/* * 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 { dialog_open, TextInput, CheckBoxes, SizeSlider, BlockingMessage, TeardownMessage, init_teardown_usage, } from "../dialog.jsx"; import { StorageUsageBar, StorageLink } from "../storage-controls.jsx"; import { StorageCard, StorageDescription, new_page, new_card, navigate_away_from_card, navigate_to_new_card_location, } from "../pages.jsx"; import { MountPoint, edit_mount_point, is_valid_mount_point, is_mounted, get_fstab_config, mount_point_text, } from "../filesystem/utils.jsx"; import { MismountAlert, check_mismounted_fsys } from "../filesystem/mismounting.jsx"; import { mounting_dialog, at_boot_input, update_at_boot_input, mount_options } from "../filesystem/mounting-dialog.jsx"; import { fmt_size, get_active_usage, teardown_active_usage } from "../utils.js"; import { std_reply, validate_fs_name, set_mount_options, destroy_filesystem } from "./utils.jsx"; const _ = cockpit.gettext; export function make_stratis_filesystem_page(parent, pool, fsys, offset, forced_options) { const filesystems = client.stratis_pool_filesystems[pool.path]; const stats = client.stratis_pool_stats[pool.path]; const block = client.slashdevs_block[fsys.Devnode]; if (!block) return; const fstab_config = get_fstab_config(block); const [, mount_point] = fstab_config; const fs_is_mounted = is_mounted(client, block); const mismount_warning = check_mismounted_fsys(block, block, fstab_config); function mount() { return mounting_dialog(client, block, "mount", forced_options); } function unmount() { return mounting_dialog(client, block, "unmount", forced_options); } function snapshot_fsys() { dialog_open({ Title: cockpit.format(_("Create a snapshot of filesystem $0"), fsys.Name), Fields: [ TextInput("name", _("Name"), { value: "", validate: name => validate_fs_name(null, name, filesystems) }), TextInput("mount_point", _("Mount point"), { validate: (val, values, variant) => { return is_valid_mount_point(client, null, client.add_mount_point_prefix(val), variant === "nomount"); } }), mount_options(false, false), at_boot_input(), ], update: update_at_boot_input, Action: { Title: _("Create snapshot and mount"), Variants: [{ tag: "nomount", Title: _("Create snapshot only") }], action: function (vals) { return pool.SnapshotFilesystem(fsys.path, vals.name) .then(std_reply) .then(result => { if (result[0]) return set_mount_options(result[1], vals, forced_options); else return Promise.resolve(); }); } } }); } function delete_fsys() { const usage = get_active_usage(client, block.path, _("delete")); if (usage.Blocking) { dialog_open({ Title: cockpit.format(_("$0 is in use"), fsys.Name), Body: BlockingMessage(usage) }); return; } dialog_open({ Title: cockpit.format(_("Confirm deletion of $0"), fsys.Name), Teardown: TeardownMessage(usage), Action: { Danger: _("Deleting a filesystem will delete all data in it."), Title: _("Delete"), action: async function () { await teardown_active_usage(client, usage); await destroy_filesystem(fsys); navigate_away_from_card(fsys_card); } }, Inits: [ init_teardown_usage(client, usage) ] }); } const mp_text = mount_point_text(mount_point, fs_is_mounted); if (mp_text == null) return null; const fsys_card = new_card({ title: _("Stratis filesystem"), location: mp_text, next: null, page_location: ["pool", pool.Name, fsys.Name], page_name: fsys.Name, page_size: , has_warning: !!mismount_warning, component: StratisFilesystemCard, props: { pool, fsys, fstab_config, forced_options, mismount_warning, offset }, actions: [ client.in_anaconda_mode() && { title: _("Edit mount point"), action: () => edit_mount_point(block, forced_options) }, (fs_is_mounted ? { title: _("Unmount"), action: unmount } : null), (!fs_is_mounted && !client.in_anaconda_mode() ? { title: _("Mount"), action: mount } : null), { title: _("Snapshot"), action: snapshot_fsys, excuse: ((!pool.Overprovisioning && stats.pool_free < Number(fsys.Size)) ? _("Not enough free space") : null), }, { title: _("Delete"), action: delete_fsys, danger: true }, ] }); new_page(parent, fsys_card); } const StratisFilesystemCard = ({ card, pool, fsys, fstab_config, forced_options, mismount_warning, offset, }) => { const filesystems = client.stratis_pool_filesystems[pool.path]; const stats = client.stratis_pool_stats[pool.path]; const block = client.slashdevs_block[fsys.Devnode]; function rename_fsys() { dialog_open({ Title: _("Rename filesystem"), Fields: [ TextInput("name", _("Name"), { value: fsys.Name, validate: name => validate_fs_name(fsys, name, filesystems) }) ], Action: { Title: _("Rename"), action: async function (vals) { await fsys.SetName(vals.name).then(std_reply); navigate_to_new_card_location(card, ["pool", pool.Name, vals.name]); } } }); } function set_limit() { dialog_open({ Title: _("Set limit of virtual filesystem size"), Fields: [ CheckBoxes("size_options", _("Options"), { value: { custom_limit: fsys.SizeLimit[0], }, fields: [ { tag: "custom_limit", title: _("Limit virtual filesystem size") }, ] }), SizeSlider("limit", _("Virtual size limit"), { visible: vals => vals.size_options.custom_limit, value: fsys.SizeLimit[0] && Number(fsys.SizeLimit[1]), min: Number(fsys.Size), max: pool.Overprovisioning ? stats.pool_total : stats.pool_free + Number(fsys.Size), allow_infinite: true, round: 512 }), ], Action: { Title: _("Set"), action: async function (vals) { await client.stratis_set_property(fsys, "SizeLimit", "(bs)", (vals.size_options.custom_limit ? [true, vals.limit.toString()] : [false, ""])); } } }); } return ( }> {_("edit")} } /> {_("edit")} } /> ); };