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

fix WizardStep and AddNamespaceDialog

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-04-25 11:26:03 -04:00
parent c89d63ad3e
commit 8499f26707
11 changed files with 102 additions and 106 deletions

View File

@ -601,20 +601,19 @@ export class KubeApi<
return parsed; return parsed;
} }
async create({ name, namespace }: Partial<ResourceDescriptor>, data?: PartialDeep<Object>): Promise<Object | null> { async create({ name, namespace }: Partial<ResourceDescriptor>, partialData?: PartialDeep<Object>): Promise<Object | null> {
await this.checkPreferredVersion(); await this.checkPreferredVersion();
const apiUrl = this.getUrl({ namespace }); const apiUrl = this.getUrl({ namespace });
const res = await this.request.post(apiUrl, { const data = merge(partialData, {
data: merge(data, { kind: this.kind,
kind: this.kind, apiVersion: this.apiVersionWithGroup,
apiVersion: this.apiVersionWithGroup, metadata: {
metadata: { name,
name, namespace,
namespace, },
},
}),
}); });
const res = await this.request.post(apiUrl, { data });
const parsed = this.parseResponse(res); const parsed = this.parseResponse(res);
if (Array.isArray(parsed)) { if (Array.isArray(parsed)) {

View File

@ -3,24 +3,25 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import "./add-namespace-dialog.scss"; import "./dialog.scss";
import React from "react"; import React from "react";
import { observable, makeObservable } from "mobx"; import type { IObservableValue } from "mobx";
import { action, observable, makeObservable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import type { DialogProps } from "../dialog"; import type { DialogProps } from "../../dialog";
import { Dialog } from "../dialog"; import { Dialog } from "../../dialog";
import { Wizard, WizardStep } from "../wizard"; import { Wizard, WizardStep } from "../../wizard";
import type { Namespace } from "../../../common/k8s-api/endpoints"; import type { Namespace } from "../../../../common/k8s-api/endpoints";
import { Input } from "../input"; import { Input } from "../../input";
import { systemName } from "../input/input_validators"; import { systemName } from "../../input/input_validators";
import { Notifications } from "../notifications"; import { Notifications } from "../../notifications";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "./store.injectable"; import namespaceStoreInjectable from "../store.injectable";
import type { AddNamespaceDialogModel } from "./add-namespace-dialog-model/add-namespace-dialog-model"; import addNamespaceDialogStateInjectable
import addNamespaceDialogModelInjectable from "./state.injectable";
from "./add-namespace-dialog-model/add-namespace-dialog-model.injectable"; import type { NamespaceStore } from "../store";
import type { NamespaceStore } from "./store"; import { autoBind } from "../../../utils";
export interface AddNamespaceDialogProps extends DialogProps { export interface AddNamespaceDialogProps extends DialogProps {
onSuccess?(ns: Namespace): void; onSuccess?(ns: Namespace): void;
@ -29,7 +30,7 @@ export interface AddNamespaceDialogProps extends DialogProps {
interface Dependencies { interface Dependencies {
namespaceStore: NamespaceStore; namespaceStore: NamespaceStore;
model: AddNamespaceDialogModel; state: IObservableValue<boolean>;
} }
@observer @observer
@ -39,41 +40,51 @@ class NonInjectedAddNamespaceDialog extends React.Component<AddNamespaceDialogPr
constructor(props: AddNamespaceDialogProps & Dependencies) { constructor(props: AddNamespaceDialogProps & Dependencies) {
super(props); super(props);
makeObservable(this); makeObservable(this);
autoBind(this);
} }
reset = () => { @action
this.namespace = ""; close() {
}; this.props.state.set(false);
}
addNamespace = async () => { @action
reset() {
this.namespace = "";
}
async addNamespace() {
const { namespace } = this; const { namespace } = this;
const { onSuccess, onError } = this.props; const { onSuccess, onError, namespaceStore } = this.props;
try { try {
const created = await this.props.namespaceStore.create({ name: namespace }); const created = await namespaceStore.create({ name: namespace });
onSuccess?.(created); onSuccess?.(created);
this.props.model.close(); this.close();
} catch (err) { } catch (err) {
Notifications.checkedError(err, "Unknown error occured while creating the namespace"); Notifications.checkedError(err, "Unknown error occured while creating the namespace");
onError?.(err); onError?.(err);
} }
}; }
render() { render() {
const { model, namespaceStore, ...dialogProps } = this.props; const { state, namespaceStore, ...dialogProps } = this.props;
const { namespace } = this; const { namespace } = this;
const header = <h5>Create Namespace</h5>; const isOpen = state.get();
return ( return (
<Dialog <Dialog
{...dialogProps} {...dialogProps}
className="AddNamespaceDialog" className="AddNamespaceDialog"
isOpen={this.props.model.isOpen} isOpen={isOpen}
onOpen={this.reset} onClose={this.reset}
close={this.props.model.close} close={this.close}
> >
<Wizard header={header} done={this.props.model.close}> <Wizard
header={<h5>Create Namespace</h5>}
done={this.close}
>
<WizardStep <WizardStep
contentClass="flex gaps column" contentClass="flex gaps column"
nextLabel="Create" nextLabel="Create"
@ -96,15 +107,10 @@ class NonInjectedAddNamespaceDialog extends React.Component<AddNamespaceDialogPr
} }
} }
export const AddNamespaceDialog = withInjectables<Dependencies, AddNamespaceDialogProps>( export const AddNamespaceDialog = withInjectables<Dependencies, AddNamespaceDialogProps>(NonInjectedAddNamespaceDialog, {
NonInjectedAddNamespaceDialog, getProps: (di, props) => ({
...props,
{ namespaceStore: di.inject(namespaceStoreInjectable),
getProps: (di, props) => ({ state: di.inject(addNamespaceDialogStateInjectable),
namespaceStore: di.inject(namespaceStoreInjectable), }),
model: di.inject(addNamespaceDialogModelInjectable), });
...props,
}),
},
);

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { action } from "mobx";
import addNamespaceDialogStateInjectable from "./state.injectable";
const openAddNamepaceDialogInjectable = getInjectable({
id: "open-add-namepace-dialog",
instantiate: (di) => {
const state = di.inject(addNamespaceDialogStateInjectable);
return action(() => {
state.set(true);
});
},
});
export default openAddNamepaceDialogInjectable;

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx";
const addNamespaceDialogStateInjectable = getInjectable({
id: "add-namespace-dialog-state",
instantiate: () => observable.box(false),
});
export default addNamespaceDialogStateInjectable;

View File

@ -1,13 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { AddNamespaceDialogModel } from "./add-namespace-dialog-model";
const addNamespaceDialogModelInjectable = getInjectable({
id: "add-namespace-dialog-model",
instantiate: () => new AddNamespaceDialogModel(),
});
export default addNamespaceDialogModelInjectable;

View File

@ -1,25 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { observable, makeObservable, action } from "mobx";
export class AddNamespaceDialogModel {
isOpen = false;
constructor() {
makeObservable(this, {
isOpen: observable,
open: action,
close: action,
});
}
open = () => {
this.isOpen = true;
};
close = () => {
this.isOpen = false;
};
}

View File

@ -4,4 +4,4 @@
*/ */
export * from "./namespace-details"; export * from "./namespace-details";
export * from "./add-namespace-dialog"; export * from "./add-dialog/dialog";

View File

@ -7,7 +7,7 @@ import "./namespaces.scss";
import React from "react"; import React from "react";
import { NamespaceStatusKind } from "../../../common/k8s-api/endpoints"; import { NamespaceStatusKind } from "../../../common/k8s-api/endpoints";
import { AddNamespaceDialog } from "./add-namespace-dialog"; import { AddNamespaceDialog } from "./add-dialog/dialog";
import { TabLayout } from "../layout/tab-layout-2"; import { TabLayout } from "../layout/tab-layout-2";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectListLayout } from "../kube-object-list-layout";
@ -15,8 +15,8 @@ import type { NamespaceStore } from "./store";
import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { KubeObjectStatusIcon } from "../kube-object-status-icon";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "./store.injectable"; import namespaceStoreInjectable from "./store.injectable";
import addNamespaceDialogModelInjectable from "./add-namespace-dialog-model/add-namespace-dialog-model.injectable";
import { KubeObjectAge } from "../kube-object/age"; import { KubeObjectAge } from "../kube-object/age";
import openAddNamepaceDialogInjectable from "./add-dialog/open.injectable";
enum columnId { enum columnId {
name = "name", name = "name",
@ -84,6 +84,6 @@ export const NonInjectedNamespacesRoute = ({ namespaceStore, openAddNamespaceDia
export const NamespacesRoute = withInjectables<Dependencies>(NonInjectedNamespacesRoute, { export const NamespacesRoute = withInjectables<Dependencies>(NonInjectedNamespacesRoute, {
getProps: (di) => ({ getProps: (di) => ({
namespaceStore: di.inject(namespaceStoreInjectable), namespaceStore: di.inject(namespaceStoreInjectable),
openAddNamespaceDialog: di.inject(addNamespaceDialogModelInjectable).open, openAddNamespaceDialog: di.inject(openAddNamepaceDialogInjectable),
}), }),
}); });

View File

@ -28,7 +28,7 @@ export class Notifications extends React.Component {
} }
static checkedError(message: unknown, fallback: string, customOpts?: Partial<Omit<Notification, "message">>) { static checkedError(message: unknown, fallback: string, customOpts?: Partial<Omit<Notification, "message">>) {
if (typeof message === "string" || message instanceof Error) { if (typeof message === "string" || message instanceof Error || message instanceof JsonApiErrorParsed) {
return Notifications.error(message, customOpts); return Notifications.error(message, customOpts);
} }

View File

@ -210,47 +210,43 @@ export class WizardStep<D> extends React.Component<WizardStepProps<D>, WizardSte
step, isFirst, isLast, children, step, isFirst, isLast, children,
loading, customButtons, disabledNext, scrollable, loading, customButtons, disabledNext, scrollable,
hideNextBtn, hideBackBtn, beforeContent, afterContent, noValidate, skip, moreButtons, hideNextBtn, hideBackBtn, beforeContent, afterContent, noValidate, skip, moreButtons,
waiting, className, contentClass, prevLabel, nextLabel,
} = this.props; } = this.props;
let { className, contentClass, nextLabel, prevLabel, waiting } = this.props;
if (skip) { if (skip) {
return null; return null;
} }
waiting = (waiting !== undefined) ? waiting : this.state.waiting;
className = cssNames(`WizardStep step${step}`, className);
contentClass = cssNames("step-content", { scrollable }, contentClass);
prevLabel = prevLabel || (isFirst?.() ? "Cancel" : "Back");
nextLabel = nextLabel || (isLast?.() ? "Submit" : "Next");
return ( return (
<form <form
className={className} className={cssNames(`WizardStep step${step}`, className)}
onSubmit={prevDefault(this.submit)} onSubmit={prevDefault(this.submit)}
noValidate={noValidate} noValidate={noValidate}
onKeyDown={(evt) => this.keyDown(evt)} onKeyDown={(evt) => this.keyDown(evt)}
ref={e => this.form = e} ref={e => this.form = e}
> >
{beforeContent} {beforeContent}
<div className={contentClass}> <div className={cssNames("step-content", { scrollable }, contentClass)}>
{loading ? this.renderLoading() : children} {loading ? this.renderLoading() : children}
</div> </div>
{customButtons !== undefined ? customButtons : ( {customButtons ?? (
<div className="buttons flex gaps align-center"> <div className="buttons flex gaps align-center">
{moreButtons} {moreButtons}
<Button <Button
className="back-btn" className="back-btn"
plain plain
label={prevLabel} label={prevLabel || (isFirst?.() ? "Cancel" : "Back")}
hidden={hideBackBtn} hidden={hideBackBtn}
onClick={this.prev} onClick={this.prev}
/> />
<Button <Button
primary primary
type="submit" type="submit"
label={nextLabel} label={nextLabel || (isLast?.() ? "Submit" : "Next")}
hidden={hideNextBtn} hidden={hideNextBtn}
waiting={waiting} waiting={waiting ?? this.state.waiting}
disabled={disabledNext} disabled={disabledNext}
onClick={this.next}
/> />
</div> </div>
)} )}