Skip to content

Commit

Permalink
feat(web): show issues on their related section
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Jun 11, 2024
1 parent 68f99e8 commit fee2c63
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 6 deletions.
4 changes: 2 additions & 2 deletions web/src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import { HTTPClient } from "./http";
* @typedef {(issues: Issues) => void} IssuesHandler
*/

const createIssuesList = (product, software, storage, users) => {
const createIssuesList = (product = [], software = [], storage = [], users = []) => {
const list = { product, storage, software, users };
list.isEmpty = !Object.values(list).some(v => v.length > 0);
return list;
Expand Down Expand Up @@ -155,4 +155,4 @@ const createDefaultClient = async () => {
return createClient(httpUrl);
};

export { createClient, createDefaultClient, phase };
export { createClient, createDefaultClient, phase, createIssuesList };
43 changes: 43 additions & 0 deletions web/src/components/core/IssuesHint.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) [2023] SUSE LLC
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, contact SUSE LLC.
*
* To contact SUSE LLC about this file by physical or electronic mail, you may
* find current contact information at www.suse.com.
*/

import React from "react";
import { Hint, HintBody, List, ListItem, Stack } from "@patternfly/react-core";
import { _ } from "~/i18n";

export default function IssuesHint({ issues }) {
if (issues === undefined || issues.length === 0) return;

return (
<Hint>
<HintBody>
<Stack hasGutter>
<p>
{_("Please, pay attention to the following tasks:")}
</p>
<List>
{issues.map((i, idx) => <ListItem key={idx}>{i.description}</ListItem>)}
</List>
</Stack>
</HintBody>
</Hint>
);
}
35 changes: 35 additions & 0 deletions web/src/components/core/IssuesHint.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) [2022-2023] SUSE LLC
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, contact SUSE LLC.
*
* To contact SUSE LLC about this file by physical or electronic mail, you may
* find current contact information at www.suse.com.
*/

import React from "react";
import { screen } from "@testing-library/react";
import { plainRender } from "~/test-utils";
import { IssuesHint } from "~/components/core";

it("renders a list of issues", () => {
const issue = {
description: "You need to create a user",
source: "config",
severity: "error"
};
plainRender(<IssuesHint issues={[issue]} />);
expect(screen.getByText(issue.description)).toBeInTheDocument();
});
1 change: 1 addition & 0 deletions web/src/components/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export { default as InstallationFinished } from "./InstallationFinished";
export { default as InstallationProgress } from "./InstallationProgress";
export { default as InstallButton } from "./InstallButton";
export { default as IssuesDialog } from "./IssuesDialog";
export { default as IssuesHint } from "./IssuesHint";
export { default as SectionSkeleton } from "./SectionSkeleton";
export { default as ListSearch } from "./ListSearch";
export { default as LoginPage } from "./LoginPage";
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/overview/OverviewPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default function OverviewPage() {
</CardField>
</GridItem>
<GridItem sm={12} xl={6}>
<CardField label="Installation">
<CardField>
<CardBody>
<Stack hasGutter>
{issues.isEmpty ? <ReadyForInstallation /> : <IssuesList issues={issues} />}
Expand Down
10 changes: 8 additions & 2 deletions web/src/components/users/UsersPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
import React from "react";

import { _ } from "~/i18n";
import { CardField, Page } from "~/components/core";
import { CardField, IssuesHint, Page } from "~/components/core";
import { FirstUser, RootAuthMethods } from "~/components/users";
import { Card, CardBody, Grid, GridItem, Stack } from "@patternfly/react-core";
import { CardBody, Grid, GridItem, Stack } from "@patternfly/react-core";
import { useIssues } from "~/context/issues";

export default function UsersPage() {
const { users: issues } = useIssues();

return (
<>
<Page.Header>
Expand All @@ -35,6 +38,9 @@ export default function UsersPage() {

<Page.MainContent>
<Grid hasGutter>
<GridItem sm={12}>
<IssuesHint issues={issues} />
</GridItem>
<GridItem sm={12} xl={6}>
<CardField label={_("First user")}>
<CardBody>
Expand Down
5 changes: 4 additions & 1 deletion web/src/context/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { InstallerClientProvider } from "./installer";
import { InstallerL10nProvider } from "./installerL10n";
import { L10nProvider } from "./l10n";
import { ProductProvider } from "./product";
import { IssuesProvider } from "./issues";

/**
* Combines all application providers.
Expand All @@ -39,7 +40,9 @@ function AppProviders({ children }) {
<InstallerL10nProvider>
<L10nProvider>
<ProductProvider>
{children}
<IssuesProvider>
{children}
</IssuesProvider>
</ProductProvider>
</L10nProvider>
</InstallerL10nProvider>
Expand Down
70 changes: 70 additions & 0 deletions web/src/context/issues.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) [2024] SUSE LLC
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, contact SUSE LLC.
*
* To contact SUSE LLC about this file by physical or electronic mail, you may
* find current contact information at www.suse.com.
*/

import React, { useContext, useEffect, useState } from "react";
import { useCancellablePromise } from "~/utils";
import { useInstallerClient } from "./installer";
import { createIssuesList } from "~/client";

/**
* @typedef {import ("~/client").Issues} Issues list
*/

const IssuesContext = React.createContext({});

function IssuesProvider({ children }) {
const [issues, setIssues] = useState(createIssuesList());
const { cancellablePromise } = useCancellablePromise();
const client = useInstallerClient();

useEffect(() => {
const loadIssues = async () => {
const issues = await cancellablePromise(client.issues());
setIssues(issues);
};

if (client) {
loadIssues();
}
}, [client, cancellablePromise, setIssues]);

useEffect(() => {
if (!client) return;

return client.onIssuesChange((updated) => {
setIssues({ ...issues, ...updated });
});
}, [client, issues, setIssues]);

return <IssuesContext.Provider value={issues}>{children}</IssuesContext.Provider>;
}

function useIssues() {
const context = useContext(IssuesContext);

if (!context) {
throw new Error("useIssues must be used within an IssuesProvider");
}

return context;
}

export { IssuesProvider, useIssues };

0 comments on commit fee2c63

Please sign in to comment.