1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

added workspace overview as details page (WIP)

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
Jim Ehrismann 2021-01-08 18:43:38 -05:00
parent a0c19eb3c5
commit f6058d73d1
9 changed files with 278 additions and 7 deletions

View File

@ -0,0 +1,2 @@
.AddWorkspaceDialog {
}

View File

@ -0,0 +1,84 @@
import "./add-workspace-dialog.scss";
import React from "react";
import { observable } from "mobx";
import { observer } from "mobx-react";
import { Dialog, DialogProps } from "../dialog";
import { Wizard, WizardStep } from "../wizard";
//import { namespaceStore } from "./namespace.store";
import { Workspace, WorkspaceId } from "../../../common/workspace-store";
import { Input } from "../input";
import { systemName } from "../input/input_validators";
import { Notifications } from "../notifications";
interface Props extends DialogProps {
onSuccess?(ws: Workspace): void;
onError?(error: any): void;
}
@observer
export class AddWorkspaceDialog extends React.Component<Props> {
@observable static isOpen = false;
@observable workspace = "";
static open() {
AddWorkspaceDialog.isOpen = true;
}
static close() {
AddWorkspaceDialog.isOpen = false;
}
reset = () => {
this.workspace = "";
};
close = () => {
AddWorkspaceDialog.close();
};
addWorkspace = async () => {
const { workspace } = this;
const { onSuccess, onError } = this.props;
try {
// await namespaceStore.create({ name: workspace }).then(onSuccess);
this.close();
} catch (err) {
Notifications.error(err);
onError && onError(err);
}
};
render() {
const { ...dialogProps } = this.props;
const { workspace } = this;
const header = <h5>Create Workspace</h5>;
return (
<Dialog
{...dialogProps}
className="AddWorkspaceDialog"
isOpen={AddWorkspaceDialog.isOpen}
onOpen={this.reset}
close={this.close}
>
<Wizard header={header} done={this.close}>
<WizardStep
contentClass="flex gaps column"
nextLabel="Create"
next={this.addWorkspace}
>
<Input
required autoFocus
iconLeft="layers"
placeholder={`Workspace`}
validators={systemName}
value={workspace} onChange={v => this.workspace = v.toLowerCase()}
/>
</WizardStep>
</Wizard>
</Dialog>
);
}
}

View File

@ -1,3 +1,4 @@
export * from "./workspaces.route"; export * from "./workspaces.route";
export * from "./workspace-list.route";
export * from "./workspaces"; export * from "./workspaces";
export * from "./workspace-list"; export * from "./workspace-list";

View File

@ -0,0 +1,52 @@
.WorkspaceDetails {
.intro-logo {
margin-right: $margin * 2;
background: $helmLogoBackground;
border-radius: $radius;
max-width: 150px;
max-height: 100px;
padding: $padding;
box-sizing: content-box;
}
.intro-contents {
.description {
font-weight: bold;
color: $textColorAccent;
padding-bottom: $padding;
.Button {
padding-left: $padding * 3;
padding-right: $padding * 3;
margin-left: $margin * 2;
align-self: flex-start;
}
}
.version {
.Select {
min-width: 80px;
white-space: nowrap;
}
.Icon {
margin-right: $margin;
}
}
.maintainers {
a {
display: inline-block;
margin-right: $margin;
}
}
.DrawerItem {
align-items: center;
}
}
.chart-description {
margin-top: $margin * 2;
}
}

View File

