Skip to content

Commit

Permalink
Merge f83ebeb into 5d045aa
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Jan 18, 2023
2 parents 5d045aa + f83ebeb commit 66379c7
Show file tree
Hide file tree
Showing 40 changed files with 889 additions and 101 deletions.
6 changes: 6 additions & 0 deletions service/lib/dinstaller/dbus/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def initialize(backend, logger)
dbus_method(:Probe, "") { config_phase }
dbus_method(:Commit, "") { install_phase }
dbus_method(:CanInstall, "out result:b") { can_install? }
dbus_method(:CollectLogs, "out tarball_filesystem_path:s, in user:s") { |u| collect_logs(u) }
dbus_reader :installation_phases, "aa{sv}"
dbus_reader :current_installation_phase, "u"
dbus_reader :busy_services, "as"
Expand Down Expand Up @@ -88,6 +89,11 @@ def can_install?
backend.valid?
end

# Collects the YaST logs
def collect_logs(user)
backend.collect_logs(user)
end

# Description of all possible installation phase values
#
# @return [Array<Hash>]
Expand Down
12 changes: 12 additions & 0 deletions service/lib/dinstaller/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ def valid?
[storage, users, software].all?(&:valid?)
end

# Collects the logs and stores them into an archive
#
# @param user [String] local username who will own archive
# @return [String] path to created archive
def collect_logs(user)
output = Yast::Execute.locally!("save_y2logs", stderr: :capture)
path = output[/^.* (\/tmp\/y2log-\S*)/, 1]
Yast::Execute.locally!("chown", "#{user}:", path)

path
end

private

attr_reader :config
Expand Down
6 changes: 6 additions & 0 deletions service/package/rubygem-d-installer.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Wed Jan 18 08:03:40 UTC 2023 - Josef Reidinger <jreidinger@suse.com>

