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

Resolve PR comments, fix load issue

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-09-30 13:07:16 -04:00
parent c73876170e
commit 63eca3f426
11 changed files with 86 additions and 88 deletions

View File

@ -286,7 +286,13 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
ensureObjectSelfLink(this.api, newItem); ensureObjectSelfLink(this.api, newItem);
return this.items[index] = newItem; if (index < 0) {
this.items.push(newItem);
} else {
this.items[index] = newItem;
}
return newItem;
} }
async patch(item: T, patch: Patch): Promise<T> { async patch(item: T, patch: Patch): Promise<T> {

View File

@ -192,7 +192,7 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
} }
/** /**
* These must be RFC6902 complient paths * These must be RFC6902 compliant paths
*/ */
private static readonly nonEditiablePathPrefixes = [ private static readonly nonEditiablePathPrefixes = [
"/metadata/managedFields", "/metadata/managedFields",
@ -209,6 +209,10 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
]); ]);
constructor(data: KubeJsonApiData) { constructor(data: KubeJsonApiData) {
if (typeof data !== "object") {
throw new TypeError(`Cannot create a KubeObject from ${typeof data}`);
}
Object.assign(this, data); Object.assign(this, data);
autoBind(this); autoBind(this);
} }
@ -311,8 +315,9 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
/** /**
* Perform a full update (or more specifically a replace) * Perform a full update (or more specifically a replace)
* *
* Note: this is brittle if `data` is not a object spread with the current * Note: this is brittle if `data` is not actually partial (but instead whole).
* fields as the `resourceVersion` maybe out of date. This is a common race condition. * As fields such as `resourceVersion` will probably out of date. This is a
* common race condition.
*/ */
async update(data: Partial<this>): Promise<KubeJsonApiData | null> { async update(data: Partial<this>): Promise<KubeJsonApiData | null> {
// use unified resource-applier api for updating all k8s objects // use unified resource-applier api for updating all k8s objects

View File

@ -62,7 +62,7 @@ export class ResourceApplier {
args.push( args.push(
"--type", "json", "--type", "json",
"--patch", JSON.stringify(patch), "--patch", JSON.stringify(patch),
"-o", "yaml" "-o", "json"
); );
try { try {
@ -93,18 +93,17 @@ export class ResourceApplier {
"-f", fileName, "-f", fileName,
]; ];
await fs.writeFile(fileName, content); logger.debug(`shooting manifests with ${kubectlPath}`, { args });
logger.debug(`shooting manifests with with ${kubectlPath}`, { args });
const execEnv = { ...process.env }; const execEnv = { ...process.env };
const httpsProxy = this.cluster.preferences?.httpsProxy; const httpsProxy = this.cluster.preferences?.httpsProxy;
if (httpsProxy) { if (httpsProxy) {
execEnv["HTTPS_PROXY"] = httpsProxy; execEnv.HTTPS_PROXY = httpsProxy;
} }
try { try {
await fs.writeFile(fileName, content);
const { stdout } = await promiseExecFile(kubectlPath, args); const { stdout } = await promiseExecFile(kubectlPath, args);
return stdout; return stdout;

View File

@ -40,7 +40,7 @@ export class ResourceApplierApiRoute {
const { response, cluster, payload } = request; const { response, cluster, payload } = request;
try { try {
const resource = await new ResourceApplier(cluster).patch(payload.name, payload.kind, payload.ns, payload.patch); const resource = await new ResourceApplier(cluster).patch(payload.name, payload.kind, payload.patch, payload.ns);
respondJson(response, resource, 200); respondJson(response, resource, 200);
} catch (error) { } catch (error) {

View File

@ -21,14 +21,37 @@
import type http from "http"; import type http from "http";
export function respondJson(res: http.ServerResponse, content: any, status = 200) { /**
respond(res, JSON.stringify(content), "application/json", status); * Respond to a HTTP request with a body of JSON data
* @param res The HTTP response to write data to
* @param content The data or its JSON stringified version of it
* @param status [200] The status code to respond with
*/
export function respondJson(res: http.ServerResponse, content: Object | string, status = 200) {
const normalizedContent = typeof content === "object"
? JSON.stringify(content)
: content;
respond(res, normalizedContent, "application/json", status);
} }
/**
* Respond to a HTTP request with a body of plain text data
* @param res The HTTP response to write data to
* @param content The string data to respond with
* @param status [200] The status code to respond with
*/
export function respondText(res: http.ServerResponse, content: string, status = 200) { export function respondText(res: http.ServerResponse, content: string, status = 200) {
respond(res, content, "text/plain", status); respond(res, content, "text/plain", status);
} }
/**
* Respond to a HTTP request with a body of plain text data
* @param res The HTTP response to write data to
* @param content The string data to respond with
* @param contentType The HTTP Content-Type header value
* @param status [200] The status code to respond with
*/
export function respond(res: http.ServerResponse, content: string, contentType: string, status = 200) { export function respond(res: http.ServerResponse, content: string, contentType: string, status = 200) {
res.setHeader("Content-Type", contentType); res.setHeader("Content-Type", contentType);
res.statusCode = status; res.statusCode = status;

View File

@ -72,6 +72,8 @@ export class ConfigMapDetails extends React.Component<Props> {
<>ConfigMap <b>{configMap.getName()}</b> successfully updated.</> <>ConfigMap <b>{configMap.getName()}</b> successfully updated.</>
</p> </p>
); );
} catch (error) {
Notifications.error(`Failed to save config map: ${error}`);
} finally { } finally {
this.isSaving = false; this.isSaving = false;
} }

View File

@ -34,9 +34,9 @@ import type { DockTab } from "./dock.store";
import { EditorPanel } from "./editor-panel"; import { EditorPanel } from "./editor-panel";
import { InfoPanel } from "./info-panel"; import { InfoPanel } from "./info-panel";
import * as resourceApplierApi from "../../../common/k8s-api/endpoints/resource-applier.api"; import * as resourceApplierApi from "../../../common/k8s-api/endpoints/resource-applier.api";
import type { JsonApiErrorParsed } from "../../../common/k8s-api/json-api";
import { Notifications } from "../notifications"; import { Notifications } from "../notifications";
import { monacoModelsManager } from "./monaco-model-manager"; import { monacoModelsManager } from "./monaco-model-manager";
import logger from "../../../common/logger";
interface Props { interface Props {
className?: string; className?: string;
@ -95,7 +95,7 @@ export class CreateResource extends React.Component<Props> {
}); });
}; };
create = async () => { create = async (): Promise<undefined> => {
if (this.error || !this.data.trim()) { if (this.error || !this.data.trim()) {
// 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;
@ -103,31 +103,31 @@ export class CreateResource extends React.Component<Props> {
// skip empty documents if "---" pasted at the beginning or end // skip empty documents if "---" pasted at the beginning or end
const resources = jsYaml.safeLoadAll(this.data).filter(Boolean); const resources = jsYaml.safeLoadAll(this.data).filter(Boolean);
const createdResources: string[] = [];
const errors: string[] = [];
await Promise.all( if (resources.length === 0) {
resources.map(data => { return void logger.info("Nothing to create");
return resourceApplierApi.update(data)
.then(item => createdResources.push(item.metadata.name))
.catch((err: JsonApiErrorParsed) => errors.push(err.toString()));
})
);
if (errors.length) {
errors.forEach(error => Notifications.error(error));
if (!createdResources.length) throw errors[0];
} }
const successMessage = (
<p>
{createdResources.length === 1 ? "Resource" : "Resources"}{" "}
<b>{createdResources.join(", ")}</b> successfully created
</p>
);
Notifications.ok(successMessage); const createdResources: string[] = [];
return successMessage; for (const result of await Promise.allSettled(resources.map(resourceApplierApi.update))) {
if (result.status === "fulfilled") {
createdResources.push(result.value.metadata.name);
} else {
Notifications.error(result.reason.toString());
}
}
if (createdResources.length > 0) {
Notifications.ok((
<p>
{createdResources.length === 1 ? "Resource" : "Resources"}{" "}
<b>{createdResources.join(", ")}</b> successfully created
</p>
));
}
return undefined;
}; };
renderControls(){ renderControls(){

View File

@ -98,9 +98,11 @@ export class EditResource extends React.Component<Props> {
return null; return null;
} }
const store = editResourceStore.getStore(this.tabId); const store = editResourceStore.getStore(this.tabId);
const currentEdit = yaml.safeLoad(this.draft); const currentVersion = yaml.safeLoad(this.draft);
const firstVersion = yaml.safeLoad(editResourceStore.getData(this.tabId).firstDraft ?? this.draft); const firstVersion = yaml.safeLoad(editResourceStore.getData(this.tabId).firstDraft ?? this.draft);
const patches = createPatch(firstVersion, currentEdit); const patches = createPatch(firstVersion, currentVersion);
console.log({ currentVersion, firstVersion, patches });
const updatedResource = await store.patch(this.resource, patches); const updatedResource = await store.patch(this.resource, patches);
return ( return (
@ -127,9 +129,9 @@ export class EditResource extends React.Component<Props> {
submittingMessage="Applying.." submittingMessage="Applying.."
controls={( controls={(
<div className="resource-info flex gaps align-center"> <div className="resource-info flex gaps align-center">
<span>Kind:</span> <Badge label={resource.kind}/> <span>Kind:</span><Badge label={resource.kind}/>
<span>Name:</span><Badge label={resource.getName()}/> <span>Name:</span><Badge label={resource.getName()}/>
<span>Namespace:</span> <Badge label={resource.getNs() || "global"}/> <span>Namespace:</span><Badge label={resource.getNs() || "global"}/>
</div> </div>
)} )}
/> />

View File

@ -91,10 +91,7 @@ export class EditorPanel extends React.Component<Props> {
onChange = (value: string) => { onChange = (value: string) => {
this.validate(value); this.validate(value);
this.props.onChange?.(value, this.yamlError);
if (this.props.onChange) {
this.props.onChange(value, this.yamlError);
}
}; };
render() { render() {

View File

@ -44,15 +44,11 @@ export class KubeObjectMenu<T extends KubeObject> extends React.Component<KubeOb
} }
get isEditable() { get isEditable() {
const { editable } = this.props; return this.props.editable ?? Boolean(this.store?.patch);
return editable !== undefined ? editable : !!(this.store && this.store.update);
} }
get isRemovable() { get isRemovable() {
const { removable } = this.props; return this.props.removable ?? Boolean(this.store?.remove);
return removable !== undefined ? removable : !!(this.store && this.store.remove);
} }
@boundMethod @boundMethod

View File

@ -4622,7 +4622,7 @@ debug@^3.0.0, debug@^3.1.1, debug@^3.2.6:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debuglog@*, debuglog@^1.0.1: debuglog@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@ -6315,7 +6315,7 @@ fs-extra@^9.0.0, fs-extra@^9.0.1:
jsonfile "^6.0.1" jsonfile "^6.0.1"
universalify "^2.0.0" universalify "^2.0.0"
fs-minipass@^1.2.7: fs-minipass@^1.2.5, fs-minipass@^1.2.7:
version "1.2.7" version "1.2.7"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz"
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
@ -7287,7 +7287,7 @@ import-local@^3.0.2:
pkg-dir "^4.2.0" pkg-dir "^4.2.0"
resolve-cwd "^3.0.0" resolve-cwd "^3.0.0"
imurmurhash@*, imurmurhash@^0.1.4: imurmurhash@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@ -9075,11 +9075,6 @@ lodash-es@^4.17.20:
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
lodash._baseuniq@~4.6.0: lodash._baseuniq@~4.6.0:
version "4.6.0" version "4.6.0"
resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz" resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz"
@ -9088,33 +9083,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0" lodash._createset "~4.0.0"
lodash._root "~3.0.0" lodash._root "~3.0.0"
lodash._bindcallback@*:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"
lodash._createset@~4.0.0: lodash._createset@~4.0.0:
version "4.0.3" version "4.0.3"
resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz" resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
lodash._getnative@*, lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
lodash._root@~3.0.0: lodash._root@~3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz" resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz"
@ -9140,11 +9113,6 @@ lodash.isequal@^4.5.0:
resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.restparam@*:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
lodash.sortby@^4.7.0: lodash.sortby@^4.7.0:
version "4.7.0" version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -9564,7 +9532,7 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
minipass@^2.3.5, minipass@^2.6.0, minipass@^2.9.0: minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
version "2.9.0" version "2.9.0"
resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz" resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz"
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
@ -9579,7 +9547,7 @@ minipass@^3.0.0:
dependencies: dependencies:
yallist "^4.0.0" yallist "^4.0.0"
minizlib@^1.3.3: minizlib@^1.2.1, minizlib@^1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz" resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz"
integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
@ -9628,7 +9596,7 @@ mkdirp@1.x, mkdirp@^1.0.3, mkdirp@~1.0.4:
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0: mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0:
version "0.5.5" version "0.5.5"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@ -14818,7 +14786,7 @@ yallist@^2.1.2:
resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz" resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3, yallist@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==