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

master-merge fixes, fine-tuning

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-10-19 14:16:32 +03:00
parent d6b7001f72
commit 59357d0a69
6 changed files with 41 additions and 44 deletions

View File

@ -30,6 +30,7 @@ import * as resourceApplierApi from "../../../common/k8s-api/endpoints/resource-
import { Notifications } from "../notifications";
import { TabKind } from "./dock.store";
import { dockViewsManager } from "./dock.views-manager";
import logger from "../../../common/logger";
interface Props extends InfoPanelProps {
}
@ -58,13 +59,13 @@ export class CreateResourceInfoPanel extends React.Component<Props> {
}
create = async (): Promise<undefined> => {
if (this.error || !this.data.trim()) {
if (!this.draft) {
// do not save when field is empty or there is an error
return null;
}
// skip empty documents
const resources = yaml.loadAll(this.data).filter(Boolean);
const resources = yaml.loadAll(this.draft).filter(Boolean);
const createdResources: string[] = [];
if (resources.length === 0) {

View File

@ -26,7 +26,7 @@ import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./doc
import type { KubeObject } from "../../../common/k8s-api/kube-object";
import { apiManager } from "../../../common/k8s-api/api-manager";
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import jsYaml from "js-yaml";
import yaml from "js-yaml";
export interface EditingResource {
resource: string; // resource path, e.g. /api/v1/namespaces/default
@ -61,7 +61,7 @@ export class EditResourceStore extends DockTabStore<EditingResource> {
let resource = this.getResource(tabId);
resource ??= await store.loadFromPath(data.resource);
data.draft ||= jsYaml.safeDump(resource.toPlainObject()); // dump resource if empty
data.draft ||= yaml.dump(resource.toPlainObject()); // dump resource if empty
} catch (error) {
console.error(`[DOCK]: dumping '${data.resource}' has failed: ${error}`, { store, data });
}

View File

@ -21,13 +21,14 @@
import React from "react";
import { observer } from "mobx-react";
import jsYaml from "js-yaml";
import yaml from "js-yaml";
import { editResourceStore } from "./edit-resource.store";
import { InfoPanel, InfoPanelProps } from "./info-panel";
import { Badge } from "../badge";
import type { KubeObject } from "../../../common/k8s-api/kube-object";
import { TabKind } from "./dock.store";
import { dockViewsManager } from "./dock.views-manager";
import { createPatch } from "rfc6902";
interface Props extends InfoPanelProps {
}
@ -42,50 +43,43 @@ export class EditResourceInfoPanel extends React.Component<Props> {
return editResourceStore.getResource(this.tabId);
}
@computed get draft(): string {
if (!this.isReadyForEditing) {
return ""; // wait until tab's data and kube-object resource are loaded
}
const { draft } = editResourceStore.getData(this.tabId);
if (typeof draft === "string") {
return draft;
}
return yaml.dump(this.resource.toPlainObject()); // dump resource first time
get draft(): string {
return editResourceStore.getData(this.tabId)?.draft;
}
@action
saveDraft(draft: string | object) {
private saveDraft(draft: string | KubeObject) {
if (typeof draft === "object") {
draft = draft ? yaml.dump(draft) : undefined;
draft = draft ? yaml.dump(draft.toPlainObject()) : undefined;
}
editResourceStore.setData(this.tabId, {
firstDraft: draft, // this must be before the next line
...editResourceStore.getData(this.tabId),
draft,
});
editResourceStore.getData(this.tabId).draft = draft;
}
onChange = (draft: string, error?: string) => {
this.error = error;
this.saveDraft(draft);
};
save = async () => {
if (this.error) {
return null;
const store = editResourceStore.getStore(this.tabId);
const { resource: resourcePath, draft } = editResourceStore.getData(this.tabId);
const resource = store.getByPath(resourcePath) ?? await store.loadFromPath(resourcePath);
const currentVersion = resource.toPlainObject();
const editedVersion = yaml.load(draft) as KubeObject;
const patches = createPatch(currentVersion, editedVersion);
const editingVersion = editedVersion.metadata.resourceVersion;
if (editingVersion != resource.getResourceVersion()) {
throw (
<div className="resource-outdated flex column gaps">
<p>
{resource.kind} version <b>{resource.getName()}</b> is updated on the server while editing.
</p>
<p>
Please backup your changes and <a onClick={() => this.saveDraft(resource)}>refresh resource</a> to the editor.
</p>
</div>
);
}
const store = editResourceStore.getStore(this.tabId);
const currentVersion = yaml.load(this.draft);
const firstVersion = yaml.load(editResourceStore.getData(this.tabId).firstDraft ?? this.draft);
const patches = createPatch(firstVersion, currentVersion);
const updatedResource = await store.patch(this.resource, patches);
editResourceStore.clearInitialDraft(this.tabId);
this.saveDraft(updatedResource); // dump latest resource version for editing
return (
<p>

View File

@ -23,7 +23,7 @@ import "./info-panel.scss";
import React, { Component, ReactNode } from "react";
import { makeObservable, observable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { cssNames } from "../../utils";
import { cssNames, isReactNode } from "../../utils";
import { Button } from "../button";
import { Icon } from "../icon";
import { Spinner } from "../spinner";
@ -85,7 +85,9 @@ export class InfoPanel extends Component<InfoPanelProps> {
if (showNotifications) Notifications.ok(result);
} catch (error) {
if (showNotifications) Notifications.error(error.toString());
const errorMessage = isReactNode(error) ? error : String(error);
if (showNotifications) Notifications.error(errorMessage);
} finally {
this.waiting = false;
}
@ -126,12 +128,12 @@ export class InfoPanel extends Component<InfoPanelProps> {
</div>
{showStatusPanel && (
<div className="flex gaps align-center">
{waiting ? <><Spinner /> {submittingMessage}</> : this.renderErrorIcon()}
{waiting ? <><Spinner/> {submittingMessage}</> : this.renderErrorIcon()}
</div>
)}
{showButtons && (
<>
<Button plain label="Cancel" onClick={close} />
<Button plain label="Cancel" onClick={close}/>
<Button
active
outlined={showSubmitClose}

View File

@ -35,7 +35,7 @@ registerCustomThemes(); // setup
export interface MonacoEditorProps {
id?: string; // associating editor's ID with created model.uri
value?: string; // initial text value for editor
value?: string;
className?: string;
autoFocus?: boolean;
readOnly?: boolean;

View File

@ -22,7 +22,7 @@
// Helper for working with storages (e.g. window.localStorage, NodeJS/file-system, etc.)
import { action, comparer, IReactionDisposer, IReactionOptions, makeObservable, observable, reaction, toJS, when, } from "mobx";
import produce, { Draft, isDraft } from "immer";
import { isEqual } from "lodash";
import { isEqual, isPlainObject } from "lodash";
import logger from "../../main/logger";
import { disposer } from "../../common/utils";
@ -166,7 +166,7 @@ export class StorageHelper<T> {
if (newValue && !isDraft(newValue)) {
Object.assign(draft, newValue);
}
} else {
} else if (isPlainObject(value)) {
Object.assign(draft, value);
}
});