Line data Source code
1 : /*
2 : * Copyright (C) 2019 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 : import '../lib/patternfly/patternfly-6-cockpit.scss';
7 : import 'polyfills';
8 : import 'cockpit-dark-theme'; // once per page
9 94 : import cockpit from "cockpit";
10 :
11 94 : import React from 'react';
12 94 : import { createRoot } from "react-dom/client";
13 : import { Page, PageSection, PageSectionVariants } from "@patternfly/react-core/dist/esm/components/Page/index.js";
14 : import { Gallery } from "@patternfly/react-core/dist/esm/layouts/Gallery/index.js";
15 : import { Dropdown, DropdownItem, DropdownList } from '@patternfly/react-core/dist/esm/components/Dropdown/index.js';
16 : import { MenuToggle, MenuToggleAction } from "@patternfly/react-core/dist/esm/components/MenuToggle";
17 :
18 : import { superuser } from "superuser";
19 :
20 : import { SystemInformationCard } from './overview-cards/systemInformationCard.jsx';
21 : import { ConfigurationCard } from './overview-cards/configurationCard.jsx';
22 : import { HealthCard } from './overview-cards/healthCard.jsx';
23 : import { MotdCard } from './overview-cards/motdCard.jsx';
24 : import { UsageCard } from './overview-cards/usageCard.jsx';
25 : import { SuperuserAlert } from './superuser-alert.jsx';
26 : import { superuser_proxy, SuperuserIndicator } from "superuser-dialogs";
27 : import { ShutdownModal } from 'cockpit-components-shutdown.jsx';
28 : import { WithDialogs, DialogsContext } from "dialogs.jsx";
29 :
30 : import "./overview.scss";
31 : import { Title, TitleSizes } from '@patternfly/react-core/dist/esm/components/Title';
32 :
33 94 : const _ = cockpit.gettext;
34 :
35 94 : class OverviewPage extends React.Component {
36 94 : static contextType = DialogsContext;
37 :
38 94 : constructor(props) {
39 94 : super(props);
40 :
41 94 : this.state = {
42 94 : actionIsOpen: false,
43 94 : privileged: true,
44 94 : };
45 94 : this.hostnameMonitor = this.hostnameMonitor.bind(this);
46 94 : this.onPermissionChanged = this.onPermissionChanged.bind(this);
47 :
48 94 : this.superuser = superuser_proxy();
49 94 : }
50 :
51 94 : componentDidMount() {
52 94 : this.hostnameMonitor();
53 94 : superuser.addEventListener("changed", this.onPermissionChanged);
54 94 : this.onPermissionChanged();
55 94 : }
56 :
57 0 : componentWillUnmount() {
58 0 : superuser.removeEventListener("changed", this.onPermissionChanged);
59 0 : }
60 :
61 94 : onPermissionChanged() {
62 94 : this.setState({ privileged: superuser.allowed });
63 94 : }
64 :
65 94 : hostname_text() {
66 94 : if (!this.state.hostnameData)
67 94 : return undefined;
68 :
69 81 : const pretty_hostname = this.state.hostnameData.PrettyHostname;
70 81 : const static_hostname = this.state.hostnameData.StaticHostname;
71 81 : let str = this.state.hostnameData.Hostname;
72 :
73 16 : if (pretty_hostname && static_hostname && static_hostname != pretty_hostname)
74 16 : str = pretty_hostname + " (" + static_hostname + ")";
75 81 : else if (static_hostname)
76 80 : str = static_hostname;
77 :
78 16 : return str || '';
79 94 : }
80 :
81 94 : hostnameMonitor() {
82 94 : this.client = cockpit.dbus('org.freedesktop.hostname1');
83 94 : this.hostname_proxy = this.client.proxy('org.freedesktop.hostname1',
84 94 : '/org/freedesktop/hostname1');
85 81 : this.hostname_proxy.addEventListener("changed", data => {
86 81 : this.setState({ hostnameData: data.detail });
87 81 : });
88 94 : }
89 :
90 94 : render() {
91 94 : const Dialogs = this.context;
92 94 : const { actionIsOpen } = this.state;
93 94 : const dropdownItems = [
94 94 : <DropdownItem key="reboot" id="reboot"
95 0 : onClick={() => Dialogs.show(<ShutdownModal />)}
96 94 : component="button">
97 94 : {_("Reboot")}
98 94 : </DropdownItem>,
99 94 : <DropdownItem key="shutdown" id="shutdown"
100 1 : onClick={() => Dialogs.show(<ShutdownModal shutdown />)}
101 94 : component="button">
102 94 : {_("Shutdown")}
103 94 : </DropdownItem>,
104 94 : ];
105 :
106 94 : let headerActions = null;
107 94 : if (this.state.privileged)
108 94 : headerActions = (
109 1 : <Dropdown onSelect={() => this.setState({ actionIsOpen: false })}
110 94 : toggle={(toggleRef) => (
111 94 : <MenuToggle
112 94 : ref={toggleRef}
113 94 : variant="secondary"
114 94 : splitButtonItems={[
115 94 : <MenuToggleAction
116 94 : id='reboot-button'
117 94 : key='reboot-button'
118 1 : onClick={() => Dialogs.show(<ShutdownModal />)}
119 : >
120 94 : {_("Reboot")}
121 94 : </MenuToggleAction>
122 94 : ]}
123 1 : onClick={() => this.setState({ actionIsOpen: !actionIsOpen })}
124 94 : id="shutdown-group"
125 94 : />
126 : )}
127 94 : isOpen={actionIsOpen}
128 94 : popperProps={{ position: "right" }}
129 : >
130 94 : <DropdownList>
131 94 : {dropdownItems}
132 94 : </DropdownList>
133 94 : </Dropdown>
134 : );
135 :
136 94 : const show_superuser = (
137 94 : cockpit.transport.host && cockpit.transport.host != "localhost" &&
138 33 : !(window.parent.name == "cockpit1" && window.parent.features &&
139 33 : window.parent.features.navbar_is_for_current_machine));
140 :
141 94 : return (
142 94 : <Page className='pf-m-no-sidebar'>
143 94 : <SuperuserAlert />
144 94 : <PageSection hasBodyWrapper={false} className='ct-overview-header' padding={{ default: 'padding' }}>
145 94 : <div className='ct-overview-header-hostname'>
146 94 : <Title size={TitleSizes['3xl']} headingLevel='h1'>
147 94 : {this.hostname_text()}
148 94 : </Title>
149 94 : {this.state.hostnameData &&
150 81 : this.state.hostnameData.OperatingSystemPrettyName &&
151 81 : <div className="ct-overview-header-subheading" id="system_information_os_text">{cockpit.format(_("running $0"), this.state.hostnameData.OperatingSystemPrettyName)}</div>}
152 94 : </div>
153 94 : <div className='ct-overview-header-actions'>
154 16 : { show_superuser && <SuperuserIndicator proxy={this.superuser} /> }
155 94 : { "\n" }
156 94 : { headerActions }
157 94 : </div>
158 94 : </PageSection>
159 94 : <PageSection hasBodyWrapper={false} variant={PageSectionVariants.default}>
160 94 : <Gallery className='ct-system-overview' hasGutter>
161 94 : <MotdCard />
162 94 : <HealthCard />
163 94 : <UsageCard />
164 94 : <SystemInformationCard />
165 94 : <ConfigurationCard hostname={this.hostname_text()} />
166 94 : </Gallery>
167 94 : </PageSection>
168 94 : </Page>
169 : );
170 94 : }
171 94 : }
172 :
173 94 : function init() {
174 94 : cockpit.translate();
175 94 : const root = createRoot(document.getElementById("overview"));
176 94 : root.render(<WithDialogs><OverviewPage /></WithDialogs>);
177 94 : }
178 :
179 94 : document.addEventListener("DOMContentLoaded", init);
|