@ -0,0 +1,62 @@
import "./workspace-details.scss";
import React, { Component } from "react";
import { WorkspaceItem } from "./workspace-list.store";
import { clusterStore } from "../../../common/cluster-store";
import { Cluster } from "../../../main/cluster";
import { observable, autorun } from "mobx";
import { observer } from "mobx-react";
import { Drawer, DrawerItem, DrawerTitle } from "../drawer";
import { autobind, stopPropagation } from "../../utils";
import { MarkdownViewer } from "../markdown-viewer";
import { Spinner } from "../spinner";
import { Button } from "../button";
import { Select, SelectOption } from "../select";
import { Badge } from "../badge";
interface Props {
workspace: WorkspaceItem;
hideDetails(): void;
}
@observer
export class WorkspaceDetails extends Component<Props> {
renderClusters() {
const { workspace } = this.props;
const clusters = clusterStore.getByWorkspaceId(workspace.getId());
return <div>
{clusters.map(cluster => <div>{cluster.contextName}</div>)}
</div>
}
render() {
const { workspace, hideDetails } = this.props;
const title = workspace ? <>Workspace: {workspace.getName()}</> : "";
return (
<Drawer
className="WorkspaceDetails"
usePortal={true}
open={!!workspace}
title={title}
onClose={hideDetails}
>
<DrawerItem name={"Description"}>
{workspace.getDescription()}
</DrawerItem>
<DrawerItem name={"Id"}>
{workspace.getId()}
</DrawerItem>
<DrawerItem name={"Owner Ref"}>
{workspace.getOwnerRef()}
</DrawerItem>
<DrawerItem name={"Enabled"} renderBoolean={true}>
{workspace.getEnabled()}
</DrawerItem>
<DrawerTitle title={"Clusters"}/>
{this.renderClusters()}
</Drawer>
);
}
}

View File

@ -0,0 +1,12 @@
import type { RouteProps } from "react-router";
import { buildURL } from "../../../common/utils/buildUrl";
export const workspaceListRoute: RouteProps = {
path: `/workspaces/:workspaceName?`
};
export interface IWorkspaceListRouteParams {
workspaceName?: string;
}
export const workspaceListURL = buildURL<IWorkspaceListRouteParams>(workspaceListRoute.path);

View File

