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 { Notifications } from "../notifications";
import { TabKind } from "./dock.store"; import { TabKind } from "./dock.store";
import { dockViewsManager } from "./dock.views-manager"; import { dockViewsManager } from "./dock.views-manager";
import logger from "../../../common/logger";
interface Props extends InfoPanelProps { interface Props extends InfoPanelProps {
} }
@ -58,13 +59,13 @@ export class CreateResourceInfoPanel extends React.Component<Props> {
} }
create = async (): Promise<undefined> => { 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 // do not save when field is empty or there is an error
return null; return null;
} }
// skip empty documents // skip empty documents
const resources = yaml.loadAll(this.data).filter(Boolean); const resources = yaml.loadAll(this.draft).filter(Boolean);
const createdResources: string[] = []; const createdResources: string[] = [];
if (resources.length === 0) { 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 type { KubeObject } from "../../../common/k8s-api/kube-object";
import { apiManager } from "../../../common/k8s-api/api-manager"; import { apiManager } from "../../../common/k8s-api/api-manager";
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import jsYaml from "js-yaml"; import yaml from "js-yaml";
export interface EditingResource { export interface EditingResource {
resource: string; // resource path, e.g. /api/v1/namespaces/default 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); let resource = this.getResource(tabId);
resource ??= await store.loadFromPath(data.resource); 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) { } catch (error) {
console.error(`[DOCK]: dumping '${data.resource}' has failed: ${error}`, { store, data }); console.error(`[DOCK]: dumping '${data.resource}' has failed: ${error}`, { store, data });
} }

View File

@ -21,13 +21,14 @@
import React from "react"; import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import jsYaml from "js-yaml"; import yaml from "js-yaml";
import { editResourceStore } from "./edit-resource.store"; import { editResourceStore } from "./edit-resource.store";
import { InfoPanel, InfoPanelProps } from "./info-panel"; import { InfoPanel, InfoPanelProps } from "./info-panel";
import { Badge } from "../badge"; import { Badge } from "../badge";
import type { KubeObject } from "../../../common/k8s-api/kube-object"; import type { KubeObject } from "../../../common/k8s-api/kube-object";
import { TabKind } from "./dock.store"; import { TabKind } from "./dock.store";
import { dockViewsManager } from "./dock.views-manager"; import { dockViewsManager } from "./dock.views-manager";
import { createPatch } from "rfc6902";
interface Props extends InfoPanelProps { interface Props extends InfoPanelProps {
} }
@ -42,50 +43,43 @@ export class EditResourceInfoPanel extends React.Component<Props> {
return editResourceStore.getResource(this.tabId); return editResourceStore.getResource(this.tabId);
} }
@computed get draft(): string { get draft(): string {
if (!this.isReadyForEditing) { return editResourceStore.getData(this.tabId)?.draft;
return ""; // wait until tab's data and kube-object resource are loaded
} }
const { draft } = editResourceStore.getData(this.tabId); private saveDraft(draft: string | KubeObject) {
if (typeof draft === "string") {
return draft;
}
return yaml.dump(this.resource.toPlainObject()); // dump resource first time
}
@action
saveDraft(draft: string | object) {
if (typeof draft === "object") { if (typeof draft === "object") {
draft = draft ? yaml.dump(draft) : undefined; draft = draft ? yaml.dump(draft.toPlainObject()) : undefined;
} }
editResourceStore.setData(this.tabId, { editResourceStore.getData(this.tabId).draft = draft;
firstDraft: draft, // this must be before the next line
...editResourceStore.getData(this.tabId),
draft,
});
} }
onChange = (draft: string, error?: string) => {
this.error = error;
this.saveDraft(draft);
};
save = async () => { save = async () => {
if (this.error) { const store = editResourceStore.getStore(this.tabId);
return null; 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); const updatedResource = await store.patch(this.resource, patches);
editResourceStore.clearInitialDraft(this.tabId); this.saveDraft(updatedResource); // dump latest resource version for editing
return ( return (
<p> <p>

View File

@ -23,7 +23,7 @@ import "./info-panel.scss";
import React, { Component, ReactNode } from "react"; import React, { Component, ReactNode } from "react";
import { makeObservable, observable, reaction } from "mobx"; import { makeObservable, observable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { cssNames } from "../../utils"; import { cssNames, isReactNode } from "../../utils";
import { Button } from "../button"; import { Button } from "../button";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
@ -85,7 +85,9 @@ export class InfoPanel extends Component<InfoPanelProps> {
if (showNotifications) Notifications.ok(result); if (showNotifications) Notifications.ok(result);
} catch (error) { } catch (error) {
if (showNotifications) Notifications.error(error.toString()); const errorMessage = isReactNode(error) ? error : String(error);
if (showNotifications) Notifications.error(errorMessage);
} finally { } finally {
this.waiting = false; this.waiting = false;
} }

View File

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

View File

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