feat(core-administration): configuration wizard pages API

CB-243
This commit is contained in:
Wroud
2020-08-26 20:01:08 +03:00
parent fc53f3ba5d
commit 534edcd620
12 changed files with 223 additions and 41 deletions
@@ -66,6 +66,7 @@ const administrationStyles = composes(
);
type Props = {
configurationWizard: boolean;
activeItem: string | null;
activeItemSub: string | null;
activeItemSubParam: string | null;
@@ -73,17 +74,24 @@ type Props = {
}
export const Administration = observer(function Administration({
activeItem, activeItemSub, activeItemSubParam, onItemSelect,
configurationWizard, activeItem, activeItemSub, activeItemSubParam, onItemSelect,
}: Props) {
const controller = useController(AdministrationController);
const items = controller.getItems(configurationWizard);
return styled(useStyles(verticalTabStyles, administrationStyles, tabsStyles))(
<container as='div'>
<TabsState currentTabId={activeItem} orientation='vertical'>
<drawer as='div'>
<TabList aria-label="Administration items">
{controller.items.map(item => (
<DrawerItem key={item.name} item={item} onSelect={onItemSelect} style={[verticalTabStyles, tabsStyles]} />
{items.map(item => (
<DrawerItem
key={item.name}
item={item}
onSelect={onItemSelect}
configurationWizard={configurationWizard}
style={[verticalTabStyles, tabsStyles]}
/>
))}
</TabList>
</drawer>
@@ -92,6 +100,7 @@ export const Administration = observer(function Administration({
activeItemName={activeItem}
activeItemSub={activeItemSub}
activeItemSubParam={activeItemSubParam}
configurationWizard={configurationWizard}
/>
</content>
</TabsState>
@@ -6,19 +6,19 @@
* you may not use this file except in compliance with the License.
*/
import { computed } from 'mobx';
import { injectable } from '@cloudbeaver/core-di';
import { AdministrationItemService } from '../AdministrationItem/AdministrationItemService';
import { filterConfigurationWizard } from '../AdministrationItem/filterConfigurationWizard';
import { orderAdministrationItems } from '../AdministrationItem/orderAdministrationItems';
@injectable()
export class AdministrationController {
@computed get items() {
getItems(configurationWizard: boolean) {
return this.administrationItemService
.items
.concat()
.sort((a, b) => a.order - b.order);
.filter(filterConfigurationWizard(configurationWizard))
.sort(orderAdministrationItems);
}
constructor(
@@ -10,8 +10,10 @@ import { observer } from 'mobx-react';
import { AdministrationItemDrawerProps } from '../AdministrationItem/IAdministrationItem';
export const DrawerItem = observer(function DrawerItem({ item, onSelect, style }: AdministrationItemDrawerProps) {
export const DrawerItem = observer(function DrawerItem({
item, onSelect, style, configurationWizard,
}: AdministrationItemDrawerProps) {
const Component = item.getDrawerComponent();
return <Component item={item} onSelect={onSelect} style={style}/>;
return <Component item={item} onSelect={onSelect} configurationWizard={configurationWizard} style={style}/>;
});
@@ -16,16 +16,22 @@ type Props = {
activeItemName: string | null;
activeItemSub: string | null;
activeItemSubParam: string | null;
configurationWizard: boolean;
}
export const ItemContent = observer(function ItemContent({ activeItemName, activeItemSub, activeItemSubParam }: Props) {
export const ItemContent = observer(function ItemContent({
activeItemName,
activeItemSub,
activeItemSubParam,
configurationWizard,
}: Props) {
const administrationItemService = useService(AdministrationItemService);
if (!activeItemName) {
return null;
}
const item = administrationItemService.getItem(activeItemName);
const item = administrationItemService.getItem(activeItemName, configurationWizard);
if (!item) {
return null;
@@ -36,11 +42,11 @@ export const ItemContent = observer(function ItemContent({ activeItemName, activ
if (sub) {
const Component = sub.getComponent();
return <Component item={item} sub={sub} param={activeItemSubParam} />;
return <Component item={item} sub={sub} param={activeItemSubParam} configurationWizard={configurationWizard} />;
}
}
const Component = item.getContentComponent();
return <Component item={item} />;
return <Component item={item} configurationWizard={configurationWizard} />;
});
@@ -10,23 +10,32 @@ import { observable } from 'mobx';
import { injectable } from '@cloudbeaver/core-di';
import { IAdministrationItem, IAdministrationItemOptions, IAdministrationItemSubItem } from './IAdministrationItem';
import { filterConfigurationWizard } from './filterConfigurationWizard';
import {
IAdministrationItem, IAdministrationItemOptions, IAdministrationItemSubItem, AdministrationItemType
} from './IAdministrationItem';
import { orderAdministrationItems } from './orderAdministrationItems';
@injectable()
export class AdministrationItemService {
@observable items: IAdministrationItem[] = []
getDefaultItem() {
if (this.items.length === 0) {
getDefaultItem(configurationWizard: boolean) {
const items = this.items.filter(filterConfigurationWizard(configurationWizard));
console.log(configurationWizard, items);
if (items.length === 0) {
return null;
}
return this.items
.concat()
.sort((a, b) => a.order - b.order)[0].name;
return items.sort(orderAdministrationItems)[0].name;
}
getItem(name: string): IAdministrationItem | null {
const item = this.items.find(item => item.name === name);
getItem(name: string, configurationWizard: boolean): IAdministrationItem | null {
const item = this.items.find(item => (
filterConfigurationWizard(configurationWizard)(item)
&& item.name === name
));
if (!item) {
return null;
}
@@ -44,32 +53,39 @@ export class AdministrationItemService {
}
create(options: IAdministrationItemOptions) {
if (this.items.some(item => item.name === options.name)) {
throw new Error(`Administration item "${options.name}" already exists`);
const type = options.type === undefined ? AdministrationItemType.Administration : options.type;
if (this.items.some(item => item.name === options.name && (
item.type === type
|| item.type === AdministrationItemType.Default
|| type === AdministrationItemType.Default
))) {
throw new Error(`Administration item "${options.name}" already exists in the same visibility scope`);
}
const item: IAdministrationItem = {
...options,
type,
sub: options.sub || [],
order: options.order || Number.MAX_SAFE_INTEGER,
};
this.items.push(item);
}
async activate(name: string, itemSub: string | null, param: string | null) {
const item = this.getItem(name);
async activate(name: string, itemSub: string | null, param: string | null, configurationWizard: boolean) {
const item = this.getItem(name, configurationWizard);
if (!item) {
return;
}
if (item.onActivate) {
await item.onActivate();
await item.onActivate(configurationWizard);
}
if (itemSub) {
const sub = this.getItemSub(item, itemSub);
if (sub && sub.onActivate) {
await sub.onActivate(param);
await sub.onActivate(param, configurationWizard);
}
}
}
@@ -8,8 +8,15 @@
import { Style } from '@cloudbeaver/core-theming';
export enum AdministrationItemType {
Default,
Administration,
ConfigurationWizard
}
export type AdministrationItemDrawerProps = {
item: IAdministrationItem;
configurationWizard: boolean;
onSelect(id: string): void;
style: Style[];
}
@@ -17,18 +24,20 @@ export type AdministrationItemDrawerComponent = React.FunctionComponent<Administ
export type AdministrationItemContentProps = {
item: IAdministrationItem;
configurationWizard: boolean;
}
export type AdministrationItemContentComponent = React.FunctionComponent<AdministrationItemContentProps>
export type AdministrationItemSubContentProps = {
item: IAdministrationItem;
sub: IAdministrationItemSubItem;
configurationWizard: boolean;
param: string | null;
}
export type AdministrationItemSubContentComponent = React.FunctionComponent<AdministrationItemSubContentProps>
export type AdministrationItemEvent = () => Promise<void> | void
export type AdministrationItemSubEvent = (param: string | null) => Promise<void> | void
export type AdministrationItemEvent = (configurationWizard: boolean) => Promise<void> | void
export type AdministrationItemSubEvent = (param: string | null, configurationWizard: boolean) => Promise<void> | void
export interface IAdministrationItemSubItem {
name: string;
@@ -38,6 +47,8 @@ export interface IAdministrationItemSubItem {
export interface IAdministrationItemOptions {
name: string;
/** By default will be set to AdministrationItemType.Administration */
type?: AdministrationItemType;
order?: number;
sub?: IAdministrationItemSubItem[];
getDrawerComponent(): AdministrationItemDrawerComponent;
@@ -46,6 +57,7 @@ export interface IAdministrationItemOptions {
}
export interface IAdministrationItem extends IAdministrationItemOptions {
type: AdministrationItemType;
order: number;
sub: IAdministrationItemSubItem[];
}
@@ -0,0 +1,15 @@
/*
* cloudbeaver - Cloud Database Manager
* Copyright (C) 2020 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 { AdministrationItemType, IAdministrationItem } from './IAdministrationItem';
export function filterConfigurationWizard(configurationWizard: boolean) {
return (item: IAdministrationItem) => (configurationWizard
? item.type !== AdministrationItemType.Administration
: item.type !== AdministrationItemType.ConfigurationWizard);
}
@@ -0,0 +1,13 @@
/*
* cloudbeaver - Cloud Database Manager
* Copyright (C) 2020 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 { IAdministrationItem } from './IAdministrationItem';
export function orderAdministrationItems(itemA: IAdministrationItem, itemB: IAdministrationItem) {
return itemA.order - itemB.order;
}
@@ -33,6 +33,7 @@ export const AdministrationScreen = observer(function AdministrationScreen() {
<>
<AdministrationTopAppBar />
<Administration
configurationWizard={false}
activeItem={administrationScreenService.activeItem}
activeItemSub={administrationScreenService.activeItemSub}
activeItemSubParam={administrationScreenService.activeItemSubParam}
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { computed } from 'mobx';
import { computed, observable } from 'mobx';
import { injectable, Bootstrap } from '@cloudbeaver/core-di';
import { PermissionsService } from '@cloudbeaver/core-root';
@@ -15,6 +15,7 @@ import { ScreenService, RouterService } from '@cloudbeaver/core-routing';
import { AdministrationItemService } from '../AdministrationItem/AdministrationItemService';
import { EAdminPermission } from '../EAdminPermission';
import { AdministrationScreen } from './AdministrationScreen';
import { ConfigurationWizardScreen } from './ConfigurationWizardScreen';
@injectable()
export class AdministrationScreenService extends Bootstrap {
@@ -24,22 +25,29 @@ export class AdministrationScreenService extends Bootstrap {
static itemSubRouteName = 'administration.item.sub'
static itemSubParamRouteName = 'administration.item.sub.param'
static setupName = 'setup'
static setupItemRouteName = 'setup.item'
static setupItemSubRouteName = 'setup.item.sub'
static setupItemSubParamRouteName = 'setup.item.sub.param'
@observable configurationWizard = false;
@computed get activeItem(): string | null {
if (!this.screenService.isActive(AdministrationScreenService.screenName)) {
if (!this.isAdministrationRouteActive()) {
return null;
}
return this.routerService.params.item || this.administrationItemService.getDefaultItem();
return this.routerService.params.item || this.administrationItemService.getDefaultItem(this.configurationWizard);
}
@computed get activeItemSub(): string | null {
if (!this.screenService.isActive(AdministrationScreenService.screenName)) {
if (!this.isAdministrationRouteActive()) {
return null;
}
return this.routerService.params.sub || null;
}
@computed get activeItemSubParam(): string | null {
if (!this.screenService.isActive(AdministrationScreenService.screenName)) {
if (!this.isAdministrationRouteActive()) {
return null;
}
return this.routerService.params.param || null;
@@ -56,19 +64,35 @@ export class AdministrationScreenService extends Bootstrap {
}
navigateToRoot() {
this.routerService.router.navigate(AdministrationScreenService.screenName);
if (this.configurationWizard) {
this.routerService.router.navigate(AdministrationScreenService.setupName);
} else {
this.routerService.router.navigate(AdministrationScreenService.screenName);
}
}
navigateToItem(item: string) {
this.routerService.router.navigate(AdministrationScreenService.itemRouteName, { item });
if (this.configurationWizard) {
this.routerService.router.navigate(AdministrationScreenService.setupItemRouteName, { item });
} else {
this.routerService.router.navigate(AdministrationScreenService.itemRouteName, { item });
}
}
navigateToItemSub(item: string, sub: string, param?: string) {
if (!param) {
this.routerService.router.navigate(AdministrationScreenService.itemSubRouteName, { item, sub });
if (this.configurationWizard) {
this.routerService.router.navigate(AdministrationScreenService.setupItemSubRouteName, { item, sub });
} else {
this.routerService.router.navigate(AdministrationScreenService.itemSubRouteName, { item, sub });
}
return;
}
this.routerService.router.navigate(AdministrationScreenService.itemSubParamRouteName, { item, sub, param });
if (this.configurationWizard) {
this.routerService.router.navigate(AdministrationScreenService.setupItemSubParamRouteName, { item, sub, param });
} else {
this.routerService.router.navigate(AdministrationScreenService.itemSubParamRouteName, { item, sub, param });
}
}
register() {
@@ -95,6 +119,30 @@ export class AdministrationScreenService extends Bootstrap {
component: AdministrationScreen,
onActivate: this.handleActivate.bind(this),
});
this.screenService.create({
name: AdministrationScreenService.setupName,
routes: [
{
name: AdministrationScreenService.setupName,
path: '/setup',
},
{
name: AdministrationScreenService.setupItemRouteName,
path: '/:item',
},
{
name: AdministrationScreenService.setupItemSubRouteName,
path: '/:sub',
},
{
name: AdministrationScreenService.setupItemSubParamRouteName,
path: '/:param',
},
],
component: ConfigurationWizardScreen,
onActivate: this.handleActivate.bind(this),
});
}
load(): void | Promise<void> { }
@@ -105,8 +153,23 @@ export class AdministrationScreenService extends Bootstrap {
return;
}
// FIXME: for development purposes only, must be removed
if (this.screenService.isActive(AdministrationScreenService.setupName)) {
this.configurationWizard = true;
}
if (this.activeItem) {
await this.administrationItemService.activate(this.activeItem, this.activeItemSub, this.activeItemSubParam);
await this.administrationItemService.activate(
this.activeItem,
this.activeItemSub,
this.activeItemSubParam,
this.configurationWizard
);
}
}
private isAdministrationRouteActive() {
return this.screenService.isActive(AdministrationScreenService.screenName)
|| this.screenService.isActive(AdministrationScreenService.setupName);
}
}
@@ -0,0 +1,44 @@
/*
* cloudbeaver - Cloud Database Manager
* Copyright (C) 2020 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 { observer } from 'mobx-react';
import { useCallback } from 'react';
import { useService } from '@cloudbeaver/core-di';
import { Translate } from '@cloudbeaver/core-localization';
import { usePermission } from '@cloudbeaver/core-root';
import { Administration } from '../Administration/Administration';
import { EAdminPermission } from '../EAdminPermission';
import { AdministrationScreenService } from './AdministrationScreenService';
import { AdministrationTopAppBar } from './AdministrationTopAppBar/AdministrationTopAppBar';
export const ConfigurationWizardScreen = observer(function ConfigurationWizardScreen() {
const administrationScreenService = useService(AdministrationScreenService);
if (!usePermission(EAdminPermission.admin)) {
return <Translate token='root_permission_denied'/>;
}
const handleSelect = useCallback(
(item: string) => administrationScreenService.navigateToItem(item),
[administrationScreenService]
);
return (
<>
<AdministrationTopAppBar />
<Administration
configurationWizard={true}
activeItem={administrationScreenService.activeItem}
activeItemSub={administrationScreenService.activeItemSub}
activeItemSubParam={administrationScreenService.activeItemSubParam}
onItemSelect={handleSelect}
/>
</>
);
});
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { AdministrationItemService, AdministrationScreenService } from '@cloudbeaver/core-administration';
import { AdministrationItemService, AdministrationScreenService, AdministrationItemType } from '@cloudbeaver/core-administration';
import { injectable, Bootstrap } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
@@ -30,6 +30,7 @@ export class ConnectionsAdministrationService extends Bootstrap {
register() {
this.administrationItemService.create({
name: 'connections',
type: AdministrationItemType.Default,
order: 2,
sub: [
{