Improve folder tree usability
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
7b3b3c9fd00ce2aae592ea4ec84d2875afce72ca2cad2f24a7e075312a6c528f urbm-2026.06.21.r007-x86_64-1.txz
|
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
b571e6ee3cca59d6f63e15c721d53d04f52d27e4e121fa1d314dde7fe7d454cc urbm-2026.06.21.r008-x86_64-1.txz
|
||||||
Vendored
+6
-2
@@ -2,13 +2,17 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "urbm">
|
<!ENTITY name "urbm">
|
||||||
<!ENTITY author "Michael Roll">
|
<!ENTITY author "Michael Roll">
|
||||||
<!ENTITY version "2026.06.21.r007">
|
<!ENTITY version "2026.06.21.r008">
|
||||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
||||||
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
||||||
<!ENTITY packageSHA256 "7b3b3c9fd00ce2aae592ea4ec84d2875afce72ca2cad2f24a7e075312a6c528f">
|
<!ENTITY packageSHA256 "b571e6ee3cca59d6f63e15c721d53d04f52d27e4e121fa1d314dde7fe7d454cc">
|
||||||
]>
|
]>
|
||||||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
||||||
<CHANGES>
|
<CHANGES>
|
||||||
|
### 2026.06.21.r008
|
||||||
|
- Improve the visual hierarchy of folder trees with clearer disclosure buttons, row spacing, and normal path casing.
|
||||||
|
- Preserve tree and page scroll positions when expanding folders in directory and snapshot browsers.
|
||||||
|
|
||||||
### 2026.06.21.r007
|
### 2026.06.21.r007
|
||||||
- Show an indeterminate progress bar while a complete snapshot file tree is loading.
|
- Show an indeterminate progress bar while a complete snapshot file tree is loading.
|
||||||
- Explain that no real percentage is available because Restic returns the full file listing only after completion.
|
- Explain that no real percentage is available because Restic returns the full file listing only after completion.
|
||||||
|
|||||||
+5
-1
@@ -2,13 +2,17 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "urbm">
|
<!ENTITY name "urbm">
|
||||||
<!ENTITY author "Michael Roll">
|
<!ENTITY author "Michael Roll">
|
||||||
<!ENTITY version "2026.06.21.r007">
|
<!ENTITY version "2026.06.21.r008">
|
||||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
<!ENTITY pluginURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg">
|
||||||
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
<!ENTITY packageURL "https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm-&version;-x86_64-1.txz">
|
||||||
<!ENTITY packageSHA256 "REPLACE_DURING_RELEASE">
|
<!ENTITY packageSHA256 "REPLACE_DURING_RELEASE">
|
||||||
]>
|
]>
|
||||||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="&pluginURL;" min="7.0.0" support="https://git.casaderoll.de/michael/URBM/issues" icon="urbm.png">
|
||||||
<CHANGES>
|
<CHANGES>
|
||||||
|
### 2026.06.21.r008
|
||||||
|
- Improve the visual hierarchy of folder trees with clearer disclosure buttons, row spacing, and normal path casing.
|
||||||
|
- Preserve tree and page scroll positions when expanding folders in directory and snapshot browsers.
|
||||||
|
|
||||||
### 2026.06.21.r007
|
### 2026.06.21.r007
|
||||||
- Show an indeterminate progress bar while a complete snapshot file tree is loading.
|
- Show an indeterminate progress bar while a complete snapshot file tree is loading.
|
||||||
- Explain that no real percentage is available because Restic returns the full file listing only after completion.
|
- Explain that no real percentage is available because Restic returns the full file listing only after completion.
|
||||||
|
|||||||
+4
-4
@@ -9,12 +9,12 @@ Tag="URBM Unraid Restic Backup Manager backup snapshots restore"
|
|||||||
<?php
|
<?php
|
||||||
$pluginRoot = '/plugins/urbm';
|
$pluginRoot = '/plugins/urbm';
|
||||||
?>
|
?>
|
||||||
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260621r007">
|
<link rel="stylesheet" href="<?= $pluginRoot ?>/assets/urbm.css?v=20260621r008">
|
||||||
<div id="urbm-app" data-api="<?= $pluginRoot ?>/api.php">
|
<div id="urbm-app" data-api="<?= $pluginRoot ?>/api.php">
|
||||||
<header class="bu-header">
|
<header class="bu-header">
|
||||||
<div class="bu-brand">
|
<div class="bu-brand">
|
||||||
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260621r007" alt="URBM-Logo">
|
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260621r008" alt="URBM-Logo">
|
||||||
<div><h1>URBM <span class="bu-version">2026.06.21.r007</span></h1><p>Restic Backup Manager für Unraid</p></div>
|
<div><h1>URBM <span class="bu-version">2026.06.21.r008</span></h1><p>Restic Backup Manager für Unraid</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="bu-health" class="bu-health" tabindex="0" data-tooltip="Zeigt, ob die URBM-Hintergrundkomponente erreichbar ist. Beispiel: 'Daemon online' bedeutet, dass Jobs gestartet werden können.">Verbindung wird hergestellt...</div>
|
<div id="bu-health" class="bu-health" tabindex="0" data-tooltip="Zeigt, ob die URBM-Hintergrundkomponente erreichbar ist. Beispiel: 'Daemon online' bedeutet, dass Jobs gestartet werden können.">Verbindung wird hergestellt...</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -32,4 +32,4 @@ $pluginRoot = '/plugins/urbm';
|
|||||||
<div id="bu-tooltip" role="tooltip" aria-hidden="true"></div>
|
<div id="bu-tooltip" role="tooltip" aria-hidden="true"></div>
|
||||||
</div>
|
</div>
|
||||||
<script>window.URBM_CSRF = <?= json_encode($var['csrf_token'] ?? '') ?>;</script>
|
<script>window.URBM_CSRF = <?= json_encode($var['csrf_token'] ?? '') ?>;</script>
|
||||||
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.21.r007.js"></script>
|
<script src="<?= $pluginRoot ?>/assets/urbm-2026.06.21.r008.js"></script>
|
||||||
|
|||||||
@@ -84,18 +84,20 @@
|
|||||||
.bu-source-partial .bu-source-select { accent-color: var(--bu-accent); }
|
.bu-source-partial .bu-source-select { accent-color: var(--bu-accent); }
|
||||||
.bu-partial-label { border: 1px solid var(--bu-accent); border-radius: 999px; color: var(--bu-text); display: inline-block; font-size: 11px; font-weight: 700; margin-left: 8px; padding: 2px 7px; vertical-align: middle; }
|
.bu-partial-label { border: 1px solid var(--bu-accent); border-radius: 999px; color: var(--bu-text); display: inline-block; font-size: 11px; font-weight: 700; margin-left: 8px; padding: 2px 7px; vertical-align: middle; }
|
||||||
.bu-inherited-label { border: 1px solid var(--bu-good); border-radius: 999px; color: var(--bu-good); display: inline-block; font-size: 11px; font-weight: 700; margin-left: 8px; padding: 2px 7px; vertical-align: middle; }
|
.bu-inherited-label { border: 1px solid var(--bu-good); border-radius: 999px; color: var(--bu-good); display: inline-block; font-size: 11px; font-weight: 700; margin-left: 8px; padding: 2px 7px; vertical-align: middle; }
|
||||||
.bu-tree { border: 1px solid var(--bu-border); border-radius: 6px; max-height: 520px; overflow: auto; padding: 5px; }
|
.bu-tree { background: var(--bu-input); border: 1px solid var(--bu-border); border-radius: 6px; max-height: 520px; overflow: auto; padding: 6px; }
|
||||||
.bu-tree-node { min-width: 0; }
|
.bu-tree-node { min-width: 0; }
|
||||||
.bu-tree-row { align-items: center; border-radius: 5px; display: grid; gap: 6px; grid-template-columns: 28px 24px minmax(0, 1fr); margin-left: calc(var(--bu-tree-depth) * 22px); min-height: 42px; padding: 3px 7px; }
|
.bu-tree-node + .bu-tree-node { border-top: 1px solid color-mix(in srgb, var(--bu-border) 45%, transparent); }
|
||||||
.bu-dir-tree-row { grid-template-columns: 28px minmax(0, 1fr) auto; }
|
.bu-tree-row { align-items: center; border-radius: 6px; display: grid; gap: 9px; grid-template-columns: 34px 24px minmax(0, 1fr); margin-left: calc(var(--bu-tree-depth) * 24px); min-height: 48px; padding: 5px 8px; }
|
||||||
|
.bu-dir-tree-row { grid-template-columns: 34px minmax(0, 1fr) auto; }
|
||||||
.bu-tree-row:hover { background: var(--bu-panel-alt); }
|
.bu-tree-row:hover { background: var(--bu-panel-alt); }
|
||||||
.bu-source-partial > .bu-tree-row { background: rgba(255, 140, 47, .09); background: color-mix(in srgb, var(--bu-accent) 9%, transparent); }
|
.bu-source-partial > .bu-tree-row { background: rgba(255, 140, 47, .09); background: color-mix(in srgb, var(--bu-accent) 9%, transparent); }
|
||||||
#urbm-app .bu-tree-toggle, #urbm-app .bu-tree-name { appearance: none; background: transparent !important; border: 0 !important; box-shadow: none !important; color: var(--bu-text) !important; margin: 0 !important; min-height: 0; padding: 0 !important; text-align: left; text-shadow: none !important; }
|
#urbm-app .bu-tree-toggle, #urbm-app .bu-tree-name { appearance: none; background: transparent !important; border: 0 !important; box-shadow: none !important; color: var(--bu-text) !important; margin: 0 !important; min-height: 0; padding: 0 !important; text-align: left; text-shadow: none !important; }
|
||||||
#urbm-app .bu-tree-toggle { align-items: center; cursor: pointer; display: flex; height: 28px; justify-content: center; width: 28px; }
|
#urbm-app .bu-tree-toggle { align-items: center; background: var(--bu-panel-alt) !important; border: 1px solid var(--bu-border) !important; border-radius: 6px !important; cursor: pointer; display: flex; height: 30px; justify-content: center; width: 30px; }
|
||||||
.bu-tree-toggle span { display: inline-block; font-size: 14px; transition: transform .16s ease; }
|
#urbm-app .bu-tree-toggle:hover { border-color: var(--bu-accent) !important; }
|
||||||
|
.bu-tree-toggle span { display: inline-block; font-size: 13px; line-height: 1; transition: transform .16s ease; }
|
||||||
.bu-tree-toggle.expanded span { transform: rotate(90deg); }
|
.bu-tree-toggle.expanded span { transform: rotate(90deg); }
|
||||||
#urbm-app .bu-tree-name { cursor: pointer; display: grid; gap: 1px; grid-template-columns: auto minmax(0, 1fr); min-width: 0; }
|
#urbm-app .bu-tree-name { cursor: pointer; display: grid; gap: 2px; grid-template-columns: auto minmax(0, 1fr); letter-spacing: normal !important; min-width: 0; text-transform: none !important; }
|
||||||
.bu-tree-name > span:first-child { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.bu-tree-name > span:first-child { font-weight: 700; letter-spacing: normal; overflow: hidden; text-overflow: ellipsis; text-transform: none; white-space: nowrap; }
|
||||||
.bu-tree-name small { color: var(--bu-muted); grid-column: 1 / -1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.bu-tree-name small { color: var(--bu-muted); grid-column: 1 / -1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.bu-tree-children { position: relative; }
|
.bu-tree-children { position: relative; }
|
||||||
.bu-tree-children::before { background: var(--bu-border); bottom: 3px; content: ''; left: calc((var(--bu-tree-depth, 0) + 1) * 22px + 18px); opacity: .45; position: absolute; top: 0; width: 1px; }
|
.bu-tree-children::before { background: var(--bu-border); bottom: 3px; content: ''; left: calc((var(--bu-tree-depth, 0) + 1) * 22px + 18px); opacity: .45; position: absolute; top: 0; width: 1px; }
|
||||||
|
|||||||
+15
-2
@@ -510,11 +510,15 @@
|
|||||||
function renderSourceBrowser() {
|
function renderSourceBrowser() {
|
||||||
const host=document.getElementById('bu-source-browser');
|
const host=document.getElementById('bu-source-browser');
|
||||||
if(!host) return;
|
if(!host) return;
|
||||||
|
const windowX=window.scrollX, windowY=window.scrollY;
|
||||||
|
const previousScroll=host.querySelector('.bu-tree')?.scrollTop || 0;
|
||||||
const chosen=state.backupSelections.length?state.backupSelections.map(path=>`<span class="bu-selection">${esc(path)}</span>`).join(''):'<span class="bu-muted">Keine Ordner ausgewählt.</span>';
|
const chosen=state.backupSelections.length?state.backupSelections.map(path=>`<span class="bu-selection">${esc(path)}</span>`).join(''):'<span class="bu-muted">Keine Ordner ausgewählt.</span>';
|
||||||
const tree=state.sourceTreeRoots.map(item=>sourceTreeNode(item,0)).join('');
|
const tree=state.sourceTreeRoots.map(item=>sourceTreeNode(item,0)).join('');
|
||||||
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>Backup-Quellen auswählen</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen. Unterordner werden erst bei Bedarf geladen.</span></div><span class="bu-count">Ausgewählt: ${state.backupSelections.length}</span></div><div class="bu-selection-list">${chosen}</div><div class="bu-tree" role="tree">${tree||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>Backup-Quellen auswählen</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen. Unterordner werden erst bei Bedarf geladen.</span></div><span class="bu-count">Ausgewählt: ${state.backupSelections.length}</span></div><div class="bu-selection-list">${chosen}</div><div class="bu-tree" role="tree">${tree||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
||||||
|
const treeElement=host.querySelector('.bu-tree'); if(treeElement) treeElement.scrollTop=previousScroll;
|
||||||
host.querySelectorAll('.bu-source-select[data-partial="true"]').forEach(box=>{box.indeterminate=true;box.setAttribute('aria-checked','mixed');});
|
host.querySelectorAll('.bu-source-select[data-partial="true"]').forEach(box=>{box.indeterminate=true;box.setAttribute('aria-checked','mixed');});
|
||||||
enhanceTooltips(host);
|
enhanceTooltips(host);
|
||||||
|
window.scrollTo(windowX, windowY);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleSourceTree(path, forceOpen=false) {
|
async function toggleSourceTree(path, forceOpen=false) {
|
||||||
@@ -558,9 +562,13 @@
|
|||||||
function renderDirectoryTree(key) {
|
function renderDirectoryTree(key) {
|
||||||
const tree=state.directoryTrees[key]; const host=document.getElementById(`bu-dir-tree-${key}`);
|
const tree=state.directoryTrees[key]; const host=document.getElementById(`bu-dir-tree-${key}`);
|
||||||
if(!tree||!host) return;
|
if(!tree||!host) return;
|
||||||
|
const windowX=window.scrollX, windowY=window.scrollY;
|
||||||
|
const previousScroll=host.querySelector('.bu-tree')?.scrollTop || 0;
|
||||||
const html=tree.roots.map(item=>directoryTreeNode(key,item,0)).join('');
|
const html=tree.roots.map(item=>directoryTreeNode(key,item,0)).join('');
|
||||||
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>${esc(tree.title)}</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen und den gewünschten Zielordner auswählen.</span></div></div><div class="bu-tree" role="tree">${html||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
host.innerHTML=`<section class="bu-browser-card"><div class="bu-toolbar"><div><h3>${esc(tree.title)}</h3><span class="bu-muted">Ordner mit dem Dreieck aufklappen und den gewünschten Zielordner auswählen.</span></div></div><div class="bu-tree" role="tree">${html||'<div class="bu-empty">Keine Ordner verfügbar.</div>'}</div></section>`;
|
||||||
|
const treeElement=host.querySelector('.bu-tree'); if(treeElement) treeElement.scrollTop=previousScroll;
|
||||||
enhanceTooltips(host);
|
enhanceTooltips(host);
|
||||||
|
window.scrollTo(windowX, windowY);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleDirectoryTree(key, path, forceOpen=false) {
|
async function toggleDirectoryTree(key, path, forceOpen=false) {
|
||||||
@@ -738,6 +746,11 @@
|
|||||||
notify('Konfiguration gespeichert');
|
notify('Konfiguration gespeichert');
|
||||||
return state.config;
|
return state.config;
|
||||||
}
|
}
|
||||||
|
function renderPreservingScroll() {
|
||||||
|
const windowX=window.scrollX, windowY=window.scrollY;
|
||||||
|
render();
|
||||||
|
window.scrollTo(windowX, windowY);
|
||||||
|
}
|
||||||
const lines = (value) => value.split('\n').map(v=>v.trim()).filter(Boolean);
|
const lines = (value) => value.split('\n').map(v=>v.trim()).filter(Boolean);
|
||||||
const runTime = run => new Date(run.createdAt || run.startedAt || run.finishedAt || 0).getTime() || 0;
|
const runTime = run => new Date(run.createdAt || run.startedAt || run.finishedAt || 0).getTime() || 0;
|
||||||
const snapshotTime = snapshot => new Date(snapshot.time || 0).getTime() || 0;
|
const snapshotTime = snapshot => new Date(snapshot.time || 0).getTime() || 0;
|
||||||
@@ -773,7 +786,7 @@
|
|||||||
if (name === 'toggle-dir-tree') { return toggleDirectoryTree(a, decodeURIComponent(b)); }
|
if (name === 'toggle-dir-tree') { return toggleDirectoryTree(a, decodeURIComponent(b)); }
|
||||||
if (name === 'retry-dir-tree') { const path=decodeURIComponent(b); const tree=state.directoryTrees[a]; if(tree) { delete tree.children[path]; tree.errors[path]=''; } return toggleDirectoryTree(a,path,true); }
|
if (name === 'retry-dir-tree') { const path=decodeURIComponent(b); const tree=state.directoryTrees[a]; if(tree) { delete tree.children[path]; tree.errors[path]=''; } return toggleDirectoryTree(a,path,true); }
|
||||||
if (name === 'select-dir-tree') { selectDirectoryTreePath(a, decodeURIComponent(b)); return; }
|
if (name === 'select-dir-tree') { selectDirectoryTreePath(a, decodeURIComponent(b)); return; }
|
||||||
if (name === 'toggle-snapshot-tree') { const path=decodeURIComponent(a); state.snapshotTreeExpanded[path]=!state.snapshotTreeExpanded[path]; return render(); }
|
if (name === 'toggle-snapshot-tree') { const path=decodeURIComponent(a); state.snapshotTreeExpanded[path]=!state.snapshotTreeExpanded[path]; return renderPreservingScroll(); }
|
||||||
if (name === 'restore-selected') { if(!state.restoreIncludes.length) throw new Error('Wähle mindestens eine Datei oder einen Ordner aus.'); state.view='restore'; document.querySelectorAll('.bu-tabs button').forEach(x=>x.classList.toggle('active',x.dataset.view==='restore')); return render(); }
|
if (name === 'restore-selected') { if(!state.restoreIncludes.length) throw new Error('Wähle mindestens eine Datei oder einen Ordner aus.'); state.view='restore'; document.querySelectorAll('.bu-tabs button').forEach(x=>x.classList.toggle('active',x.dataset.view==='restore')); return render(); }
|
||||||
if (name === 'delete-job') { if(confirm('Diesen Job löschen?')) { state.config.jobs=state.config.jobs.filter(j=>j.id!==a); await saveConfig(); render(); } return; }
|
if (name === 'delete-job') { if(confirm('Diesen Job löschen?')) { state.config.jobs=state.config.jobs.filter(j=>j.id!==a); await saveConfig(); render(); } return; }
|
||||||
if (name === 'duplicate-job') { const source=state.config.jobs.find(j=>j.id===a); const copy=structuredClone(source); copy.id=id('job'); copy.name += ' Kopie'; copy.enabled=false; state.config.jobs.push(copy); await saveConfig(); return render(); }
|
if (name === 'duplicate-job') { const source=state.config.jobs.find(j=>j.id===a); const copy=structuredClone(source); copy.id=id('job'); copy.name += ' Kopie'; copy.enabled=false; state.config.jobs.push(copy); await saveConfig(); return render(); }
|
||||||
@@ -879,7 +892,7 @@
|
|||||||
if (e.target.classList.contains('bu-file-select')) {
|
if (e.target.classList.contains('bu-file-select')) {
|
||||||
const path=e.target.value; const prefix=path.replace(/\/$/,'')+'/';
|
const path=e.target.value; const prefix=path.replace(/\/$/,'')+'/';
|
||||||
state.restoreIncludes = e.target.checked ? normalizeSourceSelections([...state.restoreIncludes.filter(selected=>!selected.startsWith(prefix)),path]) : state.restoreIncludes.filter(selected=>selected!==path);
|
state.restoreIncludes = e.target.checked ? normalizeSourceSelections([...state.restoreIncludes.filter(selected=>!selected.startsWith(prefix)),path]) : state.restoreIncludes.filter(selected=>selected!==path);
|
||||||
render();
|
renderPreservingScroll();
|
||||||
}
|
}
|
||||||
if (e.target.classList.contains('bu-workload-select')) {
|
if (e.target.classList.contains('bu-workload-select')) {
|
||||||
state.workloadSelections = e.target.checked ? [...new Set([...state.workloadSelections,e.target.value])] : state.workloadSelections.filter(id=>id!==e.target.value);
|
state.workloadSelections = e.target.checked ? [...new Set([...state.workloadSelections,e.target.value])] : state.workloadSelections.filter(id=>id!==e.target.value);
|
||||||
|
|||||||
Reference in New Issue
Block a user