@brftech/filex-core 0.42.0 → 0.42.1

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 (30) hide show
  1. package/dist/{ArchiveViewer-CGl_J_qE.js → ArchiveViewer-CLNevfPE.js} +2 -2
  2. package/dist/{ArchiveViewer-CGl_J_qE.js.map → ArchiveViewer-CLNevfPE.js.map} +1 -1
  3. package/dist/{CsvViewer-D-na6SEG.js → CsvViewer-K8XA3z7N.js} +2 -2
  4. package/dist/{CsvViewer-D-na6SEG.js.map → CsvViewer-K8XA3z7N.js.map} +1 -1
  5. package/dist/{DrawioViewer-BFkTSrNc.js → DrawioViewer-BuhZOAx6.js} +2 -2
  6. package/dist/{DrawioViewer-BFkTSrNc.js.map → DrawioViewer-BuhZOAx6.js.map} +1 -1
  7. package/dist/{EpubViewer-BfRE0DTL.js → EpubViewer-DS3mb3k8.js} +2 -2
  8. package/dist/{EpubViewer-BfRE0DTL.js.map → EpubViewer-DS3mb3k8.js.map} +1 -1
  9. package/dist/{IpynbViewer-BpBlICH-.js → IpynbViewer-BTk7p4Dn.js} +2 -2
  10. package/dist/{IpynbViewer-BpBlICH-.js.map → IpynbViewer-BTk7p4Dn.js.map} +1 -1
  11. package/dist/{MermaidViewer-Ry5Ma463.js → MermaidViewer-DqucH_io.js} +2 -2
  12. package/dist/{MermaidViewer-Ry5Ma463.js.map → MermaidViewer-DqucH_io.js.map} +1 -1
  13. package/dist/{PsdViewer-BmTlq1Gh.js → PsdViewer-CwiVENmq.js} +2 -2
  14. package/dist/{PsdViewer-BmTlq1Gh.js.map → PsdViewer-CwiVENmq.js.map} +1 -1
  15. package/dist/{TiffViewer-DE5bKDDx.js → TiffViewer-CpewSVmQ.js} +2 -2
  16. package/dist/{TiffViewer-DE5bKDDx.js.map → TiffViewer-CpewSVmQ.js.map} +1 -1
  17. package/dist/{Viewer3D-DefcNYOm.js → Viewer3D-CIrOn63I.js} +2 -2
  18. package/dist/{Viewer3D-DefcNYOm.js.map → Viewer3D-CIrOn63I.js.map} +1 -1
  19. package/dist/filex-core.js +1 -1
  20. package/dist/filex-core.umd.cjs +46 -46
  21. package/dist/filex-core.umd.cjs.map +1 -1
  22. package/dist/{index-B0N5qiyj.js → index-Dx0IbBcI.js} +8545 -8532
  23. package/dist/index-Dx0IbBcI.js.map +1 -0
  24. package/package.json +1 -1
  25. package/src/FileExplorer.vue +13 -0
  26. package/src/components/HomeView.vue +6 -3
  27. package/src/components/SideNav.vue +22 -0
  28. package/src/locales/en.ts +1 -0
  29. package/src/locales/tr.ts +1 -0
  30. package/dist/index-B0N5qiyj.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brftech/filex-core",
3
- "version": "0.42.0",
3
+ "version": "0.42.1",
4
4
  "description": "filex core — Vue 3 source of truth for the filex file manager (FileExplorer + ConnectionsPanel SFCs, composables, types)",
5
5
  "type": "module",
6
6
  "main": "./dist/filex-core.umd.cjs",
@@ -332,6 +332,10 @@ const files = ref<FileNode[]>([]);
332
332
  // RBAC effective level for the current directory ('' = ACL not enforced on
333
333
  // this storage → no gating). Drives which write/manage actions are offered.
334
334
  const dirPerm = ref<string>('');
335
+ /** The listed folder sits on a read-only storage (`read_only` on the index
336
+ * response). Folded into permCanEdit so every write affordance — toolbar,
337
+ * sidebar menu, context menu, drop zone, editor mode — reads the same fact. */
338
+ const dirReadOnly = ref(false);
335
339
  // The dead deep-link state: set to the requested path when a listing came
336
340
  // back 404 (folder doesn't exist) or 403 (RBAC-hidden — rendered identically
337
341
  // on purpose so a denied folder doesn't reveal that it exists). '' = none.
