mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-12-20 17:58:29 +00:00
Add toggleable dark mode to errata
This commit is contained in:
parent
c0b97f5c85
commit
b6d94ecdc4
@ -51,6 +51,7 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
InputLeftElement,
|
InputLeftElement,
|
||||||
|
Link,
|
||||||
Select,
|
Select,
|
||||||
Spinner,
|
Spinner,
|
||||||
Stack,
|
Stack,
|
||||||
@ -80,13 +81,18 @@ import {
|
|||||||
} from 'bazel-bin/apollo/proto/v1/client_typescript/models';
|
} from 'bazel-bin/apollo/proto/v1/client_typescript/models';
|
||||||
import { reqap } from 'common/ui/reqap';
|
import { reqap } from 'common/ui/reqap';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../api';
|
import { api } from '../api';
|
||||||
import { COLOR_RESF_GREEN } from '../styles';
|
import { COLOR_RESF_GREEN } from '../styles';
|
||||||
|
|
||||||
export const Overview = () => {
|
export const Overview = () => {
|
||||||
const inputBackground = useColorModeValue('white', 'gray.800');
|
const inputBackground = useColorModeValue('white', undefined);
|
||||||
|
|
||||||
|
const tableBg = useColorModeValue('white', 'gray.800');
|
||||||
|
const pagerButtonScheme = useColorModeValue('blackAlpha', 'gray');
|
||||||
|
const linkBlue = useColorModeValue('blue.600', 'blue.300');
|
||||||
|
const linkPurple = useColorModeValue('purple.600', 'purple.300');
|
||||||
|
|
||||||
const [advisories, setAdvisories] = useState<V1Advisory[]>();
|
const [advisories, setAdvisories] = useState<V1Advisory[]>();
|
||||||
const [lastUpdated, setLastUpdated] = useState<Date>();
|
const [lastUpdated, setLastUpdated] = useState<Date>();
|
||||||
@ -340,7 +346,7 @@ export const Overview = () => {
|
|||||||
size="xs"
|
size="xs"
|
||||||
isAttached
|
isAttached
|
||||||
alignItems="stretch"
|
alignItems="stretch"
|
||||||
colorScheme="blackAlpha"
|
colorScheme={pagerButtonScheme}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="First Page"
|
aria-label="First Page"
|
||||||
@ -359,7 +365,7 @@ export const Overview = () => {
|
|||||||
// borderTop="1px solid"
|
// borderTop="1px solid"
|
||||||
// borderBottom="1px solid"
|
// borderBottom="1px solid"
|
||||||
borderColor="gray.200"
|
borderColor="gray.200"
|
||||||
backgroundColor="white"
|
backgroundColor={tableBg}
|
||||||
lineHeight="24px"
|
lineHeight="24px"
|
||||||
px={2}
|
px={2}
|
||||||
>
|
>
|
||||||
@ -401,9 +407,9 @@ export const Overview = () => {
|
|||||||
<AlertDescription>Failed to load errata</AlertDescription>
|
<AlertDescription>Failed to load errata</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
) : (
|
||||||
<Box backgroundColor="white" boxShadow="base">
|
<Box backgroundColor={tableBg} boxShadow="base">
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table size="sm">
|
<Table size="sm" variant="striped">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th {...stickyProps} width="36px" />
|
<Th {...stickyProps} width="36px" />
|
||||||
@ -424,37 +430,33 @@ export const Overview = () => {
|
|||||||
)}
|
)}
|
||||||
{advisories?.map((a, idx) => (
|
{advisories?.map((a, idx) => (
|
||||||
<Tr key={a.name}>
|
<Tr key={a.name}>
|
||||||
<Td
|
<Td textAlign="center" pr={0}>
|
||||||
backgroundColor={idx % 2 ? 'gray.50' : undefined}
|
|
||||||
textAlign="center"
|
|
||||||
pr={0}
|
|
||||||
>
|
|
||||||
{severityToBadge(a.severity, a.type)}
|
{severityToBadge(a.severity, a.type)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
|
<Td>
|
||||||
<Link
|
<Link
|
||||||
className="text-peridot-primary visited:text-purple-500"
|
as={RouterLink}
|
||||||
to={`/${a.name}`}
|
to={`/${a.name}`}
|
||||||
|
color={linkBlue}
|
||||||
|
_visited={{ color: linkPurple }}
|
||||||
>
|
>
|
||||||
{a.name}
|
{a.name}
|
||||||
</Link>
|
</Link>
|
||||||
</Td>
|
</Td>
|
||||||
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
|
<Td>
|
||||||
{a.synopsis?.replace(
|
{a.synopsis?.replace(
|
||||||
/^(Critical|Important|Moderate|Low): /,
|
/^(Critical|Important|Moderate|Low): /,
|
||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
|
<Td>
|
||||||
{typeToText(a.type)}
|
{typeToText(a.type)}
|
||||||
{a.type === V1AdvisoryType.Security
|
{a.type === V1AdvisoryType.Security
|
||||||
? ` / ${severityToText(a.severity)}`
|
? ` / ${severityToText(a.severity)}`
|
||||||
: ''}
|
: ''}
|
||||||
</Td>
|
</Td>
|
||||||
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
|
<Td>{a.affectedProducts?.join(', ')}</Td>
|
||||||
{a.affectedProducts?.join(', ')}
|
<Td>
|
||||||
</Td>
|
|
||||||
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
|
|
||||||
{Intl.DateTimeFormat(undefined, {
|
{Intl.DateTimeFormat(undefined, {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
|
@ -30,7 +30,17 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Box, HStack, Text, Link as ChakraLink } from '@chakra-ui/react';
|
import { MoonIcon, SunIcon } from '@chakra-ui/icons';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
HStack,
|
||||||
|
Text,
|
||||||
|
Link as ChakraLink,
|
||||||
|
useColorMode,
|
||||||
|
IconButton,
|
||||||
|
useColorModeValue,
|
||||||
|
DarkMode,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import { RESFLogo } from 'common/ui/RESFLogo';
|
import { RESFLogo } from 'common/ui/RESFLogo';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route, Switch } from 'react-router';
|
import { Route, Switch } from 'react-router';
|
||||||
@ -41,6 +51,11 @@ import { Overview } from './Overview';
|
|||||||
import { ShowErrata } from './ShowErrata';
|
import { ShowErrata } from './ShowErrata';
|
||||||
|
|
||||||
export const Root = () => {
|
export const Root = () => {
|
||||||
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
|
|
||||||
|
const SwitchIcon = useColorModeValue(MoonIcon, SunIcon);
|
||||||
|
const bodyBg = useColorModeValue('gray.100', 'gray.900');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
@ -55,6 +70,7 @@ export const Root = () => {
|
|||||||
display="flex"
|
display="flex"
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
|
justifyContent="space-between"
|
||||||
py="1"
|
py="1"
|
||||||
px={4}
|
px={4}
|
||||||
>
|
>
|
||||||
@ -75,8 +91,20 @@ export const Root = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
</Link>
|
</Link>
|
||||||
|
<DarkMode>
|
||||||
|
<IconButton
|
||||||
|
size="md"
|
||||||
|
fontSize="lg"
|
||||||
|
aria-label={`Switch to ${
|
||||||
|
colorMode === 'light' ? 'dark' : 'light'
|
||||||
|
} mode`}
|
||||||
|
variant="ghost"
|
||||||
|
onClick={toggleColorMode}
|
||||||
|
icon={<SwitchIcon />}
|
||||||
|
/>
|
||||||
|
</DarkMode>
|
||||||
</Box>
|
</Box>
|
||||||
<Box as="main" flexGrow={1} overflow="auto">
|
<Box as="main" flexGrow={1} overflow="auto" background={bodyBg}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/" exact component={Overview} />
|
<Route path="/" exact component={Overview} />
|
||||||
<Route path="/:id" component={ShowErrata} />
|
<Route path="/:id" component={ShowErrata} />
|
||||||
|
@ -51,6 +51,7 @@ import {
|
|||||||
Tabs,
|
Tabs,
|
||||||
Text,
|
Text,
|
||||||
UnorderedList,
|
UnorderedList,
|
||||||
|
useColorModeValue,
|
||||||
VStack,
|
VStack,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
@ -68,7 +69,7 @@ import { RouteComponentProps } from 'react-router';
|
|||||||
import { Link as RouterLink } from 'react-router-dom';
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../api';
|
import { api } from '../api';
|
||||||
import { COLOR_RESF_BLUE, COLOR_RESF_GREEN } from '../styles';
|
import { COLOR_RESF_GREEN } from '../styles';
|
||||||
|
|
||||||
interface ShowErrataParams {
|
interface ShowErrataParams {
|
||||||
id: string;
|
id: string;
|
||||||
@ -80,6 +81,11 @@ export interface ShowErrataProps
|
|||||||
export const ShowErrata = (props: ShowErrataProps) => {
|
export const ShowErrata = (props: ShowErrataProps) => {
|
||||||
const id = props.match.params.id;
|
const id = props.match.params.id;
|
||||||
|
|
||||||
|
const cardBg = useColorModeValue('white', 'gray.800');
|
||||||
|
const sideBg = useColorModeValue('gray.100', 'gray.700');
|
||||||
|
const linkBlue = useColorModeValue('blue.600', 'blue.300');
|
||||||
|
const linkPurple = useColorModeValue('purple.600', 'purple.300');
|
||||||
|
|
||||||
const [errata, setErrata] = useState<V1Advisory>();
|
const [errata, setErrata] = useState<V1Advisory>();
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isError, setIsError] = useState(false);
|
const [isError, setIsError] = useState(false);
|
||||||
@ -152,7 +158,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
|
|||||||
<>
|
<>
|
||||||
<HStack
|
<HStack
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
backgroundColor="white"
|
backgroundColor={cardBg}
|
||||||
py="2"
|
py="2"
|
||||||
px="4"
|
px="4"
|
||||||
spacing="6"
|
spacing="6"
|
||||||
@ -168,7 +174,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
|
|||||||
<Text fontSize="sm">{errata.synopsis}</Text>
|
<Text fontSize="sm">{errata.synopsis}</Text>
|
||||||
</VStack>
|
</VStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<Tabs backgroundColor="white" p="2">
|
<Tabs backgroundColor={cardBg} p="2">
|
||||||
<TabList>
|
<TabList>
|
||||||
<Tab>Erratum</Tab>
|
<Tab>Erratum</Tab>
|
||||||
<Tab>Affected Packages</Tab>
|
<Tab>Affected Packages</Tab>
|
||||||
@ -238,7 +244,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
|
|||||||
minWidth="300px"
|
minWidth="300px"
|
||||||
spacing="5"
|
spacing="5"
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
backgroundColor="gray.100"
|
backgroundColor={sideBg}
|
||||||
>
|
>
|
||||||
<Text>
|
<Text>
|
||||||
<b>Issued:</b> {errata.publishedAt?.toLocaleDateString()}
|
<b>Issued:</b> {errata.publishedAt?.toLocaleDateString()}
|
||||||
@ -270,7 +276,10 @@ export const ShowErrata = (props: ShowErrataProps) => {
|
|||||||
<Link
|
<Link
|
||||||
href={x.sourceLink}
|
href={x.sourceLink}
|
||||||
isExternal
|
isExternal
|
||||||
color={COLOR_RESF_BLUE}
|
color={linkBlue}
|
||||||
|
_visited={{
|
||||||
|
color: linkPurple,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{x.sourceBy} - {x.ticket}
|
{x.sourceBy} - {x.ticket}
|
||||||
</Link>
|
</Link>
|
||||||
@ -295,7 +304,10 @@ export const ShowErrata = (props: ShowErrataProps) => {
|
|||||||
<Link
|
<Link
|
||||||
href={x.sourceLink}
|
href={x.sourceLink}
|
||||||
isExternal
|
isExternal
|
||||||
color={COLOR_RESF_BLUE}
|
color={linkBlue}
|
||||||
|
_visited={{
|
||||||
|
color: linkPurple,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -32,20 +32,24 @@
|
|||||||
|
|
||||||
import 'tailwind/tailwind.css';
|
import 'tailwind/tailwind.css';
|
||||||
|
|
||||||
import { ChakraProvider } from '@chakra-ui/react';
|
import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import { Root } from './components/Root';
|
import { Root } from './components/Root';
|
||||||
|
import theme from './theme';
|
||||||
|
|
||||||
export const app = () => {
|
export const app = () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<BrowserRouter>
|
<>
|
||||||
<ChakraProvider>
|
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
|
||||||
<Root />
|
<BrowserRouter>
|
||||||
</ChakraProvider>
|
<ChakraProvider theme={theme}>
|
||||||
</BrowserRouter>,
|
<Root />
|
||||||
|
</ChakraProvider>
|
||||||
|
</BrowserRouter>
|
||||||
|
</>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
41
apollo/ui/src/theme.ts
Normal file
41
apollo/ui/src/theme.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) All respective contributors to the Peridot Project. All rights reserved.
|
||||||
|
* Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved.
|
||||||
|
* Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { extendTheme, type ThemeConfig } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
const config: ThemeConfig = {
|
||||||
|
initialColorMode: 'system',
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = extendTheme({ config });
|
||||||
|
|
||||||
|
export default theme;
|
Loading…
Reference in New Issue
Block a user