- Save logs and provide the path to the file
(gh#yast/d-installer#379)

-------------------------------------------------------------------
Tue Jan 17 10:06:23 UT0 2023 - Josef Reidinger <jreidinger@suse.com>

Expand Down
13 changes: 13 additions & 0 deletions service/test/dinstaller/manager_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,17 @@
end
end
end

describe "#collect_logs" do
it "collects the logs and returns the path to the archive" do
expect(Yast::Execute).to receive(:locally!)
.with("save_y2logs", stderr: :capture)
.and_return("Saving YaST logs to /tmp/y2log-hWBn95.tar.xz")
expect(Yast::Execute).to receive(:locally!)
.with("chown", "ytm:", /y2log-hWBn95/)

path = subject.collect_logs("ytm")
expect(path).to eq("/tmp/y2log-hWBn95.tar.xz")
end
end
end
5 changes: 5 additions & 0 deletions web/package/cockpit-d-installer.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
-------------------------------------------------------------------
Wed Jan 18 08:06:05 UTC 2023 - Josef Reidinger <jreidinger@suse.com>

- Allow user downloading logs (gh#yast/d-installer#379)

-------------------------------------------------------------------
Thu Jan 12 16:23:54 UTC 2023 - Josef Reidinger <jreidinger@suse.com>

Expand Down
9 changes: 2 additions & 7 deletions web/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ import { useInstallerClient } from "@context/installer";
import { STARTUP, INSTALL } from "@client/phase";
import { BUSY } from "@client/status";

import { Layout, Title, AdditionalInfo, LoadingEnvironment, DBusError } from "@components/layout";
import { About, InstallationProgress, InstallationFinished } from "@components/core";
import { TargetIpsPopup } from "@components/network";
import { Layout, Title, LoadingEnvironment, DBusError } from "@components/layout";
import { InstallationProgress, InstallationFinished } from "@components/core";

function App() {
const client = useInstallerClient();
Expand Down Expand Up @@ -79,10 +78,6 @@ function App() {
<Layout>
<Title>D-Installer</Title>
<Content />
<AdditionalInfo>
<About />
<TargetIpsPopup />
</AdditionalInfo>
</Layout>
);
}
Expand Down
10 changes: 3 additions & 7 deletions web/src/App.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import React from "react";
import { act, screen } from "@testing-library/react";
import { installerRender, mockComponent } from "@/test-utils";
import { installerRender, mockComponent, mockLayout } from "@/test-utils";
import App from "./App";
import { createClient } from "@client";
import { STARTUP, CONFIG, INSTALL } from "@client/phase";
Expand All @@ -33,14 +33,15 @@ jest.mock('react-router-dom', () => ({
Outlet: mockComponent("Content"),
}));

jest.mock("@components/layout/Layout", () => mockLayout());

// Mock some components,
// See https://www.chakshunyu.com/blog/how-to-mock-a-react-component-in-jest/#default-export
jest.mock("@components/layout/DBusError", () => mockComponent("D-BusError Mock"));
jest.mock("@components/layout/LoadingEnvironment", () => mockComponent("LoadingEnvironment Mock"));
jest.mock("@components/questions/Questions", () => mockComponent("Questions Mock"));
jest.mock("@components/core/InstallationProgress", () => mockComponent("InstallationProgress Mock"));
jest.mock("@components/core/InstallationFinished", () => mockComponent("InstallationFinished Mock"));
jest.mock("@components/network/TargetIpsPopup", () => mockComponent("Target IPs Mock"));

const callbacks = {};
const getStatusFn = jest.fn();
Expand Down Expand Up @@ -177,10 +178,5 @@ describe("App", () => {
installerRender(<App />);
await screen.findByText("Content");
});

it("renders IP address and hostname", async () => {
installerRender(<App />);
await screen.findByText("Target IPs Mock");
});
});
});
34 changes: 34 additions & 0 deletions web/src/assets/styles/blocks.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,37 @@ section > .content {
.selection-list [data-state="unstyled"] {
border: 0;
}

.sidebar {
--color-background-primary: var(--color-primary);
--wrapper-background: var(--color-gray-light);

position: absolute;
padding: 0;
right: 0;
z-index: 1;
inline-size: 70%;
box-shadow: 0px 0px 20px 10px var(--color-primary-darkest);
}

.sidebar footer {
border-top: 1px solid var(--color-gray);
}

// Remove not wanted PatternFly padding left on a loading link
.sidebar button.pf-m-progress {
--pf-c-button--m-progress--PaddingLeft: var(--pf-global--spacer--md);
}
.sidebar button.pf-m-progress + div {
padding-inline-start: calc(var(--pf-global--spacer--md));
}

.sidebar[data-state="hidden"] {
transition: all 0.04s ease-in-out;
inline-size: 0;
box-shadow: none;
}

.sidebar[data-state="visible"] {
transition: all 0.2s ease-in-out;
}
7 changes: 7 additions & 0 deletions web/src/assets/styles/composition.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
margin-block-start: var(--stack-gutter);
}

.flex-stack {
display: flex;
flex-direction: column;
align-items: start;
@extend .stack;
}

