Cb 3963 migrate core view to css modules (#2192)

* CB-3963 error message reshadow refactor

* CB-3963 remove extra reshadow use from ItemListSearch

* CB-3963 remove reshadow from TopAppBar

* CB-3963 remove unused LoadingScreen component

* CB-3963 removed reshadow from VersionUpdate

* CB-3963 removed reshadow from VersionSelector

* CB-3963 removed reshadow from renderLayout

* CB-3963 removed reshadow from AuthenticationProvider

* CB-3963 removed reshadow from VersionInfo

* CB-3963 removed reshadow from TableItemSelect

* CB-3963 removed reshadow from CaptureView

* CB-3963 removed reshadow from ConnectionList

* CB-3963 removed reshadow from WizzardStepper

* CB-3963 removed reshadow from ConfigurationWizardTittle

* Revert "CB-3963 removed reshadow from AuthenticationProvider"

This reverts commit d5828c2689.

* CB.3963 fix checkboxes margin in table items

---------

Co-authored-by: s.teleshev <s.teleshev@mu.se>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
sergeyteleshev
2023-12-13 10:45:31 +03:00
committed by GitHub
co-authored by s.teleshev mr-anton-t
parent e9081598e3
commit 9a69f4e660
26 changed files with 226 additions and 321 deletions
@@ -0,0 +1,30 @@
.message {
box-sizing: border-box;
display: flex;
align-items: center;
border-radius: var(--theme-group-element-radius);
height: 50px;
padding: 8px 12px;
}
.errorIcon {
width: 24px;
height: 24px;
margin-right: 8px;
}
.messageBody {
composes: theme-typography--body2 from global;
max-height: 100%;
line-height: 1.2;
box-sizing: border-box;
flex: 1;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
.messageActions {
margin-left: 16px;
}
@@ -6,43 +6,13 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button } from './Button';
import { IconOrImage } from './IconOrImage';
import { useTranslate } from './localization/useTranslate';
import { useS } from './useS';
const styles = css`
message {
box-sizing: border-box;
display: flex;
align-items: center;
border-radius: var(--theme-group-element-radius);
height: 50px;
padding: 8px 12px;
}
IconOrImage {
width: 24px;
height: 24px;
margin-right: 8px;
}
message-body {
composes: theme-typography--body2 from global;
max-height: 100%;
line-height: 1.2;
box-sizing: border-box;
flex: 1;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
message-actions {
margin-left: 16px;
}
`;
import styles from './ErrorMessage.m.css';
import { s } from './s';
interface Props {
hasDetails?: boolean;
@@ -53,18 +23,19 @@ interface Props {
export const ErrorMessage = observer<Props>(function ErrorMessage({ text, className, hasDetails, onShowDetails }) {
const translate = useTranslate();
const style = useS(styles);
return styled(styles)(
<message className={className}>
<IconOrImage icon="/icons/error_icon_sm.svg" />
<message-body title={text}>{text}</message-body>
<message-actions>
return (
<div className={s(style, { message: true }, className)}>
<IconOrImage className={s(style, { errorIcon: true })} icon="/icons/error_icon_sm.svg" />
<div className={s(style, { messageBody: true })} title={text}>{text}</div>
<div className={s(style, { messageActions: true })}>
{hasDetails && (
<Button type="button" mod={['outlined']} onClick={onShowDetails}>
{translate('ui_errors_details')}
</Button>
)}
</message-actions>
</message>,
</div>
</div>
);
});
@@ -6,7 +6,6 @@
* you may not use this file except in compliance with the License.
*/
import { useCallback, useRef, useState } from 'react';
import { use } from 'reshadow';
import { IconButton } from '../IconButton';
import { useTranslate } from '../localization/useTranslate';
@@ -67,7 +66,6 @@ export const ItemListSearch: React.FC<IProps> = function ItemListSearch({ value,
autoComplete="off"
disabled={disabled}
onChange={event => changeHandler(event.target.value)}
{...use({ mod: 'surface' })}
/>
<div className={s(styles, { actionButton: true })}>
{!onSearch && inputValue ? (
@@ -1,34 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2023 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useEffect, useRef } from 'react';
import styled from 'reshadow';
import { Icon } from '../Icon';
import styles from './loading-screen.css';
const FADE_IN_DELAY = 300;
function LoadingScreen() {
const ref = useRef<HTMLDivElement>(null);
useEffect(
() => () => {
const appContainer = document.querySelector('#__next')!;
const loadingNode = appContainer.appendChild(ref.current!.cloneNode(true));
setTimeout(() => (loadingNode as any).classList.add(styles.fadeIn));
setTimeout(() => appContainer.removeChild(loadingNode), FADE_IN_DELAY);
},
[],
);
return styled(styles)(
<div ref={ref}>
<Icon name="logo" viewBox="0 0 1755.6533 681.13202" />
</div>,
);
}
@@ -1,56 +0,0 @@
:global(html) {
font-family: 'Roboto', sans-serif;
}
div {
display: flex;
position: absolute;
background-color: #ffffff;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.fadeIn {
transition: opacity 0.3s ease;
opacity: 0;
animation: none;
}
Icon {
position: relative;
width: 100%;
margin: auto;
max-width: 600px;
}
div::before {
content: ' ';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 50%;
z-index: 1;
width: 500%;
margin-left: -250%;
animation: wave 1.3s linear infinite;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0) 46%,
rgba(255, 255, 255, 0.35) 50%,
rgba(255, 255, 255, 0) 54%
)
50% 50%;
}
@keyframes wave {
0% {
transform: translate3d(-30%, 0, 0);
}
100% {
transform: translate3d(30%, 0, 0);
}
}
@@ -6,7 +6,6 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Icon } from '../Icon';
import { s } from '../s';
@@ -0,0 +1,4 @@
.checkbox {
margin-left: -10px;
margin-right: -10px;
}
@@ -7,7 +7,6 @@
*/
import { observer } from 'mobx-react-lite';
import { useContext } from 'react';
import styled, { css } from 'reshadow';
import { EventContext } from '@cloudbeaver/core-events';
@@ -15,6 +14,9 @@ import { Checkbox } from '../FormControls/Checkboxes/Checkbox';
import { EventTableItemSelectionFlag } from './EventTableItemSelectionFlag';
import { TableContext } from './TableContext';
import { TableItemContext } from './TableItemContext';
import { useS } from '../useS';
import styles from './TableItemSelect.m.css';
import { s } from '../s';
interface Props {
checked?: boolean;
@@ -23,17 +25,11 @@ interface Props {
className?: string;
}
const styles = css`
Checkbox {
margin-left: -10px;
margin-right: -10px;
}
`;
export const TableItemSelect = observer<Props>(function TableItemSelect({ checked, disabled, tooltip, className }) {
const tableContext = useContext(TableContext);
const context = useContext(TableItemContext);
const selected = checked ?? context?.isSelected();
const style = useS(styles);
function handleClick(event: React.MouseEvent<HTMLInputElement>) {
if (!context) {
@@ -48,7 +44,13 @@ export const TableItemSelect = observer<Props>(function TableItemSelect({ checke
return null;
}
return styled(styles)(
<Checkbox className={className} title={tooltip} disabled={context.selectDisabled || disabled} checked={selected} onClick={handleClick} />,
return (
<Checkbox
className={s(style, { checkbox: true }, className)}
title={tooltip}
disabled={context.selectDisabled || disabled}
checked={selected}
onClick={handleClick}
/>
);
});
@@ -0,0 +1,10 @@
.header {
composes: theme-text-on-primary theme-typography--body2 from global;
display: flex;
align-items: center;
height: 48px;
padding: 0 8px;
background-color: #2a7cb4;
z-index: 1;
flex-shrink: 0;
}
@@ -5,25 +5,17 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
export const topAppBarStyles = css`
header {
composes: theme-text-on-primary theme-typography--body2 from global;
display: flex;
align-items: center;
height: 48px;
padding: 0 8px;
background-color: #2a7cb4;
z-index: 1;
flex-shrink: 0;
}
`;
import { s } from '../s';
import { useS } from '../useS';
import styles from './TopAppBar.m.css';
interface Props extends React.PropsWithChildren {
className?: string;
}
export const TopAppBar: React.FC<Props> = function TopAppBar({ children, className }) {
return styled(topAppBarStyles)(<header className={className}>{children}</header>);
const style = useS(styles);
return (<header className={s(style, { header: true }, className)}>{children}</header>);
};
@@ -0,0 +1,3 @@
.loader {
height: 100vh;
}
@@ -7,11 +7,11 @@
*/
import { Suspense } from 'react';
import { createRoot, Root } from 'react-dom/client';
import styled from 'reshadow';
import { Body } from '@cloudbeaver/core-app';
import { DisplayError, ErrorBoundary, Loader } from '@cloudbeaver/core-blocks';
import { DisplayError, ErrorBoundary, Loader, s } from '@cloudbeaver/core-blocks';
import { AppContext, IServiceInjector } from '@cloudbeaver/core-di';
import styles from './renderLayout.m.css';
interface IRender {
initRoot(): Root;
@@ -46,18 +46,14 @@ export function renderLayout(serviceInjector: IServiceInjector): IRender {
},
renderApp() {
this.initRoot().render(
styled`
Loader {
height: 100vh;
}
`(
(
<AppContext app={serviceInjector}>
<ErrorBoundary root>
<Suspense fallback={<Loader />}>
<Suspense fallback={<Loader className={s(styles, { loader: true })} />}>
<Body />
</Suspense>
</ErrorBoundary>
</AppContext>,
</AppContext>
),
);
},
@@ -0,0 +1,3 @@
.container {
outline: none;
}
@@ -8,9 +8,7 @@
import { observer } from 'mobx-react-lite';
import { useContext } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import styled, { css } from 'reshadow';
import { useFocus } from '@cloudbeaver/core-blocks';
import { s, useFocus, useS } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { isObjectsEqual } from '@cloudbeaver/core-utils';
@@ -22,12 +20,7 @@ import type { IView } from './IView';
import { parseHotkey } from './parseHotkey';
import { useActiveView } from './useActiveView';
import { useViewContext } from './useViewContext';
const styles = css`
div {
outline: none;
}
`;
import styles from './CaptureView.m.css';
interface Props {
view: IView<any>;
@@ -40,6 +33,7 @@ export const CaptureView = observer<React.PropsWithChildren<Props>>(function Cap
const actionService = useService(ActionService);
const activeView = useActiveView(view);
const [ref, state] = useFocus<HTMLDivElement>({ onFocus: activeView.focusView, onBlur: activeView.blurView });
const style = useS(styles);
const actionItems = view.actions
.map(action => actionService.getAction(viewContext, action))
@@ -85,11 +79,11 @@ export const CaptureView = observer<React.PropsWithChildren<Props>>(function Cap
},
);
return styled(styles)(
return (
<CaptureViewContext.Provider value={viewContext}>
<div ref={ref} className={className} tabIndex={0}>
<div ref={ref} className={s(style, { container: true }, className)} tabIndex={0}>
{children}
</div>
</CaptureViewContext.Provider>,
</CaptureViewContext.Provider>
);
});
@@ -0,0 +1,30 @@
.wizardStepper {
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
position: sticky;
top: 0;
height: 48px;
display: flex;
padding: 0 16px;
align-items: center;
border-bottom: solid 2px;
z-index: 1;
flex-shrink: 0;
}
.actions {
composes: theme-border-color-background from global;
border-right: solid 1px;
display: flex;
gap: 16px;
}
.actions,
.wizardText {
display: flex;
align-items: center;
height: 28px;
}
.wizardText {
padding: 0 16px;
}
@@ -6,60 +6,28 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { ConfigurationWizardService } from '@cloudbeaver/core-administration';
import { Button, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
const styles = css`
wizard-stepper {
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
position: sticky;
top: 0;
height: 48px;
display: flex;
padding: 0 16px;
align-items: center;
border-bottom: solid 2px;
z-index: 1;
flex-shrink: 0;
}
actions {
composes: theme-border-color-background from global;
border-right: solid 1px;
display: flex;
gap: 16px;
}
actions,
wizard-text {
display: flex;
align-items: center;
height: 28px;
}
wizard-text {
padding: 0 16px;
}
`;
import styles from './WizardStepper.m.css';
export const WizardStepper = observer(function WizardStepper() {
const service = useService(ConfigurationWizardService);
const translate = useTranslate();
const style = useS(styles);
return styled(useStyles(styles))(
<wizard-stepper>
<actions>
return (
<div className={s(style, { wizardStepper: true })}>
<div className={s(style, { actions: true })}>
<Button type="button" mod={['outlined']} disabled={service.currentStepIndex === 0} onClick={() => service.back()}>
{translate('ui_stepper_back')}
</Button>
<Button type="button" mod={['unelevated']} onClick={() => service.next()}>
{translate(service.currentStepIndex === service.steps.length - 1 ? 'ui_stepper_finish' : 'ui_stepper_next')}
</Button>
</actions>
<wizard-text>{translate(service.currentStep?.configurationWizardOptions?.description || '')}</wizard-text>
</wizard-stepper>,
</div>
<div className={s(style, { wizardText: true })}>{translate(service.currentStep?.configurationWizardOptions?.description || '')}</div>
</div>
);
});
@@ -0,0 +1,4 @@
.wizardTitle {
text-transform: uppercase;
font-weight: 700;
}
@@ -5,21 +5,14 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
import { Translate } from '@cloudbeaver/core-blocks';
const styles = css`
wizard-title {
text-transform: uppercase;
font-weight: 700;
}
`;
import { Translate, s, useS } from '@cloudbeaver/core-blocks';
import styles from './ConfigurationWizardTitle.m.css';
export function ConfigurationWizardTitle() {
return styled(styles)(
<wizard-title as="div">
const style = useS(styles);
return (
<div className={s(style, { wizardTitle : true })}>
<Translate token="administration_configuration_wizard_title" />
</wizard-title>,
</div>
);
}
@@ -0,0 +1,28 @@
.group {
position: relative;
}
.group,
.container,
.tableContainer {
height: 100%;
}
.container {
display: flex;
flex-direction: column;
width: 100%;
}
.tableContainer {
overflow: auto;
}
.grantedConnectionsTableHeader {
flex: 0 0 auto;
}
.table {
composes: theme-background-surface theme-text-on-surface from global;
width: 100%;
}
@@ -8,19 +8,19 @@
import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import { useCallback, useState } from 'react';
import styled, { css } from 'reshadow';
import {
Button,
getComputed,
getSelectedItems,
Group,
s,
Table,
TableBody,
TableColumnValue,
TableItem,
useObjectRef,
useStyles,
useS,
useTranslate,
} from '@cloudbeaver/core-blocks';
import { Connection, DBDriverResource } from '@cloudbeaver/core-connections';
@@ -30,32 +30,7 @@ import { getFilteredConnections } from './getFilteredConnections';
import { GrantedConnectionsTableHeader, IFilterState } from './GrantedConnectionsTableHeader/GrantedConnectionsTableHeader';
import { GrantedConnectionsTableInnerHeader } from './GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader';
import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem';
const styles = css`
Group {
position: relative;
}
Group,
container,
table-container {
height: 100%;
}
container {
display: flex;
flex-direction: column;
width: 100%;
}
table-container {
overflow: auto;
}
GrantedConnectionsTableHeader {
flex: 0 0 auto;
}
Table {
composes: theme-background-surface theme-text-on-surface from global;
width: 100%;
}
`;
import styles from './ConnectionList.m.css';
interface Props {
connectionList: Connection[];
@@ -66,7 +41,7 @@ interface Props {
export const ConnectionList = observer<Props>(function ConnectionList({ connectionList, grantedSubjects, disabled, onGrant }) {
const props = useObjectRef({ onGrant });
const style = useStyles(styles);
const style = useS(styles);
const translate = useTranslate();
const driversResource = useService(DBDriverResource);
@@ -84,17 +59,17 @@ export const ConnectionList = observer<Props>(function ConnectionList({ connecti
const connections = getFilteredConnections(connectionList, filterState.filterValue);
const keys = connections.map(connection => connection.id);
return styled(style)(
<Group box medium overflow>
<container>
return (
<Group className={s(style, { group: true })} box medium overflow>
<div className={s(style, { container: true })}>
<GrantedConnectionsTableHeader filterState={filterState} disabled={disabled}>
<Button disabled={disabled || !selected} mod={['unelevated']} onClick={grant}>
{translate('ui_add')}
</Button>
</GrantedConnectionsTableHeader>
<table-container>
<Table keys={keys} selectedItems={selectedSubjects} isItemSelectable={item => !grantedSubjects.includes(item)} size="big">
<GrantedConnectionsTableInnerHeader disabled={disabled} />
<div className={s(style, { tableContainer: true })}>
<Table className={s(style, { table: true })} keys={keys} selectedItems={selectedSubjects} isItemSelectable={item => !grantedSubjects.includes(item)} size="big">
<GrantedConnectionsTableInnerHeader className={s(style, { grantedConnectionsTableHeader: true })} disabled={disabled} />
<TableBody>
{!connections.length && filterState.filterValue && (
<TableItem item="tableInfo" selectDisabled>
@@ -117,8 +92,8 @@ export const ConnectionList = observer<Props>(function ConnectionList({ connecti
})}
</TableBody>
</Table>
</table-container>
</container>
</Group>,
</div>
</div>
</Group>
);
});
@@ -0,0 +1,10 @@
.group {
list-style-position: inside;
height: 100%;
max-height: 300px;
}
.reactMarkdown > * {
margin: 0;
padding: 0;
}
@@ -7,44 +7,32 @@
*/
import { observer } from 'mobx-react-lite';
import ReactMarkdown from 'react-markdown';
import styled, { css } from 'reshadow';
import { Container, Group, GroupItem, GroupTitle, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Container, Group, GroupItem, GroupTitle, s, useResource, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { VersionResource } from '@cloudbeaver/core-version';
import styles from './VersionInfo.m.css';
interface Props {
item: string;
}
const style = css`
Group {
list-style-position: inside;
height: 100%;
max-height: 300px;
}
ReactMarkdown > * {
margin: 0;
padding: 0;
}
`;
export const VersionInfo = observer<Props>(function VersionInfo({ item }) {
const translate = useTranslate();
const styles = useStyles(style);
const style = useS(styles);
const versionResource = useResource(VersionInfo, VersionResource, item);
const version = versionResource.tryGetData;
return styled(styles)(
return (
<Container wrap gap overflow large>
<Group gap overflow>
<Group className={s(style, { group: true })} gap overflow>
<GroupTitle>{version ? `Release notes ${version.number} - ${version.date}` : translate('version_update_version_no_info')}</GroupTitle>
{version && (
<GroupItem>
<ReactMarkdown>{version.releaseNotes}</ReactMarkdown>
<ReactMarkdown className={s(style, { reactMarkdown: true })}>{version.releaseNotes}</ReactMarkdown>
</GroupItem>
)}
</Group>
</Container>,
</Container>
);
});
@@ -0,0 +1,11 @@
.group {
list-style-position: inside;
}
.instruction {
white-space: pre-line;
}
.h4 {
margin: 0;
}
@@ -7,37 +7,26 @@
*/
import { observer } from 'mobx-react-lite';
import { useEffect, useState } from 'react';
import styled, { css } from 'reshadow';
import { Combobox, Container, Group, GroupItem, GroupTitle, useTranslate } from '@cloudbeaver/core-blocks';
import { Combobox, Container, Group, GroupItem, GroupTitle, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { ServerConfigResource } from '@cloudbeaver/core-root';
import { IVersion, VersionResource } from '@cloudbeaver/core-version';
import { VersionUpdateService } from '@cloudbeaver/core-version-update';
import { VersionInfo } from './VersionInfo';
import styles from './VersionSelector.m.css';
interface Props {
versions: IVersion[];
}
const style = css`
Group {
list-style-position: inside;
}
Instruction {
white-space: pre-line;
}
h4 {
margin: 0;
}
`;
export const VersionSelector = observer<Props>(function VersionSelector({ versions }) {
const versionUpdateService = useService(VersionUpdateService);
const versionResource = useService(VersionResource);
const serverConfigResource = useService(ServerConfigResource);
const translate = useTranslate();
const style = useS(styles);
const [selected, setSelected] = useState('');
@@ -50,9 +39,9 @@ export const VersionSelector = observer<Props>(function VersionSelector({ versio
const version = versions.find(v => v.number === selected);
const Instruction = versionUpdateService.versionInstructionGetter?.();
return styled(style)(
return (
<Container gap>
<Group gap large>
<Group className={s(style, { group: true })} gap large>
<Combobox
items={versions}
keySelector={value => value.number}
@@ -65,15 +54,15 @@ export const VersionSelector = observer<Props>(function VersionSelector({ versio
</Combobox>
{version && Instruction && (
<GroupItem>
<Instruction version={version} containerId={serverConfigResource.data?.containerId} />
<Instruction className={s(style, { instruction: true })} version={version} containerId={serverConfigResource.data?.containerId} />
</GroupItem>
)}
<GroupTitle>{translate('plugin_version_update_administration_recommendations_label')}</GroupTitle>
<GroupItem>
<h4>{translate('plugin_version_update_administration_recommendations')}</h4>
<h4 className={s(style, { h4: true })}>{translate('plugin_version_update_administration_recommendations')}</h4>
</GroupItem>
</Group>
{version && <VersionInfo item={version.number} />}
</Container>,
</Container>
);
});
@@ -0,0 +1,4 @@
.coloredContainer {
composes: theme-typography--body2 from global;
list-style-position: inside;
}
@@ -6,11 +6,10 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { gte } from 'semver';
import type { AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
import { ColoredContainer, useResource, useStyles } from '@cloudbeaver/core-blocks';
import { ColoredContainer, s, useResource, useS, useStyles } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
import { VersionResource, VersionService } from '@cloudbeaver/core-version';
@@ -18,16 +17,10 @@ import { VersionUpdateService } from '@cloudbeaver/core-version-update';
import { VersionChecker } from './VersionChecker';
import { VersionSelector } from './VersionSelector';
const styles = css`
ColoredContainer {
composes: theme-typography--body2 from global;
list-style-position: inside;
}
`;
import styles from './VersionUpdate.m.css';
export const VersionUpdate: AdministrationItemContentComponent = observer(function VersionUpdate() {
const style = useStyles(styles);
const style = useS(styles);
const versionService = useService(VersionService);
const versionUpdateService = useService(VersionUpdateService);
const versionResource = useResource(VersionUpdate, VersionResource, CachedMapAllKey, {
@@ -37,8 +30,8 @@ export const VersionUpdate: AdministrationItemContentComponent = observer(functi
const GeneralInstructions = versionUpdateService.generalInstructionsGetter?.();
const versions = versionResource.resource.values.filter(v => gte(v.number, versionService.current));
return styled(style)(
<ColoredContainer wrap gap overflow parent>
return (
<ColoredContainer className={s(style, { coloredContainer: true })} wrap gap overflow parent>
<VersionChecker />
{versions.length > 0 && (
<>
@@ -46,6 +39,6 @@ export const VersionUpdate: AdministrationItemContentComponent = observer(functi
<VersionSelector versions={versions} />
</>
)}
</ColoredContainer>,
</ColoredContainer>
);
});