🏡 index : quine-global-labs/mirror-cockpit-project-cockpit.git

/*
 * 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 { StorageCard, StorageDescription, ChildrenTable, new_page, new_card } from "../pages.jsx";
import { fmt_size, validate_lvm2_name } from "../utils.js";
import { dialog_open, TextInput, SizeSlider } from "../dialog.jsx";
import { StorageLink } from "../storage-controls.jsx";
import { grow_dialog } from "../block/resize.jsx";

import { next_default_logical_volume_name } from "./utils.jsx";
import { lvol_rename, lvol_delete } from "./block-logical-volume.jsx";
import { make_lvm2_logical_volume_page } from "./volume-group.jsx";

const _ = cockpit.gettext;

export function make_thin_pool_logical_volume_page(parent, vgroup, lvol) {
    function create_thin() {
        dialog_open({
            Title: _("Create thin volume"),
            Fields: [
                TextInput("name", _("Name"),
                          {
                              value: next_default_logical_volume_name(client, vgroup, "lvol"),
                              validate: validate_lvm2_name
                          }),
                SizeSlider("size", _("Size"),
                           {
                               value: lvol.Size,
                               max: lvol.Size * 3,
                               allow_infinite: true,
                               round: vgroup.ExtentSize
                           })
            ],
            Action: {
                Title: _("Create"),
                action: function (vals) {
                    return vgroup.CreateThinVolume(vals.name, vals.size, lvol.path, { });
                }
            }
        });
    }

    const pool_card = make_lvm2_thin_pool_card(null, vgroup, lvol);

    const thin_vols_card = new_card({
        title: _("Thinly provisioned LVM2 logical volumes"),
        next: pool_card,
        page_location: ["vg", vgroup.Name, lvol.Name],
        page_name: lvol.Name,
        page_size: lvol.Size,
        component: LVM2ThinPoolLogicalVolumeCard,
        props: { vgroup, lvol },
        actions: [
            {
                title: _("Create new thinly provisioned logical volume"),
                action: create_thin,
                tag: "pool",
            },
        ]
    });

    const p = new_page(parent, thin_vols_card);

    client.lvols_pool_members[lvol.path].forEach(member_lvol => {
        make_lvm2_logical_volume_page(p, vgroup, member_lvol);
    });
}

function make_lvm2_thin_pool_card(next, vgroup, lvol) {
    let grow_excuse = null;
    if (vgroup.FreeSize === 0)
        grow_excuse = _("Not enough space");

    const card = new_card({
        title: _("Pool for thinly provisioned LVM2 logical volumes"),
        next,
        component: LVM2ThinPoolCard,
        props: { vgroup, lvol },
        actions: [
            {
                title: _("Grow"),
                action: () => grow_dialog(client, lvol, { }),
                excuse: grow_excuse,
            },
            {
                title: _("Delete"),
                action: () => lvol_delete(lvol, card),
                danger: true,
            },
        ],
    });
    return card;
}

function perc(ratio) {
    return (ratio * 100).toFixed(0) + "%";
}

export const LVM2ThinPoolLogicalVolumeCard = ({ card, vgroup, lvol }) => {
    return (
        <StorageCard card={card}>
            <ChildrenTable
                emptyCaption={_("No logical volumes")}
                aria-label={_("Thinly provisioned LVM2 logical volumes")}
                page={card.page} />
        </StorageCard>);
};

export const LVM2ThinPoolCard = ({ card, vgroup, lvol }) => {
    return (
        <StorageCard card={card}>
            <CardBody>
                <DescriptionList className="pf-m-horizontal-on-sm">
                    <StorageDescription title={_("Name")}
                           value={lvol.Name}
                           action={<StorageLink onClick={() => lvol_rename(lvol)}>
                               {_("edit")}
                           </StorageLink>} />
                    <StorageDescription title={_("Size")} value={fmt_size(lvol.Size)} />
                    <StorageDescription title={_("Data used")} value={perc(lvol.DataAllocatedRatio)} />
                    <StorageDescription title={_("Metadata used")} value={perc(lvol.MetadataAllocatedRatio)} />
                </DescriptionList>
            </CardBody>
        </StorageCard>);
};