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