@@ -2034,6 +2038,14 @@ function onInspectorManage(n: FileNode) {
2034
2038
  // (the pre-RBAC default). Otherwise 'editor'/'owner' may write; only 'owner'
2035
2039
  // manages permissions. Enforcement is server-side; this just shapes the menu.
2036
2040
  function permCanEdit(p: string | undefined): boolean {
2041
+ // A read-only storage refuses every write on the server (403 "storage is
2042
+ // read-only") whatever level the ACL grants — an owner of a read-only mount
2043
+ // is an owner who cannot write. Say so here rather than after the click:
2044
+ // until this line the toolbar offered New folder / Upload and the sidebar's
2045
+ // "+ New" menu on a read-only mount, and the user found out from the error
2046
+ // (issue #30). The level itself is left alone: 'owner' still opens the
2047
+ // permissions panel, sharing a read-only file is still allowed.
2048
+ if (dirReadOnly.value) return false;
2037
2049
  // undefined = ACL not enforced (dev / unwired) → full access. In production
2038
2050
  // the backend always sends a level; 'none'/'viewer' cannot write, only
2039
2051
  // 'editor'/'owner' can.
@@ -2350,6 +2362,7 @@ async function load(path?: string) {
2350
2362
  adapter.value = resp.adapter;
2351
2363
  dirname.value = resp.dirname;
2352
2364
  dirPerm.value = (resp.perm as string) || '';
2365
+ dirReadOnly.value = resp.read_only === true;
2353
2366
  /* wiring:e2 — backend tells us when this dir sits inside an encrypted
2354
2367
  subtree; '' resets on every plain folder. Drives the lock screen. */
2355
2368
  e2eRoot.value = typeof resp.e2e_root === 'string' ? resp.e2e_root : '';
@@ -144,9 +144,12 @@ const storageTile = fileIconTile({ type: 'dir', mime_type: 'inode/storage' });
144
144
  * with the wrong size line says something false.
145
145
  */
146
146
  function storageCaption(s: HomeStorage): string {
147
- return typeof s.usedBytes === 'number' && s.usedBytes >= 0
148
- ? t('drive.storage.used_unlimited', { used: formatSize(s.usedBytes) })
149
- : t('conn.guide.storage');
147
+ const base =
148
+ typeof s.usedBytes === 'number' && s.usedBytes >= 0
149
+ ? t('drive.storage.used_unlimited', { used: formatSize(s.usedBytes) })
150
+ : t('conn.guide.storage');
151
+ // A read-only mount says so on its card too (issue #30).
152
+ return s.readOnly ? `${base} · ${t('sidenav.storage.readOnly')}` : base;
150
153
  }
151
154
 
152
155
  /**
@@ -242,6 +242,16 @@ const views = computed(() => {
242
242
 
243
243
  const writable = computed(() => props.canWrite !== false);
244
244
 
245
+ /**
246
+ * The storage the listing is in is mounted read-only. Its "+ New" menu is not
247
+ * disabled but GONE: on a read-only mount there is no folder where any of
248
+ * its rows could ever work, and a disabled menu invites the question a menu
249
+ * cannot answer. The row itself says why — see the tag on it (issue #30).
250
+ */
251
+ const activeReadOnly = computed(
252
+ () => !!props.activeStorage && props.storages.some((s) => s.name === props.activeStorage && s.readOnly === true),
253
+ );
254
+
245
255
  /**
246
256
  * Which row reads as the one you are standing on.
247
257
  *
@@ -426,6 +436,7 @@ const toggleLabel = computed(() => t('sidenav.close'));
426
436
  stand here behind `v-if="!newMenu"` (Upload + New folder) is gone:
427
437
  both verbs are the first two rows of this menu. -->
428
438
  <button
439
+ v-if="!activeReadOnly"
429
440
  ref="newBtnEl"
430
441
  type="button"
431
442
  class="fe-sidenav__new"
@@ -693,6 +704,17 @@ const toggleLabel = computed(() => t('sidenav.close'));
693
704
  :aria-label="t('sidenav.storage.shared')"
694
705
  >{{ t('sidenav.storage.shared') }}</span
695
706
  >
707
+ <!-- A read-only mount says so on the row, where the user looks
708
+ for it. The admin list had an "RO" badge; the people it
709
+ applied to never saw one (issue #30). -->
710
+ <span
711
+ v-if="showLabels && s.readOnly"
712
+ class="fe-sidenav__tag"
713
+ role="img"
714
+ data-testid="sidenav-storage-readonly"
715
+ :aria-label="t('sidenav.storage.readOnly')"
716
+ >{{ t('sidenav.storage.readOnly') }}</span
717
+ >
696
718
  </button>
697
719
  </li>
698
720
  </ul>
package/src/locales/en.ts CHANGED
@@ -1047,6 +1047,7 @@ export const en: Record<string, string> = {
1047
1047
  // "expand" would promise a width change to something that has no width.
1048
1048
  'sidenav.open': 'Open navigation',
1049
1049
  'sidenav.storage.shared': 'Shared',
1050
+ 'sidenav.storage.readOnly': 'Read-only',
1050
1051
  // ⚠ `toolbar.nav` is GONE, and nothing replaced it. It was the one label on
1051
1052
  // the panel's collapse control, first as the noun "Navigation" — which names
1052
1053
  // the panel and never says the button does anything to it, so the owner
package/src/locales/tr.ts CHANGED
@@ -1047,6 +1047,7 @@ export const tr: Record<string, string> = {
1047
1047
  // genişliği büyütmeyi vaat ederdi.
1048
1048
  'sidenav.open': 'Gezintiyi aç',
1049
1049
  'sidenav.storage.shared': 'Paylaşılan',
1050
+ 'sidenav.storage.readOnly': 'Salt okunur',
1050
1051
  // ⚠ `toolbar.nav` KALDIRILDI, yerine bir şey konmadı — bkz. en.ts'teki not.
1051
1052
  // Paneli daraltan tek denetimin etiketiydi; önce "Gezinti" (panelin adı,
1052
1053
  // düğmenin ne yaptığını söylemiyor), sonra "Gezintiyi göster/gizle" (sabit