diff --git a/web/src/assets/styles/blocks.scss b/web/src/assets/styles/blocks.scss index 30e95e4aa4..85fb4643bf 100644 --- a/web/src/assets/styles/blocks.scss +++ b/web/src/assets/styles/blocks.scss @@ -482,6 +482,34 @@ ul[data-type="agama/list"][role="grid"] { } } +table[data-type="agama/tree-table"] { + tr.dimmed-row { + background-color: #fff; + opacity: 0.8; + background: repeating-linear-gradient( -45deg, #fcfcff, #fcfcff 3px, #fff 3px, #fff 10px ); + + td { + color: var(--color-gray-dimmed); + padding-block: 0; + } + } + + @media (width > 768px) { + th.text-end, + td.text-end { + text-align: end; + padding-inline-end: var(--spacer-large); + } + } + + @media (width <= 768px) { + td:empty { + display: none; + } + } +} + + .tpm-hint { container-type: inline-size; container-name: tpm-info; diff --git a/web/src/components/core/TreeTable.jsx b/web/src/components/core/TreeTable.jsx index dca2e866b9..8b766ad18f 100644 --- a/web/src/components/core/TreeTable.jsx +++ b/web/src/components/core/TreeTable.jsx @@ -36,7 +36,10 @@ export default function TreeTable({ }) { const renderColumns = (item, treeRow) => { return columns.map((c, cIdx) => { - const props = { dataLabel: c.title }; + const props = { + dataLabel: c.title, + className: c.classNames + }; if (cIdx === 0) props.treeRow = treeRow; @@ -85,10 +88,10 @@ export default function TreeTable({ }; return ( - +
- { columns.map((c, i) => ) } + { columns.map((c, i) => ) } diff --git a/web/src/components/storage/ProposalActionsSection.jsx b/web/src/components/storage/ProposalActionsSection.jsx index b4baee4413..0b038dd5a5 100644 --- a/web/src/components/storage/ProposalActionsSection.jsx +++ b/web/src/components/storage/ProposalActionsSection.jsx @@ -30,7 +30,7 @@ import { sprintf } from "sprintf-js"; import { _, n_ } from "~/i18n"; import { deviceSize } from "~/components/storage/utils"; -import { If, Section } from "~/components/core"; +import { If, Section, TreeTable } from "~/components/core"; import { partition } from "~/utils"; // TODO: would be nice adding an aria-description to these lists, but aria-description still in @@ -105,130 +105,93 @@ const ActionsSkeleton = () => { ); }; -class DevicesManager { - constructor(system, staging) { - this.system = system; - this.staging = staging; - } +const DeleteActions = ({ actions }) => { + const deleteActions = actions.filter(a => a.delete); - systemDevice(sid) { - return this.system.find(d => d.sid === sid); - } - - device(sid) { - return this.staging.find(d => d.sid === sid); - } - - lvmVgsWithMountPoints() { - const vgs = this.staging.filter(d => d.type === "lvmVg"); - return vgs.filter(v => v.logicalVolumes.find(l => l.filesystem?.mountPath !== undefined)); - } - - children(device) { - if (device.partitionTable) return this.partitionTableChildren(device.partitionTable); - if (device.type === "lvmVg") return this.lvmVgChildren(device); - return []; - } - - partitionTableChildren(partitionTable) { - const { partitions, unusedSlots } = partitionTable; - const children = partitions.concat(unusedSlots); - - return children.sort((a, b) => a.start < b.start ? -1 : 1); - } - - lvmVgChildren(lvmVg) { - return lvmVg.logicalVolumes.sort((a, b) => a.name < b.name ? -1 : 1); - } - - isSlot(storageElement) { - return storageElement.sid === undefined; - } -} - -class SlotPresenter { - constructor(slot) { - this.slot = slot; - } - - name() { - return ""; - } - - details() { - return "Unused space"; - } - - size() { - return deviceSize(this.slot.size); - } - - mountPoint() { - return ""; - } -} - -class DevicePresenter { - constructor(device, devicesManager) { - this.device = device; - this.devicesManager = devicesManager; - } - - name() { - return this.device.name; - } - - details() { - return this.device.description; - } - - size() { - return deviceSize(this.device.size); - } - - mountPoint() { - return this.device.filesystem?.mountPath || ""; - } -} - -const DeviceResult = ({ presenter }) => { + // TODO Add show the deleted system if any return ( ); }; const DevicesResult = ({ settings, devices }) => { const { system = [], staging = [] } = devices; - const devicesManager = new DevicesManager(system, staging); const usedDevices = () => { - const diskDevices = settings.installationDevices.map(d => devicesManager.device(d.sid)); - const lvmVgs = devicesManager.lvmVgsWithMountPoints(); + const sids = settings.installationDevices.map(d => d.sid); + const instDevices = staging.filter(d => sids.includes(d.sid)); + const lvmVgs = staging.filter(d => d.logicalVolumes?.find(l => l.filesystem?.mountPath !== undefined)); + + // FIXME This is only to avoid showing the existing VG of my VM. Remove and use lvmVgs. + const newLvmVgs = lvmVgs.filter(v => system.find(d => d.sid === v.sid) === undefined); + + return instDevices.concat(newLvmVgs); + }; + + const children = (device) => { + const partitionTableChildren = (partitionTable) => { + const { partitions, unusedSlots } = partitionTable; + const children = partitions.concat(unusedSlots); + + return children.sort((a, b) => a.start < b.start ? -1 : 1); + }; - return diskDevices.concat(lvmVgs); + const lvmVgChildren = (lvmVg) => { + return lvmVg.logicalVolumes.sort((a, b) => a.name < b.name ? -1 : 1); + }; + + if (device.partitionTable) return partitionTableChildren(device.partitionTable); + if (device.type === "lvmVg") return lvmVgChildren(device); + return []; }; - const presenter = (storageElement) => { - if (devicesManager.isSlot(storageElement)) - return new SlotPresenter(storageElement); - else - return new DevicePresenter(storageElement, devicesManager); + const renderDeviceName = (item) => { + const newLabel = (device) => { + const systemDevice = system.find(d => d.sid === device.sid); + if (!systemDevice) return _("(new)"); + }; + + return ( +
+ {item.sid && item.name} + {newLabel(item)} +
+ ); }; - return usedDevices().map(device => { - const devices = [device].concat(devicesManager.children(device)); + const renderDetails = (item) => { + if (!item.sid) return _("Unused space"); - return devices.map((d, i) => { - return ; - }); - }); + return ( +
+ {/* {newLabel(item)} */} + {item.description} + {item.filesystem?.label} +
+ ); + }; + + const renderSize = (item) => deviceSize(item.size); + + const renderMountPoint = (item) => item.sid && item.filesystem?.mountPath; + + return ( + { + if (!item.sid) return "dimmed-row"; + }} + /> + ); }; /** @@ -267,6 +230,7 @@ export default function ProposalActionsSection({ then={} else={ <> +
{c.title}{c.title}