cyberia 3.0.3 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/{.env.production → .env.example} +20 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +41 -10
  3. package/.github/workflows/engine-cyberia.ci.yml +53 -14
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/gitlab.ci.yml +1 -1
  6. package/.github/workflows/hardhat.ci.yml +82 -0
  7. package/.github/workflows/npmpkg.ci.yml +37 -8
  8. package/.github/workflows/publish.ci.yml +5 -5
  9. package/.github/workflows/publish.cyberia.ci.yml +5 -5
  10. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
  11. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  12. package/.github/workflows/release.cd.yml +3 -2
  13. package/.vscode/extensions.json +9 -8
  14. package/.vscode/settings.json +3 -2
  15. package/CHANGELOG.md +211 -1
  16. package/CLI-HELP.md +78 -53
  17. package/WHITE-PAPER.md +1540 -0
  18. package/bin/build.js +16 -10
  19. package/bin/cyberia.js +861 -4
  20. package/bin/deploy.js +103 -270
  21. package/bin/file.js +2 -1
  22. package/bin/index.js +861 -4
  23. package/bin/vs.js +3 -3
  24. package/conf.js +105 -97
  25. package/deployment.yaml +148 -4
  26. package/hardhat/.env.example +31 -0
  27. package/hardhat/README.md +531 -0
  28. package/hardhat/WHITE-PAPER.md +1540 -0
  29. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  30. package/hardhat/deployments/.gitkeep +0 -0
  31. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  32. package/hardhat/hardhat.config.js +136 -0
  33. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  34. package/hardhat/networks/besu-object-layer.network.json +138 -0
  35. package/hardhat/package-lock.json +7628 -0
  36. package/hardhat/package.json +45 -0
  37. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  38. package/hardhat/test/ObjectLayerToken.js +590 -0
  39. package/jsdoc.dd-cyberia.json +59 -0
  40. package/jsdoc.json +20 -13
  41. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  42. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  43. package/manifests/deployment/dd-cyberia-development/deployment.yaml +490 -0
  44. package/manifests/deployment/dd-cyberia-development/proxy.yaml +261 -0
  45. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
  46. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  47. package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
  48. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  49. package/manifests/pv-pvc-dd.yaml +1 -1
  50. package/package.json +50 -44
  51. package/proxy.yaml +79 -7
  52. package/pv-pvc.yaml +132 -0
  53. package/scripts/k3s-node-setup.sh +1 -1
  54. package/scripts/ports-ls.sh +2 -0
  55. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +3 -1
  56. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +1 -2
  57. package/src/api/document/document.service.js +1 -1
  58. package/src/api/file/file.controller.js +3 -1
  59. package/src/api/file/file.service.js +28 -5
  60. package/src/api/ipfs/ipfs.service.js +2 -2
  61. package/src/api/object-layer/object-layer.controller.js +6 -2
  62. package/src/api/object-layer/object-layer.model.js +12 -8
  63. package/src/api/object-layer/object-layer.router.js +668 -42
  64. package/src/api/object-layer/object-layer.service.js +6 -7
  65. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
  66. package/src/api/user/user.router.js +10 -5
  67. package/src/api/user/user.service.js +7 -7
  68. package/src/cli/baremetal.js +6 -10
  69. package/src/cli/cloud-init.js +0 -3
  70. package/src/cli/db.js +54 -71
  71. package/src/cli/deploy.js +64 -12
  72. package/src/cli/env.js +5 -5
  73. package/src/cli/fs.js +0 -2
  74. package/src/cli/image.js +0 -3
  75. package/src/cli/index.js +35 -13
  76. package/src/cli/monitor.js +5 -6
  77. package/src/cli/repository.js +329 -46
  78. package/src/cli/run.js +180 -120
  79. package/src/cli/secrets.js +1 -3
  80. package/src/cli/ssh.js +1 -1
  81. package/src/client/Itemledger.index.js +1 -959
  82. package/src/client/components/core/AgGrid.js +20 -5
  83. package/src/client/components/core/Alert.js +2 -2
  84. package/src/client/components/core/Content.js +22 -3
  85. package/src/client/components/core/Docs.js +30 -6
  86. package/src/client/components/core/FileExplorer.js +71 -4
  87. package/src/client/components/core/Input.js +1 -1
  88. package/src/client/components/core/Modal.js +20 -6
  89. package/src/client/components/core/RichText.js +1 -2
  90. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +1 -0
  91. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
  92. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +0 -1
  93. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +64 -2
  94. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +1 -0
  95. package/src/client/components/underpost/CssUnderpost.js +59 -0
  96. package/src/client/components/underpost/LogInUnderpost.js +3 -0
  97. package/src/client/components/underpost/LogOutUnderpost.js +2 -0
  98. package/src/client/components/underpost/MenuUnderpost.js +99 -13
  99. package/src/client/components/underpost/RoutesUnderpost.js +2 -0
  100. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  101. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  102. package/src/client/public/cryptokoyn/microdata.json +85 -0
  103. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  104. package/src/client/public/cryptokoyn/sitemap +3 -3
  105. package/src/client/public/default/sitemap +3 -3
  106. package/src/client/public/itemledger/browserconfig.xml +2 -2
  107. package/src/client/public/itemledger/manifest.webmanifest +4 -4
  108. package/src/client/public/itemledger/microdata.json +71 -0
  109. package/src/client/public/itemledger/sitemap +3 -3
  110. package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
  111. package/src/client/public/test/sitemap +3 -3
  112. package/src/client/ssr/body/404.js +15 -11
  113. package/src/client/ssr/body/500.js +15 -11
  114. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  115. package/src/client/ssr/head/PwaItemledger.js +60 -0
  116. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  117. package/src/client/ssr/pages/Test.js +11 -10
  118. package/src/client.build.js +0 -3
  119. package/src/client.dev.js +0 -3
  120. package/src/db/DataBaseProvider.js +17 -2
  121. package/src/db/mariadb/MariaDB.js +14 -9
  122. package/src/db/mongo/MongooseDB.js +17 -1
  123. package/src/index.js +1 -1
  124. package/src/proxy.js +0 -3
  125. package/src/runtime/express/Express.js +15 -9
  126. package/src/runtime/lampp/Lampp.js +6 -13
  127. package/src/server/auth.js +12 -14
  128. package/src/server/backup.js +2 -3
  129. package/src/server/besu-genesis-generator.js +1630 -0
  130. package/src/server/client-build-docs.js +126 -17
  131. package/src/server/client-build-live.js +9 -18
  132. package/src/server/client-build.js +203 -75
  133. package/src/server/client-dev-server.js +14 -13
  134. package/src/server/conf.js +376 -164
  135. package/src/server/cron.js +2 -1
  136. package/src/server/dns.js +28 -12
  137. package/src/server/downloader.js +0 -2
  138. package/src/server/logger.js +27 -9
  139. package/src/server/object-layer.js +79 -6
  140. package/src/server/peer.js +0 -2
  141. package/src/server/process.js +1 -50
  142. package/src/server/proxy.js +4 -8
  143. package/src/server/runtime.js +5 -8
  144. package/src/server/ssr.js +0 -3
  145. package/src/server/start.js +19 -12
  146. package/src/server/tls.js +0 -2
  147. package/src/server.js +0 -4
  148. package/.env.development +0 -43
  149. package/.env.test +0 -43
  150. package/hardhat/contracts/CryptoKoyn.sol +0 -59
  151. package/hardhat/contracts/ItemLedger.sol +0 -73
  152. package/hardhat/contracts/Lock.sol +0 -34
  153. package/hardhat/hardhat.config.cjs +0 -45
  154. package/hardhat/ignition/modules/Lock.js +0 -18
  155. package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
  156. package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
  157. package/hardhat/scripts/deployItemledger.cjs +0 -25
  158. package/hardhat/test/Lock.js +0 -126
  159. package/hardhat/white-paper.md +0 -581
  160. package/white-paper.md +0 -581
