summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js27
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/style.css10
12 files changed, 45 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index cb7a462..4a4e712 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -1240,6 +1240,10 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
// Directories are not index entries, so a new empty one needs a nudge
// to appear in the breadcrumb listing.
const [nodeDirs, setNodeDirs] = useState([]);
+ // The group's roots and whether each is readable. A root whose drive is
+ // unplugged keeps its files listed — they are frozen, not deleted — so this is
+ // the only thing that lets the UI say which of the two it is.
+ const [nodeRoots, setNodeRoots] = useState([]);
const [isNodeAdmin, setIsNodeAdmin] = useState(false);
// Paired ≠ operator account. `is_node_admin` says the hub account owning this
@@ -1275,6 +1279,7 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
const fresh = indexMsg.entries || [];
setEntries(fresh);
if (indexMsg.dirs) setNodeDirs(indexMsg.dirs);
+ if (indexMsg.roots) setNodeRoots(indexMsg.roots);
cacheGroupIndex(groupId, group ? group.name : groupId, fresh);
}, [groupId, group]);
@@ -1492,6 +1497,7 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
const indexMsg = await transport.fetchIndex();
if (indexMsg.entries) setEntries(indexMsg.entries);
if (indexMsg.dirs) setNodeDirs(indexMsg.dirs);
+ if (indexMsg.roots) setNodeRoots(indexMsg.roots);
} catch (err) {
setError(err.message);
}
@@ -1671,6 +1677,19 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
}
const subdirs = [...dirs].sort();
+ // At the top of a group the folders on screen ARE the roots, so their state
+ // belongs there. Deeper in, everything shown lives inside one readable root
+ // and there is nothing to flag.
+ const rootState = new Map(nodeRoots.map(r => [r.name, r]));
+ const unavailableHere = currentPath
+ ? []
+ : subdirs.filter(d => rootState.get(d) && rootState.get(d).available === false);
+ // A member cannot create a folder at the top of a group: that level is the
+ // set of roots, which is the operator's configuration and not a directory on
+ // anyone's disk. The node refuses it, so offering it would only produce an
+ // error nobody can act on.
+ const canCreateDir = Boolean(currentPath);
+
const baseLabel = {
idle: t('status.idle'),
discovering: t('status.discovering'),
@@ -1875,9 +1894,11 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
<input type="file" multiple style="display:none"
onChange=${uploadFile} />
</label>
+ ${canCreateDir && html`
<button class="tb-btn" onClick=${makeDirectory}>
<${Icon} name="folder-plus" /> ${t('group.mkdir')}
</button>
+ `}
</div>
<div class="breadcrumbs">
@@ -1944,8 +1965,10 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
onChange=${() => toggle(dirKey(d))} />
</td>
`}
- <td>\u{1F4C1}</td>
- <td>${d}/</td>
+ <td>${unavailableHere.includes(d) ? '\u{26A0}' : '\u{1F4C1}'}</td>
+ <td>${d}/${unavailableHere.includes(d) ? html`
+ <span class="root-offline"> ${t('group.root_unavailable')}</span>
+ ` : ''}</td>
<td class="file-size">${inside.length ? formatSize(bytes) : ''}</td>
<td class="td-type"></td>
<td class="td-date"></td>
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
index 15401bf..aaed0d1 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -92,6 +92,7 @@ export default {
'group.upload': 'Hochladen',
'group.mkdir': 'Neuer Ordner',
'group.mkdir_prompt': 'Name des neuen Ordners:',
+ 'group.root_unavailable': '(nicht verfügbar — Laufwerk getrennt)',
'group.view': 'Ansehen',
'group.delete': 'Löschen',
'group.delete_confirm': '{name} löschen?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
index a98eb1a..02532d6 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -92,6 +92,7 @@ export default {
'group.upload': 'Upload',
'group.mkdir': 'New folder',
'group.mkdir_prompt': 'Name of the new folder:',
+ 'group.root_unavailable': '(unavailable — the drive is disconnected)',
'group.view': 'View',
'group.delete': 'Delete',
'group.delete_confirm': 'Delete {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
index 596d952..49bfc1c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -90,6 +90,7 @@ export default {
'group.upload': 'Subir',
'group.mkdir': 'Nueva carpeta',
'group.mkdir_prompt': 'Nombre de la nueva carpeta:',
+ 'group.root_unavailable': '(no disponible — la unidad está desconectada)',
'group.view': 'Ver',
'group.delete': 'Eliminar',
'group.delete_confirm': '¿Eliminar {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
index 61dc99e..1afc5b1 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -91,6 +91,7 @@ export default {
'group.upload': 'Envoyer',
'group.mkdir': 'Nouveau dossier',
'group.mkdir_prompt': 'Nom du nouveau dossier :',
+ 'group.root_unavailable': '(indisponible — le disque est déconnecté)',
'group.view': 'Afficher',
'group.delete': 'Supprimer',
'group.delete_confirm': 'Supprimer {name} ?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
index 6693115..44b4353 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -91,6 +91,7 @@ export default {
'group.upload': 'Carica',
'group.mkdir': 'Nuova cartella',
'group.mkdir_prompt': 'Nome della nuova cartella:',
+ 'group.root_unavailable': '(non disponibile — l’unità è scollegata)',
'group.view': 'Visualizza',
'group.delete': 'Elimina',
'group.delete_confirm': 'Eliminare {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
index 8e18a19..33fdee3 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -89,6 +89,7 @@ export default {
'group.upload': 'アップロード',
'group.mkdir': '新しいフォルダー',
'group.mkdir_prompt': '新しいフォルダーの名前:',
+ 'group.root_unavailable': '(利用不可 — ドライブが切断されています)',
'group.view': '表示',
'group.delete': '削除',
'group.delete_confirm': '{name} を削除しますか?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
index 6fd9220..aa0385e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -92,6 +92,7 @@ export default {
'group.upload': 'Uploaden',
'group.mkdir': 'Nieuwe map',
'group.mkdir_prompt': 'Naam van de nieuwe map:',
+ 'group.root_unavailable': '(niet beschikbaar — de schijf is losgekoppeld)',
'group.view': 'Bekijken',
'group.delete': 'Verwijderen',
'group.delete_confirm': '{name} verwijderen?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
index 81f0139..e66dd12 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -95,6 +95,7 @@ export default {
'group.upload': 'Wyślij',
'group.mkdir': 'Nowy folder',
'group.mkdir_prompt': 'Nazwa nowego folderu:',
+ 'group.root_unavailable': '(niedostępne — dysk jest odłączony)',
'group.view': 'Podgląd',
'group.delete': 'Usuń',
'group.delete_confirm': 'Usunąć {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
index a2f41af..03de040 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
@@ -92,6 +92,7 @@ export default {
'group.upload': 'Enviar',
'group.mkdir': 'Nova pasta',
'group.mkdir_prompt': 'Nome da nova pasta:',
+ 'group.root_unavailable': '(indisponível — a unidade está desconectada)',
'group.view': 'Visualizar',
'group.delete': 'Excluir',
'group.delete_confirm': 'Excluir {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
index 86c7580..72995dd 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
@@ -88,6 +88,7 @@ export default {
'group.upload': '上传',
'group.mkdir': '新建文件夹',
'group.mkdir_prompt': '新文件夹的名称:',
+ 'group.root_unavailable': '(不可用 — 驱动器已断开连接)',
'group.view': '查看',
'group.delete': '删除',
'group.delete_confirm': '删除 {name}?',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css
index 1ba0ef0..6b0b6fe 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/style.css
+++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css
@@ -1894,3 +1894,13 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
}
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
+
+/* A root whose volume is absent. Its files stay listed — they are frozen, not
+ deleted — so the row has to carry the difference. */
+.root-offline {
+ font-size: 0.85em;
+ font-weight: 500;
+ color: var(--warn, #d97706);
+ margin-left: 6px;
+}
+.dir-row .root-offline { white-space: nowrap; }