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);
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> {

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

View File

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

View File

@ -40,7 +40,7 @@ export class ResourceApplierApiRoute {
const { response, cluster, payload } = request;
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);
} catch (error) {

View File

@ -21,14 +21,37 @@
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) {
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) {
res.setHeader("Content-Type", contentType);
res.statusCode = status;

View File

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

View File

@ -34,9 +34,9 @@ import type { DockTab } from "./dock.store";
import { EditorPanel } from "./editor-panel";
import { InfoPanel } from "./info-panel";
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 { monacoModelsManager } from "./monaco-model-manager";
import logger from "../../../common/logger";
interface Props {
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()) {
// do not save when field is empty or there is an error
return null;
@ -103,31 +103,31 @@ export class CreateResource extends React.Component<Props> {
// skip empty documents if "---" pasted at the beginning or end
const resources = jsYaml.safeLoadAll(this.data).filter(Boolean);
const createdResources: string[] = [];
const errors: string[] = [];
await Promise.all(
resources.map(data => {
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];
if (resources.length === 0) {
return void logger.info("Nothing to create");
}
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(){

View File

@ -98,9 +98,11 @@ export class EditResource extends React.Component<Props> {
return null;
}
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 patches = createPatch(firstVersion, currentEdit);
const patches = createPatch(firstVersion, currentVersion);
console.log({ currentVersion, firstVersion, patches });
const updatedResource = await store.patch(this.resource, patches);
return (
@ -127,9 +129,9 @@ export class EditResource extends React.Component<Props> {
submittingMessage="Applying.."
controls={(
<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>Namespace:</span> <Badge label={resource.getNs() || "global"}/>
<span>Namespace:</span><Badge label={resource.getNs() || "global"}/>
</div>
)}
/>

View File

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

View File

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

View File

@ -4622,7 +4622,7 @@ debug@^3.0.0, debug@^3.1.1, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@ -6315,7 +6315,7 @@ fs-extra@^9.0.0, fs-extra@^9.0.1:
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-minipass@^1.2.7:
fs-minipass@^1.2.5, fs-minipass@^1.2.7:
version "1.2.7"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz"
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
@ -7287,7 +7287,7 @@ import-local@^3.0.2:
pkg-dir "^4.2.0"
resolve-cwd "^3.0.0"
imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
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"
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:
version "4.6.0"
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._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:
version "4.0.3"
resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz"
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:
version "3.0.1"
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"
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:
version "4.7.0"
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"
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"
resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz"
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
@ -9579,7 +9547,7 @@ minipass@^3.0.0:
dependencies:
yallist "^4.0.0"
minizlib@^1.3.3:
minizlib@^1.2.1, minizlib@^1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz"
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"
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"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
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"
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"
resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==