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

/*
 * Copyright (C) 2020 Red Hat, Inc.
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

import cockpit from "cockpit";
import React, { useState } from "react";
import { AboutModal } from "@patternfly/react-core/dist/esm/components/AboutModal/index.js";
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { Divider } from "@patternfly/react-core/dist/esm/components/Divider/index.js";
import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { Menu, MenuContent, MenuSearch, MenuSearchInput, MenuItem, MenuList } from "@patternfly/react-core/dist/esm/components/Menu/index.js";
import {
    Modal, ModalBody, ModalFooter, ModalHeader
} from '@patternfly/react-core/dist/esm/components/Modal/index.js';
import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput/index.js";
import { Content, ContentVariants } from "@patternfly/react-core/dist/esm/components/Content/index.js";
import { SearchIcon } from '@patternfly/react-icons';

import { useInit } from "hooks";
import { DialogResult } from "dialogs";

import { ShellState } from "./state";

import "menu-select-widget.scss";

const _ = cockpit.gettext;

interface Package {
    name: string;
    version: string;
}

export const AboutCockpitModal = ({
    dialogResult
} : {
    dialogResult: DialogResult<void>
}) => {
    const [packages, setPackages] = useState<Package[]>([]);

    useInit(() => {
        const packages: Package[] = [];
        const cmd = "(set +e; rpm -qa --qf '%{NAME} %{VERSION}\\n'; dpkg-query -f '${Package} ${Version}\n' --show; pacman -Q) 2> /dev/null | grep cockpit | sort";
        cockpit.spawn(["bash", "-c", cmd], { err: "message" })
                .then(pkgs =>
                    pkgs.trim().split("\n")
                            .forEach(p => {
                                const parts = p.split(" ");
                                packages.push({ name: parts[0], version: parts[1] });
                            })
                )
                .catch(error => console.error("Could not read packages versions:", error))
                .finally(() => setPackages(packages));
    });

    return (
        <AboutModal
            isOpen
            onClose={() => dialogResult.resolve()}
            id="about-cockpit-modal"
            aria-label="About Cockpit and its versions"
            trademark={_("Licensed under GNU LGPL version 2.1")}
            productName={_("Web Console")}
            brandImageSrc="../shell/images/cockpit-icon-gray.svg"
            brandImageAlt={_("Web console logo")}
        >
            <Content component={ContentVariants.p}>
                {_("Cockpit is an interactive Linux server admin interface.")}
            </Content>
            <Content component={ContentVariants.p}>
                <Content component={ContentVariants.a} href="https://cockpit-project.org" target="_blank" rel="noopener noreferrer">
                    {_("Project website")}
                </Content>
            </Content>
            <Content component="dl">
                {packages === null && <span>{_("Loading packages...")}</span>}
                {packages !== null && packages.map(p =>
                    <React.Fragment key={p.name}>
                        <Content key={p.name} component="dt">{p.name}</Content>
                        <Content component="dd">{p.version}</Content>
                    </React.Fragment>
                )}
            </Content>
        </AboutModal>
    );
};

export interface LangModalProps {
    dialogResult: DialogResult<void>;
    state: ShellState;
}

export const LangModal = ({
    dialogResult,
    state
}: LangModalProps) => {
    const language = document.cookie.replace(/(?:(?:^|.*;\s*)CockpitLang\s*=\s*([^;]*).*$)|^.*$/, "$1") || "en-us";

    const [selected, setSelected] = useState(language);
    const [searchInput, setSearchInput] = useState("");

    function onSelect() {
        if (!selected)
            return;

        const cookie = "CockpitLang=" + encodeURIComponent(selected) + "; path=/; expires=Sun, 16 Jul 3567 06:23:41 GMT";
        document.cookie = cookie;
        window.localStorage.setItem("cockpit.lang", selected);
        window.location.reload();
    }

    return (
        <Modal isOpen position="top" variant="small"
               id="display-language-modal"
               className="display-language-modal"
               onClose={() => dialogResult.resolve()}
        >
            <ModalHeader title={_("Display language")} />
            <ModalBody>
                <Flex direction={{ default: 'column' }}>
                    <p>{_("Choose the language to be used in the application")}</p>
                    <Menu id="display-language-list"
                          isPlain
                          isScrollable
                          className="ct-menu-select-widget"
                          onSelect={(_, selected) => setSelected(selected as string)}
                          activeItemId={selected}
                          selected={selected}>
                        <MenuSearch>
                            <MenuSearchInput>
                                <TextInput
                                    value={searchInput}
                                    aria-label={_("Filter menu items")}
                                    customIcon={<SearchIcon />}
                                    type="search"
                                    onChange={(_event, value) => setSearchInput(value)}
                                />
                            </MenuSearchInput>
                        </MenuSearch>
                        <Divider />
                        <MenuContent>
                            <MenuList>
                                {
                                    (() => {
                                        const locales = state.config.manifest.locales || {};
                                        const filteredLocales = Object.keys(locales)
                                                .filter(key => !searchInput || locales[key].toLowerCase().includes(searchInput.toString().toLowerCase()));

                                        if (filteredLocales.length === 0) {
                                            return (
                                                <MenuItem isDisabled>
                                                    {_("No languages match")}
                                                </MenuItem>
                                            );
                                        }
                                        return filteredLocales.map(key => {
                                            return (
                                                <MenuItem itemId={key} key={key} data-value={key}>
                                                    {locales[key]}
                                                </MenuItem>
                                            );
                                        });
                                    })()
                                }
                            </MenuList>
                        </MenuContent>
                    </Menu>
                </Flex>
            </ModalBody>
            <ModalFooter>
                <Button variant='primary' onClick={onSelect}>{_("Select")}</Button>
                <Button variant='link' onClick={() => dialogResult.resolve()}>{_("Cancel")}</Button>
            </ModalFooter>
        </Modal>
    );
};

export interface OopsModalProps {
    dialogResult: DialogResult<void>;
}

export function OopsModal({ dialogResult }: OopsModalProps) {
    return (
        <Modal isOpen position="top" variant="medium"
               onClose={() => dialogResult.resolve()}
        >
            <ModalHeader title={_("Unexpected error")} />
            <ModalBody>
                {_("Cockpit had an unexpected internal error.")}
                <br />
                <br />
                <span>{("You can try restarting Cockpit by pressing refresh in your browser. The javascript console contains details about this error") + " ("}
                    <b>{_("Ctrl-Shift-I")}</b>
                    {" " + _("in most browsers") + ")."}
                </span>
            </ModalBody>
            <ModalFooter>
                <Button variant='secondary' onClick={() => dialogResult.resolve()}>{_("Close")}</Button>
            </ModalFooter>
        </Modal>
    );
}