Skip to content

Commit

Permalink
WIP - new shell
Browse files Browse the repository at this point in the history
  • Loading branch information
mvollmer committed Sep 17, 2024
1 parent c35a131 commit 40bd4da
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 830 deletions.
2 changes: 1 addition & 1 deletion files.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const info = {
"playground/remote.tsx",

"selinux/selinux.js",
"shell/shell.js",
"shell/shell.jsx",
"sosreport/sosreport.jsx",
"static/login.js",
"storaged/storaged.jsx",
Expand Down
134 changes: 32 additions & 102 deletions pkg/shell/base_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@
*/

import cockpit from "cockpit";
import React from "react";
import { createRoot } from "react-dom/client";

import { TimeoutModal } from "./shell-modals.jsx";

const shell_embedded = window.location.pathname.indexOf(".html") !== -1;
const _ = cockpit.gettext;
// const _ = cockpit.gettext;

function component_checksum(machine, component) {
const parts = component.split("/");
Expand All @@ -42,8 +38,15 @@ function Frames(index, setupIdleResetTimers) {
/* Lists of frames, by host */
self.iframes = { };

/* Array with stable order, so that React will always render
iframes in the same order.
*/
self.frame_array = [];

function remove_frame(frame) {
frame.remove();
const idx = self.frame_array.findIndex(f => f === frame);
if (idx >= 0)
self.frame_array.splice(idx, 1);
}

self.remove = function remove(machine, component) {
Expand All @@ -65,46 +68,6 @@ function Frames(index, setupIdleResetTimers) {
});
};

function frame_ready(frame, count) {
let ready = false;

window.clearTimeout(frame.timer);
frame.timer = null;

try {
if (frame.contentWindow.document && frame.contentWindow.document.body)
ready = frame.contentWindow.document.body.offsetWidth > 0 && frame.contentWindow.document.body.offsetHeight > 0;
} catch (ex) {
ready = true;
}

if (!count)
count = 0;
count += 1;
if (count > 50)
ready = true;

if (ready) {
if (frame.getAttribute("data-ready") != "1") {
frame.setAttribute("data-ready", "1");
if (count > 0)
index.navigate();
}
if (frame.contentWindow && setupIdleResetTimers)
setupIdleResetTimers(frame.contentWindow);

if (frame.contentDocument && frame.contentDocument.documentElement) {
frame.contentDocument.documentElement.lang = language;
if (cockpit.language_direction)
frame.contentDocument.documentElement.dir = cockpit.language_direction;
}
} else {
frame.timer = window.setTimeout(function() {
frame_ready(frame, count + 1);
}, 100);
}
}

self.lookup = function lookup(machine, component, hash) {
let host;
let address;
Expand All @@ -128,23 +91,11 @@ function Frames(index, setupIdleResetTimers) {

const name = "cockpit1:" + host + "/" + component;
let frame = list[component];
if (frame && frame.getAttribute("name") != name) {
if (frame && frame.name != name) {
remove_frame(frame);
frame = null;
}

/* A preloaded frame */
if (!frame) {
const wind = window.frames[name];
if (wind)
frame = wind.frameElement;
if (frame) {
const src = frame.getAttribute('src');
frame.url = src.split("#")[0];
list[component] = frame;
}
}

/* Need to create a new frame */
if (!frame) {
/* Never create new frames for machines that are not
Expand All @@ -158,11 +109,7 @@ function Frames(index, setupIdleResetTimers) {
return null;

new_frame = true;
frame = document.createElement("iframe");
frame.setAttribute("class", "container-frame");
frame.setAttribute("name", name);
frame.setAttribute("data-host", host);
frame.style.display = "none";
frame = { name, host: machine.address, component, ready: true, active: false };

let base, checksum;
if (machine) {
Expand Down Expand Up @@ -200,26 +147,15 @@ function Frames(index, setupIdleResetTimers) {
if (!hash)
hash = "/";
const src = frame.url + "#" + hash;
if (frame.getAttribute('src') != src) {
if (frame.contentWindow) {
// This prevents the browser from creating a new
// history entry. It would do that whenever the "src"
// of a frame is changed and the window location is
// not consistent with the new "src" value.
//
// This matters when a "jump" command changes both the
// the current frame and the hash of the new frame.
frame.contentWindow.location.replace(src);
}
frame.setAttribute('src', src);
}
frame.src = src;

/* Store frame only when fully setup */
if (new_frame) {
list[component] = frame;
document.getElementById("content").appendChild(frame);
self.frame_array.push(frame);

const style = localStorage.getItem('shell:style') || 'auto';
console.log("style", style);
let dark_mode;
// If a user set's an explicit theme, ignore system changes.
if ((window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && style === "auto") || style === "dark") {
Expand All @@ -228,17 +164,8 @@ function Frames(index, setupIdleResetTimers) {
dark_mode = false;
}

// The new iframe is shown before any HTML/CSS is ready and loaded,
// explicitly set a dark background so we don't see any white flashes
if (dark_mode && frame.contentDocument && frame.contentDocument.documentElement) {
// --pf-v5-global--BackgroundColor--dark-300
const dark_mode_background = '#1b1d21';
frame.contentDocument.documentElement.style.background = dark_mode_background;
} else {
frame.contentDocument.documentElement.style.background = 'white';
}
frame.dark_mode = dark_mode;
}
frame_ready(frame);
return frame;
};
}
Expand Down Expand Up @@ -287,7 +214,7 @@ function Router(index) {
function perform_jump(child, control) {
const current_frame = index.current_frame();
if (child !== window) {
if (!current_frame || current_frame.contentWindow != child)
if (!current_frame || current_frame.name != child.name)
return;
}
let str = control.location || "";
Expand All @@ -300,8 +227,8 @@ function Router(index) {

function perform_track(child) {
const current_frame = index.current_frame();
/* Note that we ignore tracknig for old shell code */
if (current_frame && current_frame.contentWindow === child &&
/* Note that we ignore tracking for old shell code */
if (current_frame && current_frame.name === child.name &&
child.name && child.name.indexOf("/shell/shell") === -1) {
let hash = child.location.hash;
if (hash.indexOf("#") === 0)
Expand Down Expand Up @@ -341,6 +268,7 @@ function Router(index) {

function unregister(source) {
const child = source.window;
console.log("UNREGISTER", child);
cockpit.kill(null, child.name);
const frame = child.frameElement;
if (frame)
Expand All @@ -355,6 +283,7 @@ function Router(index) {
}

function register(child) {
console.log("REGISTER", child);
let host, page;
const name = child.name || "";
if (name.indexOf("cockpit1:") === 0) {
Expand Down Expand Up @@ -463,8 +392,8 @@ function Router(index) {
source.inited = true;

/* If this new frame is not the current one, tell it */
if (child.frameElement != index.current_frame())
self.hint(child.frameElement.contentWindow, { hidden: true });
if (child.frameElement.name != index.current_frame()?.name)
self.hint(child.frameElement.name, { hidden: true });
}
} else if (control.command === "jump") {
perform_jump(child, control);
Expand Down Expand Up @@ -511,8 +440,8 @@ function Router(index) {
message_handler(messages[i]);
};

self.hint = function hint(child, data) {
const source = source_by_name[child.name];
self.hint = function hint(name, data) {
const source = source_by_name[name];
/* This is often invalid when the window is closed */
if (source && source.inited && !source.window.closed) {
data.command = "hint";
Expand Down Expand Up @@ -560,6 +489,7 @@ function Index() {

let session_timeout_dialog_root = null;

/* XXX
function updateFinalCountdown() {
const remaining_secs = Math.floor(final_countdown / 1000);
const timeout_text = cockpit.format(_("You will be logged out in $0 seconds."), remaining_secs);
Expand Down Expand Up @@ -589,6 +519,7 @@ function Index() {
cockpit.logout(true, _("You have been logged out due to inactivity."));
}
}
*/

/* Auto-logout idle timer */
function resetTimer(ev) {
Expand Down Expand Up @@ -718,7 +649,7 @@ function Index() {
const iframe = list ? list[component] : undefined;

if (iframe) {
const src = iframe.getAttribute('src');
const src = iframe.src;
if (src)
return src.split("#")[1];
}
Expand Down Expand Up @@ -754,8 +685,7 @@ function Index() {
// When switching hosts, check if we left from some page
if (!state.component && state.host !== current.host) {
const host_frames = self.frames.iframes[state.host] || {};
const active = Object.keys(host_frames)
.filter(k => host_frames[k].getAttribute('data-active') === 'true');
const active = Object.keys(host_frames).filter(k => host_frames[k].active === 'true');
if (active.length > 0)
state.component = active[0];
}
Expand Down Expand Up @@ -800,10 +730,10 @@ function Index() {
self.current_frame = function (frame) {
if (frame !== undefined) {
if (current_frame !== frame) {
if (current_frame && current_frame.contentWindow)
self.router.hint(current_frame.contentWindow, { hidden: true });
if (frame && frame.contentWindow)
self.router.hint(frame.contentWindow, { hidden: false });
if (current_frame)
self.router.hint(current_frame.name, { hidden: true });
if (frame)
self.router.hint(frame.name, { hidden: false });
}
current_frame = frame;
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/shell/hosts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { HostModal, try2Connect, codes } from "./hosts_dialog.jsx";
import { useLoggedInUser } from "hooks";

const _ = cockpit.gettext;
const hosts_sel = document.getElementById("nav-hosts");

class HostsSelector extends React.Component {
constructor() {
Expand All @@ -29,10 +28,12 @@ class HostsSelector extends React.Component {
}

componentDidMount() {
const hosts_sel = document.getElementById("nav-hosts");
hosts_sel.appendChild(this.el);
}

componentWillUnmount() {
const hosts_sel = document.getElementById("nav-hosts");
hosts_sel.removeChild(this.el);
}

Expand Down
42 changes: 2 additions & 40 deletions pkg/shell/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,8 @@
<script src="../*/po.manifest.js"></script>
<script src="../*/po.js"></script>
<script src="po.js"></script>
</head>
<body class="pf-v5-m-tabular-nums" hidden="true">
<div id="main" class="page">
<a class="screenreader-text skiplink desktop_v" href="#content" translate="yes">Skip to content</a>
<a class="screenreader-text skiplink desktop_v" href="#hosts-sel" translate="yes">Skip main navigation</a>

<div id="sidebar-toggle" class="pf-v5-c-select pf-m-dark sidebar-toggle">
</div>

<div id="nav-system" class="area-ct-subnav nav-system-menu sidebar interact">
<nav id="host-apps" class="host-apps">
<!-- Navigation goes here !-->
</nav>
</div>

<nav id="hosts-sel" class="navbar navbar-default navbar-pf navbar-pf-vertical" tabindex="-1">
<!-- Hosts selector goes here !-->
</nav>

<div id="nav-hosts" class="area-ct-subnav nav-hosts-menu sidebar">
<!-- Hosts go here !-->
</div>

<div id="topnav" class="header">
<!-- Top navigation goes here !-->
</div>


<div id="troubleshoot-dialog"></div>
<div id="session-timeout-dialog"></div>

<div id="content" role="main" class="area-ct-content" tabindex="-1">
<!-- This is where the iframes appear -->
<div id="early-failure-ready" class="curtains-ct" hidden="true"></div>
</div>
</div>

<div id="early-failure" class="early-failure" hidden="true">
</div>

<script src="shell.js"></script>
</head>
<body class="pf-v5-m-tabular-nums" id="shell">
</body>
</html>
Loading

0 comments on commit 40bd4da

Please sign in to comment.