/* * Copyright (C) 2023 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import cockpit from "cockpit"; import React from "react"; import client from "../client"; import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js"; import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { useEvent } from "hooks"; import { block_name, fmt_size, validate_fsys_label } from "../utils.js"; import { dialog_open, TextInput, } from "../dialog.jsx"; import { StorageLink, StorageUsageBar, StorageSize } from "../storage-controls.jsx"; import { StorageCard, StorageDescription, new_card, useIsNarrow } from "../pages.jsx"; import { std_format_action } from "../block/actions.jsx"; import { is_mounted, MountPoint, mount_point_text, edit_mount_point } from "./utils.jsx"; import { mounting_dialog } from "./mounting-dialog.jsx"; import { check_mismounted_fsys, MismountAlert } from "./mismounting.jsx"; const _ = cockpit.gettext; /* This page is used in a variety of cases, which can be distinguished * by looking at the "backing_block" and "content_block" parameters: * * not-encrypted: backing_block == content_block, * content_block != null * * encrypted and unlocked: backing_block != content_block, * backing_block != null, * content_block != null * * encrypted and locked: backing_block != null, * content_block == null * * "backing_block" is always non-null and always refers to the block * device that we want to talk about in the UI. "content_block" (when * non-null) is the block that we need to use for filesystem related * actions, such as mounting. It's the one with the * "o.fd.UDisks2.Filesystem" interface. * * When "content_block" is null, then "backing_block" is a locked LUKS * device, but we could figure out the fstab entry for the filesystem * that's on it. */ const MountPointUsageBar = ({ mount_point, block, short }) => { useEvent(client.fsys_sizes, "changed"); const narrow = useIsNarrow(); const stats = client.fsys_sizes.data[mount_point]; if (stats) return ; else if (short && !narrow) return ; else return fmt_size(block.Size); }; export function make_filesystem_card(next, backing_block, content_block, fstab_config) { const [, mount_point] = fstab_config; const mismount_warning = check_mismounted_fsys(backing_block, content_block, fstab_config); const mounted = content_block && is_mounted(client, content_block); const mp_text = mount_point_text(mount_point, mounted); if (mp_text == null) return null; return new_card({ title: content_block ? cockpit.format(_("$0 filesystem"), content_block.IdType) : _("Filesystem"), location: mp_text, next, page_size: , has_warning: !!mismount_warning, component: FilesystemCard, props: { backing_block, content_block, fstab_config, mismount_warning }, actions: [ client.in_anaconda_mode() && { title: _("Edit mount point"), action: () => edit_mount_point(content_block || backing_block) }, content_block && mounted ? { title: _("Unmount"), action: () => mounting_dialog(client, content_block, "unmount") } : null, !(content_block && mounted) && !client.in_anaconda_mode() ? { title: _("Mount"), action: () => mounting_dialog(client, content_block || backing_block, "mount") } : null, std_format_action(backing_block, content_block), ] }); } export const FilesystemCard = ({ card, backing_block, content_block, fstab_config, mismount_warning }) => { function rename_dialog() { // assert(content_block) const block_fsys = client.blocks_fsys[content_block.path]; dialog_open({ Title: _("Filesystem name"), Fields: [ TextInput("name", _("Name"), { validate: name => validate_fsys_label(name, content_block.IdType), value: content_block.IdLabel }) ], Action: { Title: _("Save"), action: function (vals) { return block_fsys.SetLabel(vals.name, {}); } } }); } const [, mount_point] = fstab_config; const mounted = content_block && is_mounted(client, content_block); return ( {_("edit")} } /> { mounted && } { mismount_warning && } ); };