@ -8,9 +8,21 @@ export class WorkspaceItem {
return this.workspace.name; return this.workspace.name;
} }
getDescription() {
return this.workspace.description;
}
getId() { getId() {
return this.workspace.id; return this.workspace.id;
} }
getOwnerRef() {
return this.workspace.ownerRef;
}
getEnabled() {
return this.workspace.enabled ? "True" : "False";
}
} }
export class WorkspaceListStore extends ItemStore<WorkspaceItem> { export class WorkspaceListStore extends ItemStore<WorkspaceItem> {

View File

@ -1,22 +1,55 @@
import "./workspaces.scss"; import "./workspaces.scss";
import React from "react"; import React from "react";
import { RouteComponentProps } from "react-router";
import { observer } from "mobx-react";
import { navigation } from "../../navigation";
import { workspaceListURL, IWorkspaceListRouteParams } from "./workspace-list.route";
import { TabLayout } from "../layout/tab-layout"; import { TabLayout } from "../layout/tab-layout";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { ItemListLayout, ItemListLayoutProps } from "../item-object-list/item-list-layout"; import { ItemListLayout, ItemListLayoutProps } from "../item-object-list/item-list-layout";
import { AddWorkspaceDialog } from "./add-workspace-dialog";
import { Workspace, WorkspaceId } from "../../../common/workspace-store"; import { Workspace, WorkspaceId } from "../../../common/workspace-store";
import { WorkspaceItem, workspaceListStore } from "./workspace-list.store"; import { WorkspaceItem, workspaceListStore } from "./workspace-list.store";
import { WorkspaceDetails } from "./workspace-details";
enum sortBy { enum sortBy {
name = "name", name = "name",
id = "id", description = "description",
} }
export class WorkspaceList extends React.Component { interface Props extends RouteComponentProps<IWorkspaceListRouteParams> {
}
@observer
export class WorkspaceList extends React.Component<Props> {
componentDidMount() { componentDidMount() {
workspaceListStore.loadAll(); workspaceListStore.loadAll();
} }
get selectedWorkspace() {
const { match: { params: { workspaceName } } } = this.props;
return workspaceListStore.getByName(workspaceName);
}
showDetails = (workspace: WorkspaceItem) => {
if (!workspace) {
navigation.merge(workspaceListURL());
}
else {
navigation.merge(workspaceListURL({
params: {
workspaceName: workspace.getName(),
}
}));
}
};
hideDetails = () => {
this.showDetails(null);
};
render() { render() {
return ( return (
<TabLayout> <TabLayout>
@ -25,19 +58,32 @@ export class WorkspaceList extends React.Component {
className="Workspaces" store={workspaceListStore} className="Workspaces" store={workspaceListStore}
sortingCallbacks={{ sortingCallbacks={{
[sortBy.name]: (ws: WorkspaceItem) => ws.getName(), [sortBy.name]: (ws: WorkspaceItem) => ws.getName(),
[sortBy.id]: (ws: WorkspaceItem) => ws.getId(), [sortBy.description]: (ws: WorkspaceItem) => ws.getDescription(),
}} }}
searchFilters={[]} searchFilters={[]}
renderHeaderTitle="Workspaces" renderHeaderTitle="Workspaces"
renderTableHeader={[ renderTableHeader={[
{ title: "Name", className: "name", sortBy: sortBy.name }, { title: "Name", className: "name", sortBy: sortBy.name },
{ title: "Id", className: "id", sortBy: sortBy.id }, { title: "Description", className: "description", sortBy: sortBy.description },
]} ]}
renderTableContents={(item: WorkspaceItem) => [ renderTableContents={(item: WorkspaceItem) => [
item.getName(), item.getName(),
item.getId(), item.getDescription(),
]} ]}
addRemoveButtons={{
addTooltip: "Add Workspace",
onAdd: () => AddWorkspaceDialog.open(),
}}
detailsItem={this.selectedWorkspace}
onDetails={this.showDetails}
/> />
{this.selectedWorkspace && (
<WorkspaceDetails
workspace={this.selectedWorkspace}
hideDetails={this.hideDetails}
/>
)}
<AddWorkspaceDialog/>
</TabLayout> </TabLayout>
); );
} }

View File

@ -8,7 +8,7 @@ import { ClustersMenu } from "./clusters-menu";
import { BottomBar } from "./bottom-bar"; import { BottomBar } from "./bottom-bar";
import { LandingPage, landingRoute, landingURL } from "../+landing-page"; import { LandingPage, landingRoute, landingURL } from "../+landing-page";
import { Preferences, preferencesRoute } from "../+preferences"; import { Preferences, preferencesRoute } from "../+preferences";
import { WorkspaceList, workspacesRoute } from "../+workspaces"; import { WorkspaceList, workspaceListRoute } from "../+workspaces";
import { AddCluster, addClusterRoute } from "../+add-cluster"; import { AddCluster, addClusterRoute } from "../+add-cluster";
import { ClusterView } from "./cluster-view"; import { ClusterView } from "./cluster-view";
import { ClusterSettings, clusterSettingsRoute } from "../+cluster-settings"; import { ClusterSettings, clusterSettingsRoute } from "../+cluster-settings";
@ -67,7 +67,7 @@ export class ClusterManager extends React.Component {
<Route component={LandingPage} {...landingRoute} /> <Route component={LandingPage} {...landingRoute} />
<Route component={Preferences} {...preferencesRoute} /> <Route component={Preferences} {...preferencesRoute} />
<Route component={Extensions} {...extensionsRoute} /> <Route component={Extensions} {...extensionsRoute} />
<Route component={WorkspaceList} {...workspacesRoute} /> <Route component={WorkspaceList} {...workspaceListRoute} />
<Route component={AddCluster} {...addClusterRoute} /> <Route component={AddCluster} {...addClusterRoute} />
<Route component={ClusterView} {...clusterViewRoute} /> <Route component={ClusterView} {...clusterViewRoute} />
<Route component={ClusterSettings} {...clusterSettingsRoute} /> <Route component={ClusterSettings} {...clusterSettingsRoute} />