.split {
display: flex;
align-items: center;
Expand Down
12 changes: 8 additions & 4 deletions web/src/assets/styles/layout.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.wrapper {
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-rows: var(--header-block-size) 1fr var(--footer-block-size);
grid-template-areas:
'header'
'content'
Expand All @@ -11,7 +11,7 @@
block-size: 100dvb;
max-inline-size: 1024px;
margin-inline: auto;
background: white;
background: var(--wrapper-background);

svg {
fill: currentColor;
Expand All @@ -20,15 +20,15 @@
}

.wrapper > * {
padding: var(--spacer-normal);
padding: var(--wrapper-padding);
}

.wrapper > header {
--color-button-plain-link: white;
--color-button-plain-link-hover: #fcfcfc;

grid-area: header;
background: var(--color-primary-darkest);
background: var(--color-background-primary);
color: var(--color-text-secondary);
}

Expand All @@ -46,3 +46,7 @@
.wrapper > footer > img {
max-inline-size: 150px;
}

[data-variant="flip-X"] {
transform: scaleX(-1);
}
7 changes: 7 additions & 0 deletions web/src/assets/styles/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@
--stack-gutter: var(--spacer-normal);
--split-gutter: var(--spacer-small);

--wrapper-padding: var(--spacer-normal);
--wrapper-background: white;

--color-primary: #30BA78;
--color-primary-darkest: #0C322C;
--color-gray-light: #FCFCFC;
--color-gray: #F2F2F2;
--color-gray-dark: #EFEFEF; // Fog
--color-gray-darker: #999999;
Expand Down Expand Up @@ -55,4 +59,7 @@
--gradient-border-end-color: transparent;

--icon-size-m: 32px;

--header-block-size: 6vh;
--footer-block-size: 8vh;
}
12 changes: 12 additions & 0 deletions web/src/client/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ class ManagerBaseClient {
return proxy.CanInstall();
}

/**
* Returns the binary content of the YaST logs file
*
* @return {Promise<Uint8Array>}
*/
async fetchLogs() {
const proxy = await this.client.proxy(MANAGER_IFACE);
const path = proxy.CollectLogs("root");
const file = cockpit.file(path, { binary: true });
return file.read();
}

/**
* Return the installer status
*
Expand Down
15 changes: 15 additions & 0 deletions web/src/client/manager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const managerProxy = {
Commit: jest.fn(),
Probe: jest.fn(),
CanInstall: jest.fn(),
CollectLogs: jest.fn(),
CurrentInstallationPhase: 0
};

Expand Down Expand Up @@ -148,3 +149,17 @@ describe("#canInstall", () => {
});
});
});

describe("#fetchLogs", () => {
beforeEach(() => {
managerProxy.CollectLogs = jest.fn(() => "/tmp/y2log-hWBn95.tar.xz");
cockpit.file = jest.fn(() => ({ read: () => "fake-binary-data" }));
});

it("returns the logs file binary content", async () => {
const client = new ManagerClient();
const logsContent = await client.fetchLogs();
expect(logsContent).toEqual("fake-binary-data");
expect(cockpit.file).toHaveBeenCalledWith("/tmp/y2log-hWBn95.tar.xz", { binary: true });
});
});
16 changes: 13 additions & 3 deletions web/src/components/core/About.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,28 @@
*/

import React, { useState } from "react";
import { noop } from "@/utils";
import { Button, Text } from "@patternfly/react-core";
import { Icon } from "@components/layout";
import { Popup } from "@components/core";

export default function About() {
export default function About({ onClickCallback = noop }) {
const [isOpen, setIsOpen] = useState(false);

const open = () => setIsOpen(true);
const open = () => {
setIsOpen(true);
onClickCallback();
};

const close = () => setIsOpen(false);

return (
<>
<Button variant="link" onClick={open}>
<Button
variant="link"
icon={<Icon name="help" size="24" />}
onClick={open}
>
About
</Button>

Expand Down
14 changes: 12 additions & 2 deletions web/src/components/core/About.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
import React from "react";

import { screen, waitFor, within } from "@testing-library/react";
import { installerRender } from "@/test-utils";
import { plainRender } from "@/test-utils";

import About from "./About";

describe("About", () => {
it("allows user to read 'About D-Installer'", async () => {
const { user } = installerRender(<About />);
const { user } = plainRender(<About />);

const button = screen.getByRole("button", { name: /About/i });
await user.click(button);
Expand All @@ -44,4 +44,14 @@ describe("About", () => {
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
});
});

it("triggers given onClickCallback function when opening the dialog", async () => {
const onClickCallback = jest.fn();

const { user } = plainRender(<About onClickCallback={onClickCallback} />);
const button = screen.getByRole("button", { name: /About/i });

await user.click(button);
expect(onClickCallback).toHaveBeenCalled();
});
});

0 comments on commit 66379c7

Please sign in to comment.