@@ -13,20 +13,32 @@ const AgGrid = {
13
13
  Render: async function (options) {
14
14
  let { id, paginationOptions } = options;
15
15
  setTimeout(() => {
16
+ // Normalize rowSelection from deprecated string form to object form (AG Grid v32.2.1+)
17
+ let gridOptionsOverrides = { ...(options.gridOptions || {}) };
18
+ if (typeof gridOptionsOverrides.rowSelection === 'string') {
19
+ const mode = gridOptionsOverrides.rowSelection; // 'single' or 'multiple'
20
+ gridOptionsOverrides.rowSelection = {
21
+ mode: mode === 'multiple' ? 'multiRow' : 'singleRow',
22
+ };
23
+ }
24
+
16
25
  // Grid Options: Contains all of the grid configurations
17
26
  const gridOptions = {
27
+ // Use legacy CSS theme mode to avoid conflict with Theming API (AG Grid v33+)
28
+ theme: 'legacy',
18
29
  // Row Data: The data to be displayed.
19
30
  pagination: false, // Disabled by default, will be handled by the management view
20
31
  // paginationPageSize: 100,
21
32
  // suppressPaginationPanel: true, // We are using our own custom pagination component
22
33
  // rowHeight: 60,
23
- enableCellChangeFlash: true,
34
+ // enableCellChangeFlash was removed in v35; use enableCellChangeFlash on defaultColDef instead
24
35
  defaultColDef: {
25
36
  editable: false,
26
37
  flex: 1,
27
38
  minWidth: 50,
28
39
  filter: true,
29
40
  autoHeight: true,
41
+ enableCellChangeFlash: true,
30
42
  },
31
43
  rowClassRules: {
32
44
  'row-new-highlight': (params) => {
@@ -76,7 +88,7 @@ const AgGrid = {
76
88
  return { field };
77
89
  })
78
90
  : [],
79
- ...options.gridOptions,
91
+ ...gridOptionsOverrides,
80
92
  };
81
93
 
82
94
  // Your Javascript code to create the grid
@@ -86,8 +98,11 @@ const AgGrid = {
86
98
  // myGridElement.style.setProperty('width', '100%');
87
99
  ThemeEvents[id] = () => {
88
100
  if (s(`.${id}`)) {
89
- s(`.${id}`).classList.remove(darkTheme ? this.theme : this.theme + '-dark');
90
- s(`.${id}`).classList.add(!darkTheme ? this.theme : this.theme + '-dark');
101
+ // darkTheme has already been updated by Css.js when this event fires
102
+ // If darkTheme is true: remove light class, add dark class
103
+ // If darkTheme is false: remove dark class, add light class
104
+ s(`.${id}`).classList.remove(this.theme, this.theme + '-dark');
105
+ s(`.${id}`).classList.add(darkTheme ? this.theme + '-dark' : this.theme);
91
106
  } else {
92
107
  // console.warn('change theme: grid not found');
93
108
  delete ThemeEvents[id];
@@ -112,7 +127,7 @@ const AgGrid = {
112
127
  : '';
113
128
  return html`
114
129
  <div
115
- class="${id} ${this.theme}${options?.darkTheme ? `-dark` : ''}"
130
+ class="${id} ${darkTheme ? this.theme + '-dark' : this.theme}"
116
131
  style="${options?.style
117
132
  ? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
118
133
  : ''}"
@@ -49,7 +49,7 @@ const e404 = async () => {
49
49
  <br />
50
50
  <br />${Translate.Render('page-not-found')} <br />
51
51
  <br />
52
- <a href="${location.origin}">${Translate.Render('back')}</a>
52
+ <a target="_top" href="${location.origin}">${Translate.Render('back')}</a>
53
53
  </div>`;
54
54
  };
55
55
 
@@ -68,7 +68,7 @@ const e500 = async () => {
68
68
  <br />
69
69
  <br />${Translate.Render('page-broken')} <br />
70
70
  <br />
71
- <a href="${location.origin}">${Translate.Render('back')}</a>
71
+ <a target="_top" href="${location.origin}">${Translate.Render('back')}</a>
72
72
  </div>`;
73
73
  };
74
74
 
@@ -56,7 +56,7 @@ const attachMarkdownLinkHandlers = (containerSelector) => {
56
56
  };
57
57
 
58
58
  const Content = {
59
- Render: async function (options = { idModal: '' }) {
59
+ Render: async function (options = { idModal: '', titleIcon: '' }) {
60
60
  const { idModal } = options;
61
61
  setTimeout(async () => {
62
62
  try {
@@ -111,11 +111,30 @@ const Content = {
111
111
  throw new Error(`no-preview-available`);
112
112
  }
113
113
 
114
+ // Use custom titleIcon from options, or extract from the modal's original title HTML, or fall back to default
115
+ const titleIcon = options.titleIcon
116
+ ? options.titleIcon
117
+ : Modal.Data[idModal] &&
118
+ Modal.Data[idModal].options &&
119
+ Modal.Data[idModal].options.title &&
120
+ Modal.Data[idModal].options.title.includes &&
121
+ Modal.Data[idModal].options.title.includes('<img')
122
+ ? Modal.Data[idModal].options.title.match(/<img[^>]*>/)?.[0] || html`<i class="inl far fa-file"></i>`
123
+ : html`<i class="inl far fa-file"></i>`;
124
+
125
+ // Preserve the original text wrapper class if present in the modal's stored title
126
+ const originalTitle = Modal.Data[idModal]?.options?.title || '';
127
+ const hasCustomTextClass = originalTitle.includes && originalTitle.includes('underpost-text-title-modal');
128
+ const docTitle = documentObj.title ? documentObj.title : documentObj.location;
129
+ const titleText = hasCustomTextClass
130
+ ? `<span class='inl underpost-text-title-modal'>${docTitle}</span>`
131
+ : docTitle;
132
+
114
133
  htmls(
115
134
  `.title-modal-${idModal}`,
116
135
  html`${renderViewTitle({
117
- icon: html`<i class="inl far fa-file"></i>`,
118
- text: `${documentObj.title ? documentObj.title : documentObj.location}`,
136
+ icon: titleIcon,
137
+ text: titleText,
119
138
  })} `,
120
139
  );
121
140
  htmls(`.content-render-${idModal}`, ``);
@@ -12,6 +12,10 @@ const Docs = {
12
12
  const docData = this.Data.find((d) => d.type === type);
13
13
  const ModalId = `modal-docs-${docData.type}`;
14
14
  const { barConfig } = await Themes[Css.currentTheme]();
15
+ const parentBarMode =
16
+ Modal.Data['modal-docs'] && Modal.Data['modal-docs'].options.barMode
17
+ ? Modal.Data['modal-docs'].options.barMode
18
+ : undefined;
15
19
 
16
20
  await Modal.Render({
17
21
  barConfig,
@@ -20,11 +24,18 @@ const Docs = {
20
24
  html: async () => {
21
25
  if (docData.renderHtml) return await docData.renderHtml();
22
26
  return html`
27
+ <style>
28
+ .iframe-${ModalId} {
29
+ width: 100%;
30
+ border: none;
31
+ background: white;
32
+ display: block;
33
+ }
34
+ </style>
23
35
  <iframe
24
36
  class="in iframe-${ModalId}"
25
- style="width: 100%; border: none; background: white; display: block"
26
37
  src="${docData.url()}"
27
- sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-popups-to-escape-sandbox"
38
+ sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-popups-to-escape-sandbox allow-top-navigation"
28
39
  >
29
40
  </iframe>
30
41
  `;
@@ -34,7 +45,7 @@ const Docs = {
34
45
  route: 'docs',
35
46
  slideMenu: 'modal-menu',
36
47
  observer: true,
37
- barMode: 'top-bottom-bar',
48
+ barMode: parentBarMode,
38
49
  query: true,
39
50
  RouterInstance: Modal.Data['modal-docs'].options.RouterInstance,
40
51
  });
@@ -166,6 +177,8 @@ const Docs = {
166
177
  icon: html`<i class="fab fa-github"></i>`,
167
178
  text: `Last Release`,
168
179
  url: function () {
180
+ const tokenOpts = Docs.Tokens['modal-docs'];
181
+ if (tokenOpts && tokenOpts.lastReleaseUrl) return tokenOpts.lastReleaseUrl();
169
182
  return `https://github.com/underpostnet/pwa-microservices-template-ghpkg/`;
170
183
  },
171
184
  },
@@ -180,6 +193,8 @@ const Docs = {
180
193
  </svg>`,
181
194
  text: html`Demo`,
182
195
  url: function () {
196
+ const tokenOpts = Docs.Tokens['modal-docs'];
197
+ if (tokenOpts && tokenOpts.demoUrl) return tokenOpts.demoUrl();
183
198
  return `https://underpostnet.github.io/pwa-microservices-template-ghpkg/`;
184
199
  },
185
200
  },
@@ -204,6 +219,8 @@ const Docs = {
204
219
  icon: html`<img height="20" width="20" class="doc-icon-coverage" />`,
205
220
  text: `Coverage report`,
206
221
  url: function () {
222
+ const tokenOpts = Docs.Tokens['modal-docs'];
223
+ if (tokenOpts && tokenOpts.coverageUrl) return tokenOpts.coverageUrl();
207
224
  return `${getProxyPath()}docs/coverage`;
208
225
  },
209
226
  themeEvent: () => {
@@ -223,7 +240,7 @@ const Docs = {
223
240
  },
224
241
  ],
225
242
  Tokens: {},
226
- Init: async function (options) {
243
+ Init: async function (options = {}) {
227
244
  const { idModal } = options;
228
245
  this.Tokens[idModal] = options;
229
246
  setTimeout(() => {
@@ -284,10 +301,14 @@ const Docs = {
284
301
  break;
285
302
  }
286
303
  tabHref = docData.url();
304
+ const subMenuIcon =
305
+ options.subMenuIcon && typeof options.subMenuIcon === 'function'
306
+ ? options.subMenuIcon(docData.type)
307
+ : docData.icon;
287
308
  docMenuRender += html`
288
309
  ${await BtnIcon.Render({
289
310
  class: `in wfa main-btn-menu submenu-btn btn-docs btn-docs-${docData.type}`,
290
- label: html`<span class="inl menu-btn-icon">${docData.icon}</span
311
+ label: html`<span class="inl menu-btn-icon">${subMenuIcon}</span
291
312
  ><span class="menu-label-text menu-label-text-docs"> ${docData.text} </span>`,
292
313
  tabHref,
293
314
  tooltipHtml: await Badge.Render(buildBadgeToolTipMenuOption(docData.text, 'right')),
@@ -447,7 +468,10 @@ const Docs = {
447
468
  if (s(`.docs-card-container-${item.id}`)) {
448
469
  s(`.docs-card-container-${item.id}`).onclick = () => {
449
470
  if (item.id.match('demo')) {
450
- location.href = 'https://underpostnet.github.io/pwa-microservices-template-ghpkg/';
471
+ const demoData = Docs.Data.find((d) => d.type === 'demo');
472
+ location.href = demoData
473
+ ? demoData.url()
474
+ : 'https://underpostnet.github.io/pwa-microservices-template-ghpkg/';
451
475
  } else if (item.id.match('api')) {
452
476
  if (s(`.btn-docs-api`)) s(`.btn-docs-api`).click();
453
477
  } else {
@@ -544,10 +544,13 @@ const FileExplorer = {
544
544
  this.eGui = document.createElement('div');
545
545
  const isPublic = params.data.isPublic;
546
546
  const toggleId = `toggle-public-${params.data._id}`;
547
+ const hasGenericFile = !!params.data.hasGenericFile;
548
+ const hasMdFile = !!params.data.hasMdFile;
549
+
547
550
  this.eGui.innerHTML = html`
548
551
  <div class="fl">
549
552
  ${await BtnIcon.Render({
550
- class: `in fll management-table-btn-mini btn-file-download-${params.data._id}`,
553
+ class: `in fll management-table-btn-mini btn-file-download-${params.data._id}${!hasGenericFile ? ' btn-disabled' : ''}`,
551
554
  label: html` <i class="fas fa-download"></i>`,
552
555
  type: 'button',
553
556
  })}
@@ -562,10 +565,15 @@ const FileExplorer = {
562
565
  type: 'button',
563
566
  })}
564
567
  ${await BtnIcon.Render({
565
- class: `in fll management-table-btn-mini btn-file-copy-content-link-${params.data._id}`,
568
+ class: `in fll management-table-btn-mini btn-file-copy-content-link-${params.data._id}${!hasGenericFile ? ' btn-disabled' : ''}`,
566
569
  label: html`<i class="fas fa-copy"></i>`,
567
570
  type: 'button',
568
571
  })}
572
+ ${await BtnIcon.Render({
573
+ class: `in fll management-table-btn-mini btn-file-copy-md-link-${params.data._id}${!hasMdFile ? ' btn-disabled' : ''}`,
574
+ label: html`<i class="fas fa-file-code"></i>`,
575
+ type: 'button',
576
+ })}
569
577
  ${await BtnIcon.Render({
570
578
  class: `in fll management-table-btn-mini btn-file-edit-${params.data._id}`,
571
579
  label: html`<i class="fas fa-edit"></i>`,
@@ -591,11 +599,46 @@ const FileExplorer = {
591
599
  ? getApiBaseUrl({ id: originObj.fileId._id, endpoint: 'file/blob' })
592
600
  : undefined;
593
601
 
602
+ const mdBlobUri =
603
+ originObj && originObj.mdFileId
604
+ ? getApiBaseUrl({ id: originObj.mdFileId._id, endpoint: 'file/blob' })
605
+ : undefined;
606
+
594
607
  if (!originObj) {
595
608
  s(`.btn-file-view-${params.data._id}`).classList.add('hide');
596
609
  s(`.btn-file-copy-content-link-${params.data._id}`).classList.add('hide');
597
610
  }
598
611
 
612
+ // Disable download button if no generic file
613
+ if (!hasGenericFile) {
614
+ const dlBtn = s(`.btn-file-download-${params.data._id}`);
615
+ if (dlBtn) {
616
+ dlBtn.style.opacity = '0.4';
617
+ dlBtn.style.cursor = 'not-allowed';
618
+ dlBtn.style.pointerEvents = 'none';
619
+ }
620
+ }
621
+
622
+ // Disable copy generic file link button if no generic file
623
+ if (!hasGenericFile) {
624
+ const copyBtn = s(`.btn-file-copy-content-link-${params.data._id}`);
625
+ if (copyBtn) {
626
+ copyBtn.style.opacity = '0.4';
627
+ copyBtn.style.cursor = 'not-allowed';
628
+ copyBtn.style.pointerEvents = 'none';
629
+ }
630
+ }
631
+
632
+ // Disable copy md file link button if no md file
633
+ if (!hasMdFile) {
634
+ const mdCopyBtn = s(`.btn-file-copy-md-link-${params.data._id}`);
635
+ if (mdCopyBtn) {
636
+ mdCopyBtn.style.opacity = '0.4';
637
+ mdCopyBtn.style.cursor = 'not-allowed';
638
+ mdCopyBtn.style.pointerEvents = 'none';
639
+ }
640
+ }
641
+
599
642
  EventsUI.onClick(`.btn-file-view-${params.data._id}`, async (e) => {
600
643
  e.preventDefault();
601
644
  if (location.href !== url) {
@@ -606,6 +649,7 @@ const FileExplorer = {
606
649
 
607
650
  EventsUI.onClick(`.btn-file-copy-content-link-${params.data._id}`, async (e) => {
608
651
  e.preventDefault();
652
+ if (!hasGenericFile || !blobUri) return;
609
653
  await copyData(blobUri);
610
654
  NotificationManager.Push({
611
655
  html: Translate.Render('success-copy-data'),
@@ -613,10 +657,21 @@ const FileExplorer = {
613
657
  });
614
658
  });
615
659
 
660
+ EventsUI.onClick(`.btn-file-copy-md-link-${params.data._id}`, async (e) => {
661
+ e.preventDefault();
662
+ if (!hasMdFile || !mdBlobUri) return;
663
+ await copyData(mdBlobUri);
664
+ NotificationManager.Push({
665
+ html: Translate.Render('success-copy-data'),
666
+ status: 'success',
667
+ });
668
+ });
669
+
616
670
  EventsUI.onClick(`.btn-file-download-${params.data._id}`, async (e) => {
617
671
  e.preventDefault();
672
+ if (!hasGenericFile) return;
618
673
  try {
619
- // Use FileService with blob/ prefix for centralized blob fetching
674
+ // Use FileService with blob/ prefix for blob fetching
620
675
  const { data: blobArray, status } = await FileService.get({ id: `blob/${params.data.fileId}` });
621
676
  if (status === 'success' && blobArray && blobArray[0]) {
622
677
  downloadFile(blobArray[0], params.data.name);
@@ -721,6 +776,12 @@ const FileExplorer = {
721
776
  documentInstance[docIndex].isPublic = data.isPublic;
722
777
  }
723
778
 
779
+ // Refresh the isPublic column cell in the grid
780
+ const rowNode = AgGrid.grids[gridFileId].getRowNode(params.node.id);
781
+ if (rowNode) {
782
+ rowNode.setDataValue('isPublic', data.isPublic);
783
+ }
784
+
724
785
  // Update button icon
725
786
  const btnElement = s(`.${toggleId}`);
726
787
  if (btnElement) {
@@ -1347,7 +1408,13 @@ const FileExplorer = {
1347
1408
  { field: 'name', flex: 2, headerName: 'Title', cellRenderer: LoadFileNameRenderer },
1348
1409
  { field: 'mdFileName', flex: 1, headerName: 'MD File Name' },
1349
1410
  { field: 'fileName', flex: 1, headerName: 'Generic File Name' },
1350
- { headerName: '', width: 150, cellRenderer: LoadFileActionsRenderer },
1411
+ {
1412
+ field: 'isPublic',
1413
+ headerName: 'Public',
1414
+ width: 90,
1415
+ cellDataType: 'boolean',
1416
+ },
1417
+ { headerName: '', width: 180, cellRenderer: LoadFileActionsRenderer },
1351
1418
  ],
1352
1419
  },
1353
1420
  })}
@@ -101,7 +101,7 @@ const getFileFromFileData = (fileData) => {
101
101
  /**
102
102
  * Fetch file content from blob endpoint and create File object.
103
103
  * Used for metadata-only format files during edit mode.
104
- * Uses FileService with blob/ prefix for centralized blob fetching.
104
+ * Uses FileService with blob/ prefix for blob fetching.
105
105
  *
106
106
  * @async
107
107
  * @function getFileFromBlobEndpoint
@@ -2424,20 +2424,34 @@ const Modal = {
2424
2424
  },
2425
2425
  };
2426
2426
 
2427
- const renderMenuLabel = ({ img, text, icon }) => {
2428
- if (!img) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
2429
- return html`<img class="abs center img-btn-square-menu" src="${getProxyPath()}assets/ui-icons/${img}" />
2427
+ const renderMenuLabel = ({ img, src, text, icon }) => {
2428
+ if (!img && !src) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
2429
+ const imgSrc = src ? src : `${getProxyPath()}assets/ui-icons/${img}`;
2430
+ return html`<img class="abs center img-btn-square-menu" src="${imgSrc}" />
2430
2431
  <div class="abs center main-btn-menu-text">${text}</div>`;
2431
2432
  };
2432
2433
 
2433
2434
  const renderViewTitle = (
2434
- options = { icon: '', img: '', text: '', assetFolder: '', 'ui-icons': '', dim, top, topText: '' },
2435
+ options = {
2436
+ icon: '',
2437
+ img: '',
2438
+ text: '',
2439
+ assetFolder: '',
2440
+ 'ui-icon': '',
2441
+ imgClass: '',
2442
+ textClass: '',
2443
+ dim,
2444
+ top,
2445
+ topText: '',
2446
+ },
2435
2447
  ) => {
2436
2448
  if (options.dim === undefined) options.dim = 30;
2437
2449
  const { img, text, icon, dim, top } = options;
2438
2450
  if (!img && !options['ui-icon']) return html`<span class="view-title-icon">${icon}</span> ${text}`;
2451
+ const imgClass = options.imgClass || 'abs img-btn-square-view-title';
2452
+ const textClass = options.textClass || 'in text-btn-square-view-title';
2439
2453
  return html`<img
2440
- class="abs img-btn-square-view-title"
2454
+ class="${imgClass}"
2441
2455
  style="${renderCssAttr({
2442
2456
  style: {
2443
2457
  width: `${dim}px`,
@@ -2450,7 +2464,7 @@ const renderViewTitle = (
2450
2464
  : img}"
2451
2465
  />
2452
2466
  <div
2453
- class="in text-btn-square-view-title"
2467
+ class="${textClass}"
2454
2468
  style="${renderCssAttr({
2455
2469
  style: {
2456
2470
  // 'padding-left': `${20 + dim}px`,
@@ -30,10 +30,9 @@ const RichText = {
30
30
  return html` <style>
31
31
  .md-container {
32
32
  background: white;
33
- color: black;
34
33
  }
35
34
  .md-container button {
36
- color: black !important;
35
+ color: black;
37
36
  }
38
37
  </style>
39
38
  <div class="in md-container"><textarea class="${id}"></textarea></div>`;
@@ -31,6 +31,7 @@ const CyberiaDependencies = {
31
31
  pngjs: '^7.0.0',
32
32
  jimp: '^1.6.0',
33
33
  sharp: '^0.32.5',
34
+ ethers: '~6.16.0',
34
35
  };
35
36
 
36
37
  export { BaseElement, ModelElement, CyberiaPortalParams, CyberiaDependencies };
@@ -63,20 +63,62 @@ const CssCommonCyberia = async () => {
63
63
  text-align: center;
64
64
  }
65
65
 
66
- .landing-title,
67
66
  h1,
68
67
  h2,
69
68
  h3 {
70
69
  font-family: var(--cy-font-retro-cta);
70
+ }
71
+
72
+ p {
73
+ font-family: var(--cy-font-retro);
74
+ }
75
+
76
+ .landing-title,
77
+ .html-main-body h1,
78
+ .html-main-body h2,
79
+ .html-main-body h3 {
71
80
  font-size: 5rem;
72
81
  color: #ffcc00;
73
82
  text-shadow: 2px 2px 0px #9e7b00;
74
83
  margin-bottom: 2rem;
75
84
  }
76
85
 
77
- p {
86
+ /* Docs section retro styling */
87
+ .docs-header h1 {
88
+ font-family: var(--cy-font-retro-cta);
89
+ color: #ffcc00;
90
+ text-shadow: 2px 2px 0px #9e7b00;
91
+ }
92
+ .docs-card {
93
+ border: 2px solid #ffcc00;
94
+ transition: all 0.3s ease-in-out;
95
+ }
96
+ .docs-card:hover {
97
+ background: rgba(255, 204, 0, 0.08);
98
+ box-shadow:
99
+ 0 0 10px rgba(255, 204, 0, 0.3),
100
+ 0 0 20px rgba(255, 204, 0, 0.15);
101
+ transform: translateY(-3px);
102
+ }
103
+ .card-icon {
104
+ color: #ffcc00;
105
+ }
106
+ .card-content h3 {
107
+ font-family: var(--cy-font-retro-cta);
108
+ font-size: 1.25rem;
109
+ }
110
+ .card-content p {
111
+ font-family: var(--cy-font-retro);
112
+ }
113
+ .submenu-btn {
78
114
  font-family: var(--cy-font-retro);
79
115
  }
116
+ .submenu-btn:hover {
117
+ background: rgba(255, 204, 0, 0.1);
118
+ }
119
+ .down-arrow-submenu {
120
+ left: 102px;
121
+ }
80
122
 
81
123
  .object-layer-viewer-container {
82
124
  width: 100% !important;
@@ -10,7 +10,6 @@ const LogInCyberiaPortal = async function () {
10
10
 
11
11
  ElementsCyberiaPortal.Data.user.main.model.user = user;
12
12
 
13
- // if (user.role === 'admin' || user.role === 'moderator') s(`.main-btn-admin`).classList.remove('hide');
14
13
  await ObjectLayerManagement.Reload('viewer');
15
14
  };
16
15
  const { user } = await Auth.sessionIn();
@@ -2,14 +2,22 @@ import { Account } from '../core/Account.js';
2
2
  import { BtnIcon } from '../core/BtnIcon.js';
3
3
  import { getId, newInstance, random } from '../core/CommonJs.js';
4
4
  import { Css, ThemeEvents, Themes, darkTheme } from '../core/Css.js';
5
+ import { Docs } from '../core/Docs.js';
5
6
  import { EventsUI } from '../core/EventsUI.js';
6
7
  import { LogIn } from '../core/LogIn.js';
7
8
  import { LogOut } from '../core/LogOut.js';
8
- import { buildBadgeToolTipMenuOption, Modal, renderMenuLabel, renderViewTitle } from '../core/Modal.js';
9
+ import {
10
+ buildBadgeToolTipMenuOption,
11
+ isSubMenuOpen,
12
+ Modal,
13
+ renderMenuLabel,
14
+ renderViewTitle,
15
+ subMenuRender,
16
+ } from '../core/Modal.js';
9
17
  import { SignUp } from '../core/SignUp.js';
10
18
  import { Translate } from '../core/Translate.js';
11
19
  import { htmls, s } from '../core/VanillaJs.js';
12
- import { getProxyPath } from '../core/Router.js';
20
+ import { getProxyPath, setQueryParams } from '../core/Router.js';
13
21
  import { ElementsCyberiaPortal } from './ElementsCyberiaPortal.js';
14
22
  import Sortable from 'sortablejs';
15
23
  import { RouterCyberiaPortal, BannerAppTemplate } from './RoutesCyberiaPortal.js';
@@ -135,6 +143,27 @@ const MenuCyberiaPortal = {
135
143
  handleContainerClass: 'handle-btn-container',
136
144
  tooltipHtml: await Badge.Render(buildBadgeToolTipMenuOption('chat')),
137
145
  })}
146
+ ${await BtnIcon.Render({
147
+ class: 'in wfa main-btn-menu main-btn-docs',
148
+ useMenuBtn: true,
149
+ label: html`<div class="in">
150
+ ${renderMenuLabel({
151
+ icon: html`<img class="inl cyberia-menu-icon" src="${getProxyPath()}assets/ui-icons/wiki.png" />`,
152
+ text: html`<span class="menu-label-text"
153
+ >${Translate.Render('docs')}
154
+ <i
155
+ class="fas fa-caret-down inl down-arrow-submenu down-arrow-submenu-docs"
156
+ style="rotate: 0deg; transition: 0.4s;"
157
+ ></i
158
+ ></span>`,
159
+ })}
160
+ </div> `,
161
+ attrs: `data-id="docs"`,
162
+ tabHref: `${getProxyPath()}docs`,
163
+ handleContainerClass: 'handle-btn-container',
164
+ tooltipHtml: await Badge.Render(buildBadgeToolTipMenuOption('docs')),
165
+ })}
166
+ <div class="abs menu-btn-container-children-docs"></div>
138
167
  ${await BtnIcon.Render({
139
168
  class: 'in wfa main-btn-menu main-btn-admin hide',
140
169
  useMenuBtn: true,
@@ -432,6 +461,39 @@ const MenuCyberiaPortal = {
432
461
  });
433
462
  });
434
463
 
464
+ EventsUI.onClick(`.main-btn-docs`, async (e) => {
465
+ if (!isSubMenuOpen('docs') || e.isTrusted) {
466
+ if (e.isTrusted) setQueryParams({ cid: '' });
467
+ await subMenuRender('docs');
468
+ }
469
+
470
+ const { barConfig } = await Themes[Css.currentTheme]();
471
+ await Modal.Render({
472
+ id: 'modal-docs',
473
+ route: 'docs',
474
+ barConfig,
475
+ title: renderViewTitle({
476
+ icon: html`<img class="inl cyberia-menu-icon-modal" src="${getProxyPath()}assets/ui-icons/wiki.png" />`,
477
+ text: `<span class='inl cyberia-text-title-modal'>${Translate.Render('docs')}</span>`,
478
+ }),
479
+ html: async () =>
480
+ await Docs.Init({
481
+ idModal: 'modal-docs',
482
+ subMenuIcon: (type) =>
483
+ html`<img class="inl cyberia-menu-icon" src="${getProxyPath()}assets/ui-icons/arrow-right.png" />`,
484
+ coverageUrl: () => `${getProxyPath()}docs/hardhat-coverage`,
485
+ demoUrl: () => `https://client.cyberiaonline.com/`,
486
+ lastReleaseUrl: () => `https://github.com/underpostnet/engine-cyberia.git`,
487
+ }),
488
+ handleType: 'bar',
489
+ observer: true,
490
+ maximize: true,
491
+ mode: 'view',
492
+ slideMenu: 'modal-menu',
493
+ RouterInstance,
494
+ });
495
+ });
496
+
435
497
  EventsUI.onClick(`.main-btn-server`, async () => {
436
498
  const { barConfig } = await Themes[Css.currentTheme]();
437
499
  await Modal.Render({
@@ -45,6 +45,7 @@ const RoutesCyberiaPortal = () => {
45
45
  title: 'cyberia-map-engine',
46
46
  render: () => s(`.main-btn-cyberia-map-engine`).click(),
47
47
  },
48
+ '/docs': { title: 'docs', render: () => s(`.main-btn-docs`).click() },
48
49
  };
49
50
  };
50
51