mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix editing of kube resource (#5906)
This commit is contained in:
parent
b94672b5a8
commit
e682c7de45
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,991 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
|
import type { RenderResult } from "@testing-library/react";
|
||||||
|
import { fireEvent } from "@testing-library/react";
|
||||||
|
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import navigateToNamespacesInjectable from "../../../common/front-end-routing/routes/cluster/namespaces/navigate-to-namespaces.injectable";
|
||||||
|
import React from "react";
|
||||||
|
import createEditResourceTabInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-tab.injectable";
|
||||||
|
import getRandomIdForEditResourceTabInjectable from "../../../renderer/components/dock/edit-resource/get-random-id-for-edit-resource-tab.injectable";
|
||||||
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
|
import asyncFn from "@async-fn/jest";
|
||||||
|
import type { CallForResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||||
|
import callForResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||||
|
import type { CallForPatchResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-patch-resource/call-for-patch-resource.injectable";
|
||||||
|
import callForPatchResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-patch-resource/call-for-patch-resource.injectable";
|
||||||
|
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
||||||
|
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||||
|
import showSuccessNotificationInjectable from "../../../renderer/components/notifications/show-success-notification.injectable";
|
||||||
|
import showErrorNotificationInjectable from "../../../renderer/components/notifications/show-error-notification.injectable";
|
||||||
|
import readJsonFileInjectable from "../../../common/fs/read-json-file.injectable";
|
||||||
|
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||||
|
import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
|
||||||
|
import { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready";
|
||||||
|
|
||||||
|
jest.mock("../../../renderer/components/tooltip/withTooltip", () => ({
|
||||||
|
withTooltip:
|
||||||
|
(Target: any) =>
|
||||||
|
({ tooltip, ...props }: any) => {
|
||||||
|
if (tooltip) {
|
||||||
|
const testId = props["data-testid"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Target
|
||||||
|
tooltip={tooltip.children ? undefined : tooltip}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
<div data-testid={testId && `tooltip-content-for-${testId}`}>
|
||||||
|
{tooltip.children || tooltip}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Target {...props} />;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("cluster/namespaces - edit namespace from new tab", () => {
|
||||||
|
let builder: ApplicationBuilder;
|
||||||
|
let callForNamespaceMock: AsyncFnMock<CallForResource>;
|
||||||
|
let callForPatchNamespaceMock: AsyncFnMock<CallForPatchResource>;
|
||||||
|
let showSuccessNotificationMock: jest.Mock;
|
||||||
|
let showErrorNotificationMock: jest.Mock;
|
||||||
|
let storagesAreReady: () => Promise<void>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
builder = getApplicationBuilder();
|
||||||
|
|
||||||
|
builder.setEnvironmentToClusterFrame();
|
||||||
|
|
||||||
|
callForNamespaceMock = asyncFn();
|
||||||
|
callForPatchNamespaceMock = asyncFn();
|
||||||
|
|
||||||
|
showSuccessNotificationMock = jest.fn();
|
||||||
|
showErrorNotificationMock = jest.fn();
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||||
|
rendererDi.override(
|
||||||
|
directoryForLensLocalStorageInjectable,
|
||||||
|
() => "/some-directory-for-lens-local-storage",
|
||||||
|
);
|
||||||
|
|
||||||
|
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||||
|
|
||||||
|
storagesAreReady = controlWhenStoragesAreReady(rendererDi);
|
||||||
|
|
||||||
|
rendererDi.override(
|
||||||
|
showSuccessNotificationInjectable,
|
||||||
|
() => showSuccessNotificationMock,
|
||||||
|
);
|
||||||
|
|
||||||
|
rendererDi.override(
|
||||||
|
showErrorNotificationInjectable,
|
||||||
|
() => showErrorNotificationMock,
|
||||||
|
);
|
||||||
|
|
||||||
|
rendererDi.override(getRandomIdForEditResourceTabInjectable, () =>
|
||||||
|
jest
|
||||||
|
.fn(() => "some-irrelevant-random-id")
|
||||||
|
.mockReturnValueOnce("some-first-tab-id")
|
||||||
|
.mockReturnValueOnce("some-second-tab-id"),
|
||||||
|
);
|
||||||
|
|
||||||
|
rendererDi.override(callForResourceInjectable, () => async (selfLink: string) => {
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/apis/some-api-version/namespaces/some-uid",
|
||||||
|
"/apis/some-api-version/namespaces/some-other-uid",
|
||||||
|
].includes(selfLink)
|
||||||
|
) {
|
||||||
|
return await callForNamespaceMock(selfLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
rendererDi.override(callForPatchResourceInjectable, () => async (namespace, ...args) => {
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/apis/some-api-version/namespaces/some-uid",
|
||||||
|
"/apis/some-api-version/namespaces/some-other-uid",
|
||||||
|
].includes(namespace.selfLink)
|
||||||
|
) {
|
||||||
|
return await callForPatchNamespaceMock(namespace, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.allowKubeResource("namespaces");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when navigating to namespaces", () => {
|
||||||
|
let rendered: RenderResult;
|
||||||
|
let rendererDi: DiContainer;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
rendered = await builder.render();
|
||||||
|
|
||||||
|
await storagesAreReady();
|
||||||
|
|
||||||
|
rendererDi = builder.dis.rendererDi;
|
||||||
|
|
||||||
|
const navigateToNamespaces = rendererDi.inject(
|
||||||
|
navigateToNamespacesInjectable,
|
||||||
|
);
|
||||||
|
|
||||||
|
navigateToNamespaces();
|
||||||
|
|
||||||
|
const dockStore = rendererDi.inject(dockStoreInjectable);
|
||||||
|
|
||||||
|
// TODO: Make TerminalWindow unit testable to allow realistic behaviour
|
||||||
|
dockStore.closeTab("terminal");
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Implement skipped tests when loading of resources can be tested
|
||||||
|
xit("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("calls for namespaces", () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("shows spinner", () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when namespaces resolve", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("does not show spinner anymore", () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when clicking the context menu for a namespace", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("does not show edit resource tab yet", () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when clicking to edit namespace", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// TODO: Make implementation match the description (tests above)
|
||||||
|
const namespaceStub = new Namespace(someNamespaceDataStub);
|
||||||
|
|
||||||
|
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable);
|
||||||
|
|
||||||
|
createEditResourceTab(namespaceStub);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows dock tab for editing namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows spinner in the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for namespace", () => {
|
||||||
|
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
"/apis/some-api-version/namespaces/some-uid",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when call for namespace resolves with namespace", () => {
|
||||||
|
let someNamespace: Namespace;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
someNamespace = new Namespace({
|
||||||
|
apiVersion: "some-api-version",
|
||||||
|
kind: "Namespace",
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
uid: "some-uid",
|
||||||
|
name: "some-name",
|
||||||
|
resourceVersion: "some-resource-version",
|
||||||
|
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||||
|
somePropertyToBeRemoved: "some-value",
|
||||||
|
somePropertyToBeChanged: "some-old-value",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await callForNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: someNamespace,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show spinner anymore", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has the configuration in editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe(`apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeRemoved: some-value
|
||||||
|
somePropertyToBeChanged: some-old-value
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given no changes in the configuration, when selecting to save", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for save with empty values", () => {
|
||||||
|
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
someNamespace,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows spinner", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("saving-edit-resource-from-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save button is disabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save and close button is disabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when saving resolves with success", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForPatchNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: { name: "some-name", kind: "Namespace" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show spinner anymore", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("saving-edit-resource-from-tab-for-some-first-tab-id"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save and close button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows success notification", () => {
|
||||||
|
expect(showSuccessNotificationMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show error notification", () => {
|
||||||
|
expect(showErrorNotificationMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not close the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when saving resolves with failure", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForPatchNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: "some-error",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show spinner anymore", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save and close button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show success notification", () => {
|
||||||
|
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows error notification", () => {
|
||||||
|
expect(showErrorNotificationMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not close the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when selecting to save and close", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not close the tab yet", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when saving resolves with success", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForPatchNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: { name: "some-name", kind: "Namespace" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("closes the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when saving resolves with failure", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForPatchNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: "Some error",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Not doable at the moment because info panel controls closing of the tab
|
||||||
|
xit("does not close the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when selecting to cancel", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const cancelButton = rendered.getByTestId(
|
||||||
|
"cancel-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(cancelButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not have dock tab anymore", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given change in configuration", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
fireEvent.change(input, {
|
||||||
|
target: {
|
||||||
|
value: `apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeChanged: some-changed-value
|
||||||
|
someAddedProperty: some-new-value
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has the changed configuration in editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe(`apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeChanged: some-changed-value
|
||||||
|
someAddedProperty: some-new-value
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stores the changed configuration", async () => {
|
||||||
|
const readJsonFile = rendererDi.inject(
|
||||||
|
readJsonFileInjectable,
|
||||||
|
);
|
||||||
|
|
||||||
|
const actual = (await readJsonFile(
|
||||||
|
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
actual.edit_resource_store["some-first-tab-id"],
|
||||||
|
).toEqual({
|
||||||
|
resource: "/apis/some-api-version/namespaces/some-uid",
|
||||||
|
firstDraft: `apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeRemoved: some-value
|
||||||
|
somePropertyToBeChanged: some-old-value
|
||||||
|
`,
|
||||||
|
draft: `apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeChanged: some-changed-value
|
||||||
|
someAddedProperty: some-new-value
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when selecting to save", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for save with changed configuration", () => {
|
||||||
|
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
someNamespace,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
op: "remove",
|
||||||
|
path: "/metadata/somePropertyToBeRemoved",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "add",
|
||||||
|
path: "/metadata/someAddedProperty",
|
||||||
|
value: "some-new-value",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "replace",
|
||||||
|
path: "/metadata/somePropertyToBeChanged",
|
||||||
|
value: "some-changed-value",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("given save resolves and another change in configuration, when saving, calls for save with changed configuration", async () => {
|
||||||
|
await callForPatchNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
|
||||||
|
response: {
|
||||||
|
name: "some-name",
|
||||||
|
kind: "Namespace",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
fireEvent.change(input, {
|
||||||
|
target: {
|
||||||
|
value: `apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeChanged: some-changed-value
|
||||||
|
someAddedProperty: some-new-value
|
||||||
|
someOtherAddedProperty: some-other-new-value
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
callForPatchNamespaceMock.mockClear();
|
||||||
|
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
someNamespace,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
op: "add",
|
||||||
|
path: "/metadata/someOtherAddedProperty",
|
||||||
|
value: "some-other-new-value",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given invalid change in configuration", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
fireEvent.change(input, {
|
||||||
|
target: {
|
||||||
|
value: "@some-invalid-configuration@",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has the changed configuration in editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe(`@some-invalid-configuration@`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save button is disabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save and close button is disabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when valid change in configuration", () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
|
||||||
|
fireEvent.change(input, {
|
||||||
|
target: {
|
||||||
|
value: `apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("save and close button is enabled", () => {
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(saveButton).not.toHaveAttribute("disabled");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given clicking the context menu for second namespace, when clicking to edit namespace", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
callForNamespaceMock.mockClear();
|
||||||
|
|
||||||
|
// TODO: Make implementation match the description
|
||||||
|
const namespaceStub = new Namespace(someOtherNamespaceDataStub);
|
||||||
|
|
||||||
|
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable);
|
||||||
|
|
||||||
|
createEditResourceTab(namespaceStub);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows dock tab for editing second namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-content-for-some-second-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still has dock tab for first namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows spinner in the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for second namespace", () => {
|
||||||
|
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
"/apis/some-api-version/namespaces/some-other-uid",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when second namespace resolves", () => {
|
||||||
|
let someOtherNamespace: Namespace;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
someOtherNamespace = new Namespace({
|
||||||
|
apiVersion: "some-api-version",
|
||||||
|
kind: "Namespace",
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
uid: "some-other-uid",
|
||||||
|
name: "some-other-name",
|
||||||
|
resourceVersion: "some-resource-version",
|
||||||
|
selfLink:
|
||||||
|
"/apis/some-api-version/namespaces/some-other-uid",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await callForNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: someOtherNamespace,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has the configuration in editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-second-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe(`apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-other-uid
|
||||||
|
name: some-other-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-other-uid
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when selecting to save, calls for save of second namespace", () => {
|
||||||
|
callForPatchNamespaceMock.mockClear();
|
||||||
|
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-second-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
someOtherNamespace,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when clicking dock tab for the first namespace", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
callForNamespaceMock.mockClear();
|
||||||
|
|
||||||
|
const tab = rendered.getByTestId("dock-tab-for-some-first-tab-id");
|
||||||
|
|
||||||
|
fireEvent.click(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows dock tab for editing first namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still has dock tab for second namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-second-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show spinner in the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not call for namespace", () => {
|
||||||
|
expect(callForNamespaceMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has configuration in the editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe(`apiVersion: some-api-version
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
uid: some-uid
|
||||||
|
name: some-name
|
||||||
|
resourceVersion: some-resource-version
|
||||||
|
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||||
|
somePropertyToBeRemoved: some-value
|
||||||
|
somePropertyToBeChanged: some-old-value
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when selecting to save, calls for save of first namespace", () => {
|
||||||
|
callForPatchNamespaceMock.mockClear();
|
||||||
|
|
||||||
|
const saveButton = rendered.getByTestId(
|
||||||
|
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
someNamespace,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when call for namespace resolves without namespace", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows the dock tab for editing namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows error message", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||||
|
).toHaveTextContent("Resource not found");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show error notification", () => {
|
||||||
|
expect(showErrorNotificationMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when call for namespace resolves with failure", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await callForNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: "some-error",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows the dock tab for editing namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows error message", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||||
|
).toHaveTextContent("Resource not found");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows error notification", () => {
|
||||||
|
expect(showErrorNotificationMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const someNamespaceDataStub = {
|
||||||
|
apiVersion: "some-api-version",
|
||||||
|
kind: "Namespace",
|
||||||
|
metadata: {
|
||||||
|
uid: "some-uid",
|
||||||
|
name: "some-name",
|
||||||
|
resourceVersion: "some-resource-version",
|
||||||
|
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const someOtherNamespaceDataStub = {
|
||||||
|
apiVersion: "some-api-version",
|
||||||
|
kind: "Namespace",
|
||||||
|
metadata: {
|
||||||
|
uid: "some-other-uid",
|
||||||
|
name: "some-other-name",
|
||||||
|
resourceVersion: "some-resource-version",
|
||||||
|
selfLink: "/apis/some-api-version/namespaces/some-other-uid",
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { RenderResult } from "@testing-library/react";
|
||||||
|
import { act } from "@testing-library/react";
|
||||||
|
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import React from "react";
|
||||||
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
|
import asyncFn from "@async-fn/jest";
|
||||||
|
import type { CallForResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||||
|
import callForResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||||
|
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||||
|
import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
|
||||||
|
import { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready";
|
||||||
|
import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable";
|
||||||
|
import { TabKind } from "../../../renderer/components/dock/dock/store";
|
||||||
|
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||||
|
|
||||||
|
jest.mock("../../../renderer/components/tooltip/withTooltip", () => ({
|
||||||
|
withTooltip:
|
||||||
|
(Target: any) =>
|
||||||
|
({ tooltip, ...props }: any) => {
|
||||||
|
if (tooltip) {
|
||||||
|
const testId = props["data-testid"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Target
|
||||||
|
tooltip={tooltip.children ? undefined : tooltip}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
<div data-testid={testId && `tooltip-content-for-${testId}`}>
|
||||||
|
{tooltip.children || tooltip}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Target {...props} />;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("cluster/namespaces - edit namespaces from previously opened tab", () => {
|
||||||
|
let builder: ApplicationBuilder;
|
||||||
|
let callForNamespaceMock: AsyncFnMock<CallForResource>;
|
||||||
|
let storagesAreReady: () => Promise<void>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
builder = getApplicationBuilder();
|
||||||
|
|
||||||
|
builder.setEnvironmentToClusterFrame();
|
||||||
|
|
||||||
|
callForNamespaceMock = asyncFn();
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||||
|
rendererDi.override(
|
||||||
|
directoryForLensLocalStorageInjectable,
|
||||||
|
() => "/some-directory-for-lens-local-storage",
|
||||||
|
);
|
||||||
|
|
||||||
|
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||||
|
|
||||||
|
storagesAreReady = controlWhenStoragesAreReady(rendererDi);
|
||||||
|
|
||||||
|
rendererDi.override(callForResourceInjectable, () => callForNamespaceMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.allowKubeResource("namespaces");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given tab was previously opened, when application is started", () => {
|
||||||
|
let rendered: RenderResult;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const writeJsonFile = builder.dis.rendererDi.inject(writeJsonFileInjectable);
|
||||||
|
|
||||||
|
await writeJsonFile(
|
||||||
|
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||||
|
{
|
||||||
|
dock: {
|
||||||
|
height: 300,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
id: "some-first-tab-id",
|
||||||
|
kind: TabKind.EDIT_RESOURCE,
|
||||||
|
title: "Namespace: some-namespace",
|
||||||
|
pinned: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
isOpen: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
edit_resource_store: {
|
||||||
|
"some-first-tab-id": {
|
||||||
|
resource: "/apis/some-api-version/namespaces/some-uid",
|
||||||
|
draft: "some-saved-configuration",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
rendered = await builder.render();
|
||||||
|
|
||||||
|
await storagesAreReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows dock tab for editing namespace", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows spinner in the dock tab", () => {
|
||||||
|
expect(
|
||||||
|
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls for namespace", () => {
|
||||||
|
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||||
|
"/apis/some-api-version/namespaces/some-uid",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when call for namespace resolves with namespace", () => {
|
||||||
|
let someNamespace: Namespace;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
someNamespace = new Namespace({
|
||||||
|
apiVersion: "some-api-version",
|
||||||
|
kind: "Namespace",
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
uid: "some-uid",
|
||||||
|
name: "some-name",
|
||||||
|
resourceVersion: "some-resource-version",
|
||||||
|
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||||
|
somePropertyToBeRemoved: "some-value",
|
||||||
|
somePropertyToBeChanged: "some-old-value",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Figure out why act is needed here. In CI it works without it.
|
||||||
|
await act(async () => {
|
||||||
|
await callForNamespaceMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: someNamespace,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has the saved configuration in editor", () => {
|
||||||
|
const input = rendered.getByTestId(
|
||||||
|
"monaco-editor-for-some-first-tab-id",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
|
||||||
|
expect(input.value).toBe("some-saved-configuration");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -2644,10 +2644,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -3651,10 +3652,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
class="Spinner singleColor center"
|
class="Spinner singleColor center"
|
||||||
data-testid="install-chart-configuration-spinner"
|
data-testid="install-chart-configuration-spinner"
|
||||||
/>
|
/>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -4624,10 +4626,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration-for-other-version"
|
>
|
||||||
/>
|
some-default-configuration-for-other-version
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -5597,10 +5600,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -6590,10 +6594,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="@some-invalid-configuration@"
|
>
|
||||||
/>
|
@some-invalid-configuration@
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -7565,10 +7570,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -8567,10 +8573,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9548,10 +9555,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -13030,10 +13038,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -15102,10 +15111,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-second-tab-id"
|
data-testid="monaco-editor-for-some-second-tab-id"
|
||||||
value="some-other-default-configuration"
|
>
|
||||||
/>
|
some-other-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -16122,10 +16132,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -17095,10 +17106,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-valid-configuration"
|
>
|
||||||
/>
|
some-valid-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -18068,10 +18080,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-default-configuration"
|
>
|
||||||
/>
|
some-default-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1243,10 +1243,11 @@ exports[`installing helm chart from previously opened tab given tab for installi
|
|||||||
Install
|
Install
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-some-first-tab-id"
|
data-testid="monaco-editor-for-some-first-tab-id"
|
||||||
value="some-stored-configuration"
|
>
|
||||||
/>
|
some-stored-configuration
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7336,10 +7336,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-configuration"
|
>
|
||||||
/>
|
some-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button primary"
|
class="Button primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
@ -8555,10 +8556,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-new-configuration"
|
>
|
||||||
/>
|
some-new-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button primary"
|
class="Button primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
@ -9774,10 +9776,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-new-configuration"
|
>
|
||||||
/>
|
some-new-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button waiting primary"
|
class="Button waiting primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
@ -10820,10 +10823,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-new-configuration"
|
>
|
||||||
/>
|
some-new-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button primary"
|
class="Button primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
@ -11867,10 +11871,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-new-configuration"
|
>
|
||||||
/>
|
some-new-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button primary"
|
class="Button primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
@ -13087,10 +13092,11 @@ exports[`showing details for helm release given application is started when navi
|
|||||||
User-supplied values only
|
User-supplied values only
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<textarea
|
||||||
data-testid="monaco-editor-for-helm-release-configuration"
|
data-testid="monaco-editor-for-helm-release-configuration"
|
||||||
value="some-other-configuration"
|
>
|
||||||
/>
|
some-other-configuration
|
||||||
|
</textarea>
|
||||||
<button
|
<button
|
||||||
class="Button primary"
|
class="Button primary"
|
||||||
data-testid="helm-release-configuration-save-button"
|
data-testid="helm-release-configuration-save-button"
|
||||||
|
|||||||
20
src/common/cluster/is-allowed-resource.ts
Normal file
20
src/common/cluster/is-allowed-resource.ts
Normal 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 type { KubeResource } from "../rbac";
|
||||||
|
import { apiResourceRecord, apiResources } from "../rbac";
|
||||||
|
|
||||||
|
export const isAllowedResource = (allowedResources: string[]) => (kind: string): boolean => {
|
||||||
|
if ((kind as KubeResource) in apiResourceRecord) {
|
||||||
|
return allowedResources.includes(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiResource = apiResources.find(resource => resource.kind === kind);
|
||||||
|
|
||||||
|
if (apiResource) {
|
||||||
|
return allowedResources.includes(apiResource.apiName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // allowed by default for other resources
|
||||||
|
};
|
||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ClusterRoleBindingApi } from "./cluster-role-binding.api";
|
import { ClusterRoleBindingApi } from "./cluster-role-binding.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const clusterRoleBindingApiInjectable = getInjectable({
|
const clusterRoleBindingApiInjectable = getInjectable({
|
||||||
id: "cluster-role-binding-api",
|
id: "cluster-role-binding-api",
|
||||||
@ -14,6 +15,8 @@ const clusterRoleBindingApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ClusterRoleBindingApi();
|
return new ClusterRoleBindingApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default clusterRoleBindingApiInjectable;
|
export default clusterRoleBindingApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ClusterRoleApi } from "./cluster-role.api";
|
import { ClusterRoleApi } from "./cluster-role.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const clusterRoleApiInjectable = getInjectable({
|
const clusterRoleApiInjectable = getInjectable({
|
||||||
id: "cluster-role-api",
|
id: "cluster-role-api",
|
||||||
@ -14,6 +15,8 @@ const clusterRoleApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ClusterRoleApi();
|
return new ClusterRoleApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default clusterRoleApiInjectable;
|
export default clusterRoleApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ClusterApi } from "./cluster.api";
|
import { ClusterApi } from "./cluster.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const clusterApiInjectable = getInjectable({
|
const clusterApiInjectable = getInjectable({
|
||||||
id: "cluster-api",
|
id: "cluster-api",
|
||||||
@ -14,6 +15,8 @@ const clusterApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ClusterApi();
|
return new ClusterApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default clusterApiInjectable;
|
export default clusterApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ComponentStatusApi } from "./component-status.api";
|
import { ComponentStatusApi } from "./component-status.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const componentStatusApiInjectable = getInjectable({
|
const componentStatusApiInjectable = getInjectable({
|
||||||
id: "component-status-api",
|
id: "component-status-api",
|
||||||
@ -14,6 +15,8 @@ const componentStatusApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ComponentStatusApi();
|
return new ComponentStatusApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default componentStatusApiInjectable;
|
export default componentStatusApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ConfigMapApi } from "./config-map.api";
|
import { ConfigMapApi } from "./config-map.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const configMapApiInjectable = getInjectable({
|
const configMapApiInjectable = getInjectable({
|
||||||
id: "config-map-api",
|
id: "config-map-api",
|
||||||
@ -14,6 +15,8 @@ const configMapApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ConfigMapApi();
|
return new ConfigMapApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default configMapApiInjectable;
|
export default configMapApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { CronJobApi } from "./cron-job.api";
|
import { CronJobApi } from "./cron-job.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const cronJobApiInjectable = getInjectable({
|
const cronJobApiInjectable = getInjectable({
|
||||||
id: "cron-job-api",
|
id: "cron-job-api",
|
||||||
@ -14,6 +15,8 @@ const cronJobApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new CronJobApi();
|
return new CronJobApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default cronJobApiInjectable;
|
export default cronJobApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { CustomResourceDefinitionApi } from "./custom-resource-definition.api";
|
import { CustomResourceDefinitionApi } from "./custom-resource-definition.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const customResourceDefinitionApiInjectable = getInjectable({
|
const customResourceDefinitionApiInjectable = getInjectable({
|
||||||
id: "custom-resource-definition-api",
|
id: "custom-resource-definition-api",
|
||||||
@ -14,6 +15,8 @@ const customResourceDefinitionApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new CustomResourceDefinitionApi();
|
return new CustomResourceDefinitionApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default customResourceDefinitionApiInjectable;
|
export default customResourceDefinitionApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { DaemonSetApi } from "./daemon-set.api";
|
import { DaemonSetApi } from "./daemon-set.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const daemonSetApiInjectable = getInjectable({
|
const daemonSetApiInjectable = getInjectable({
|
||||||
id: "daemon-set-api",
|
id: "daemon-set-api",
|
||||||
@ -14,6 +15,8 @@ const daemonSetApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new DaemonSetApi();
|
return new DaemonSetApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default daemonSetApiInjectable;
|
export default daemonSetApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { DeploymentApi } from "./deployment.api";
|
import { DeploymentApi } from "./deployment.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const deploymentApiInjectable = getInjectable({
|
const deploymentApiInjectable = getInjectable({
|
||||||
id: "deployment-api",
|
id: "deployment-api",
|
||||||
@ -14,6 +15,8 @@ const deploymentApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new DeploymentApi();
|
return new DeploymentApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default deploymentApiInjectable;
|
export default deploymentApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { EndpointsApi } from "./endpoint.api";
|
import { EndpointsApi } from "./endpoint.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const endpointsApiInjectable = getInjectable({
|
const endpointsApiInjectable = getInjectable({
|
||||||
id: "endpoints-api",
|
id: "endpoints-api",
|
||||||
@ -14,6 +15,8 @@ const endpointsApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new EndpointsApi();
|
return new EndpointsApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default endpointsApiInjectable;
|
export default endpointsApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { KubeEventApi } from "./events.api";
|
import { KubeEventApi } from "./events.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const kubeEventApiInjectable = getInjectable({
|
const kubeEventApiInjectable = getInjectable({
|
||||||
id: "kube-event-api",
|
id: "kube-event-api",
|
||||||
@ -14,6 +15,8 @@ const kubeEventApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new KubeEventApi();
|
return new KubeEventApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default kubeEventApiInjectable;
|
export default kubeEventApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { HorizontalPodAutoscalerApi } from "./horizontal-pod-autoscaler.api";
|
import { HorizontalPodAutoscalerApi } from "./horizontal-pod-autoscaler.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const horizontalPodAutoscalerApiInjectable = getInjectable({
|
const horizontalPodAutoscalerApiInjectable = getInjectable({
|
||||||
id: "horizontal-pod-autoscaler-api",
|
id: "horizontal-pod-autoscaler-api",
|
||||||
@ -14,6 +15,8 @@ const horizontalPodAutoscalerApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new HorizontalPodAutoscalerApi();
|
return new HorizontalPodAutoscalerApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default horizontalPodAutoscalerApiInjectable;
|
export default horizontalPodAutoscalerApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { IngressApi } from "./ingress.api";
|
import { IngressApi } from "./ingress.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const ingressApiInjectable = getInjectable({
|
const ingressApiInjectable = getInjectable({
|
||||||
id: "ingress-api",
|
id: "ingress-api",
|
||||||
@ -14,6 +15,8 @@ const ingressApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new IngressApi();
|
return new IngressApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ingressApiInjectable;
|
export default ingressApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { JobApi } from "./job.api";
|
import { JobApi } from "./job.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const jobApiInjectable = getInjectable({
|
const jobApiInjectable = getInjectable({
|
||||||
id: "job-api",
|
id: "job-api",
|
||||||
@ -14,6 +15,8 @@ const jobApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new JobApi();
|
return new JobApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default jobApiInjectable;
|
export default jobApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { LimitRangeApi } from "./limit-range.api";
|
import { LimitRangeApi } from "./limit-range.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const limitRangeApiInjectable = getInjectable({
|
const limitRangeApiInjectable = getInjectable({
|
||||||
id: "limit-range-api",
|
id: "limit-range-api",
|
||||||
@ -14,6 +15,8 @@ const limitRangeApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new LimitRangeApi();
|
return new LimitRangeApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default limitRangeApiInjectable;
|
export default limitRangeApiInjectable;
|
||||||
|
|||||||
@ -6,14 +6,18 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { NamespaceApi } from "./namespace.api";
|
import { NamespaceApi } from "./namespace.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const namespaceApiInjectable = getInjectable({
|
const namespaceApiInjectable = getInjectable({
|
||||||
id: "namespace-api",
|
id: "namespace-api",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "namespaceApi is only available in certain environments");
|
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "namespaceApi is only available in certain environments");
|
||||||
|
|
||||||
return new NamespaceApi();
|
return new NamespaceApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default namespaceApiInjectable;
|
export default namespaceApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { NetworkPolicyApi } from "./network-policy.api";
|
import { NetworkPolicyApi } from "./network-policy.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const networkPolicyApiInjectable = getInjectable({
|
const networkPolicyApiInjectable = getInjectable({
|
||||||
id: "network-policy-api",
|
id: "network-policy-api",
|
||||||
@ -14,6 +15,8 @@ const networkPolicyApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new NetworkPolicyApi();
|
return new NetworkPolicyApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default networkPolicyApiInjectable;
|
export default networkPolicyApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { NodeApi } from "./node.api";
|
import { NodeApi } from "./node.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const nodeApiInjectable = getInjectable({
|
const nodeApiInjectable = getInjectable({
|
||||||
id: "node-api",
|
id: "node-api",
|
||||||
@ -14,6 +15,8 @@ const nodeApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new NodeApi();
|
return new NodeApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default nodeApiInjectable;
|
export default nodeApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PersistentVolumeClaimApi } from "./persistent-volume-claim.api";
|
import { PersistentVolumeClaimApi } from "./persistent-volume-claim.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const persistentVolumeClaimApiInjectable = getInjectable({
|
const persistentVolumeClaimApiInjectable = getInjectable({
|
||||||
id: "persistent-volume-claim-api",
|
id: "persistent-volume-claim-api",
|
||||||
@ -14,6 +15,8 @@ const persistentVolumeClaimApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PersistentVolumeClaimApi();
|
return new PersistentVolumeClaimApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default persistentVolumeClaimApiInjectable;
|
export default persistentVolumeClaimApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PersistentVolumeApi } from "./persistent-volume.api";
|
import { PersistentVolumeApi } from "./persistent-volume.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const persistentVolumeApiInjectable = getInjectable({
|
const persistentVolumeApiInjectable = getInjectable({
|
||||||
id: "persistent-volume-api",
|
id: "persistent-volume-api",
|
||||||
@ -14,6 +15,8 @@ const persistentVolumeApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PersistentVolumeApi();
|
return new PersistentVolumeApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default persistentVolumeApiInjectable;
|
export default persistentVolumeApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PodDisruptionBudgetApi } from "./pod-disruption-budget.api";
|
import { PodDisruptionBudgetApi } from "./pod-disruption-budget.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const podDisruptionBudgetApiInjectable = getInjectable({
|
const podDisruptionBudgetApiInjectable = getInjectable({
|
||||||
id: "pod-disruption-budget-api",
|
id: "pod-disruption-budget-api",
|
||||||
@ -14,6 +15,8 @@ const podDisruptionBudgetApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PodDisruptionBudgetApi();
|
return new PodDisruptionBudgetApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default podDisruptionBudgetApiInjectable;
|
export default podDisruptionBudgetApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PodMetricsApi } from "./pod-metrics.api";
|
import { PodMetricsApi } from "./pod-metrics.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const podMetricsApiInjectable = getInjectable({
|
const podMetricsApiInjectable = getInjectable({
|
||||||
id: "pod-metrics-api",
|
id: "pod-metrics-api",
|
||||||
@ -14,6 +15,8 @@ const podMetricsApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PodMetricsApi();
|
return new PodMetricsApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default podMetricsApiInjectable;
|
export default podMetricsApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PodSecurityPolicyApi } from "./pod-security-policy.api";
|
import { PodSecurityPolicyApi } from "./pod-security-policy.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const podSecurityPolicyApiInjectable = getInjectable({
|
const podSecurityPolicyApiInjectable = getInjectable({
|
||||||
id: "pod-security-policy-api",
|
id: "pod-security-policy-api",
|
||||||
@ -14,6 +15,8 @@ const podSecurityPolicyApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PodSecurityPolicyApi();
|
return new PodSecurityPolicyApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default podSecurityPolicyApiInjectable;
|
export default podSecurityPolicyApiInjectable;
|
||||||
|
|||||||
@ -6,14 +6,18 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PodApi } from "./pod.api";
|
import { PodApi } from "./pod.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const podApiInjectable = getInjectable({
|
const podApiInjectable = getInjectable({
|
||||||
id: "pod-api",
|
id: "pod-api",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "podApi is only available in certain environments");
|
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "podApi is only available in certain environments");
|
||||||
|
|
||||||
return new PodApi();
|
return new PodApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default podApiInjectable;
|
export default podApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { PriorityClassApi } from "./priority-class.api";
|
import { PriorityClassApi } from "./priority-class.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const priorityClassApiInjectable = getInjectable({
|
const priorityClassApiInjectable = getInjectable({
|
||||||
id: "priority-class-api",
|
id: "priority-class-api",
|
||||||
@ -14,6 +15,8 @@ const priorityClassApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new PriorityClassApi();
|
return new PriorityClassApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default priorityClassApiInjectable;
|
export default priorityClassApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ReplicaSetApi } from "./replica-set.api";
|
import { ReplicaSetApi } from "./replica-set.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const replicaSetApiInjectable = getInjectable({
|
const replicaSetApiInjectable = getInjectable({
|
||||||
id: "replica-set-api",
|
id: "replica-set-api",
|
||||||
@ -14,6 +15,8 @@ const replicaSetApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ReplicaSetApi();
|
return new ReplicaSetApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default replicaSetApiInjectable;
|
export default replicaSetApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ResourceQuotaApi } from "./resource-quota.api";
|
import { ResourceQuotaApi } from "./resource-quota.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const resourceQuotaApiInjectable = getInjectable({
|
const resourceQuotaApiInjectable = getInjectable({
|
||||||
id: "resource-quota-api",
|
id: "resource-quota-api",
|
||||||
@ -14,6 +15,8 @@ const resourceQuotaApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ResourceQuotaApi();
|
return new ResourceQuotaApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default resourceQuotaApiInjectable;
|
export default resourceQuotaApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { RoleBindingApi } from "./role-binding.api";
|
import { RoleBindingApi } from "./role-binding.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const roleBindingApiInjectable = getInjectable({
|
const roleBindingApiInjectable = getInjectable({
|
||||||
id: "role-binding-api",
|
id: "role-binding-api",
|
||||||
@ -14,6 +15,8 @@ const roleBindingApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new RoleBindingApi();
|
return new RoleBindingApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default roleBindingApiInjectable;
|
export default roleBindingApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { RoleApi } from "./role.api";
|
import { RoleApi } from "./role.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const roleApiInjectable = getInjectable({
|
const roleApiInjectable = getInjectable({
|
||||||
id: "role-api",
|
id: "role-api",
|
||||||
@ -14,6 +15,8 @@ const roleApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new RoleApi();
|
return new RoleApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default roleApiInjectable;
|
export default roleApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { SecretApi } from "./secret.api";
|
import { SecretApi } from "./secret.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const secretApiInjectable = getInjectable({
|
const secretApiInjectable = getInjectable({
|
||||||
id: "secret-api",
|
id: "secret-api",
|
||||||
@ -14,6 +15,8 @@ const secretApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new SecretApi();
|
return new SecretApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default secretApiInjectable;
|
export default secretApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { SelfSubjectRulesReviewApi } from "./self-subject-rules-reviews.api";
|
import { SelfSubjectRulesReviewApi } from "./self-subject-rules-reviews.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const selfSubjectRulesReviewApiInjectable = getInjectable({
|
const selfSubjectRulesReviewApiInjectable = getInjectable({
|
||||||
id: "self-subject-rules-review-api",
|
id: "self-subject-rules-review-api",
|
||||||
@ -14,6 +15,8 @@ const selfSubjectRulesReviewApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new SelfSubjectRulesReviewApi();
|
return new SelfSubjectRulesReviewApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default selfSubjectRulesReviewApiInjectable;
|
export default selfSubjectRulesReviewApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ServiceAccountApi } from "./service-account.api";
|
import { ServiceAccountApi } from "./service-account.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const serviceAccountApiInjectable = getInjectable({
|
const serviceAccountApiInjectable = getInjectable({
|
||||||
id: "service-account-api",
|
id: "service-account-api",
|
||||||
@ -14,6 +15,8 @@ const serviceAccountApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ServiceAccountApi();
|
return new ServiceAccountApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default serviceAccountApiInjectable;
|
export default serviceAccountApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { ServiceApi } from "./service.api";
|
import { ServiceApi } from "./service.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const serviceApiInjectable = getInjectable({
|
const serviceApiInjectable = getInjectable({
|
||||||
id: "service-api",
|
id: "service-api",
|
||||||
@ -14,6 +15,8 @@ const serviceApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new ServiceApi();
|
return new ServiceApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default serviceApiInjectable;
|
export default serviceApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { StatefulSetApi } from "./stateful-set.api";
|
import { StatefulSetApi } from "./stateful-set.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const statefulSetApiInjectable = getInjectable({
|
const statefulSetApiInjectable = getInjectable({
|
||||||
id: "stateful-set-api",
|
id: "stateful-set-api",
|
||||||
@ -14,6 +15,8 @@ const statefulSetApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new StatefulSetApi();
|
return new StatefulSetApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default statefulSetApiInjectable;
|
export default statefulSetApiInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
import { StorageClassApi } from "./storage-class.api";
|
import { StorageClassApi } from "./storage-class.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
const storageClassApiInjectable = getInjectable({
|
const storageClassApiInjectable = getInjectable({
|
||||||
id: "storage-class-api",
|
id: "storage-class-api",
|
||||||
@ -14,6 +15,8 @@ const storageClassApiInjectable = getInjectable({
|
|||||||
|
|
||||||
return new StorageClassApi();
|
return new StorageClassApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default storageClassApiInjectable;
|
export default storageClassApiInjectable;
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* 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 { parseKubeApi } from "../kube-api-parse";
|
||||||
|
import { kubeApiInjectionToken } from "./kube-api-injection-token";
|
||||||
|
import type { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
|
const getKubeApiFromPathInjectable = getInjectable({
|
||||||
|
id: "get-kube-api-from-path",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const kubeApis = di.injectMany(kubeApiInjectionToken);
|
||||||
|
|
||||||
|
return (apiPath: string) => {
|
||||||
|
const parsed = parseKubeApi(apiPath);
|
||||||
|
|
||||||
|
const kubeApi = kubeApis.find((api) => api.apiBase === parsed.apiBase);
|
||||||
|
|
||||||
|
return (kubeApi as KubeApi) || undefined;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getKubeApiFromPathInjectable;
|
||||||
10
src/common/k8s-api/kube-api/kube-api-injection-token.ts
Normal file
10
src/common/k8s-api/kube-api/kube-api-injection-token.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import type { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
|
export const kubeApiInjectionToken = getInjectionToken<KubeApi<any, any>>({
|
||||||
|
id: "kube-api-injection-token",
|
||||||
|
});
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getGlobalOverride } from "../../../../../../common/test-utils/get-global-override";
|
||||||
|
import callForPatchResourceInjectable from "./call-for-patch-resource.injectable";
|
||||||
|
|
||||||
|
export default getGlobalOverride(callForPatchResourceInjectable, () => () => {
|
||||||
|
throw new Error(
|
||||||
|
"Tried to call patching of kube resource without explicit override.",
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { AsyncResult } from "../../../../../../common/utils/async-result";
|
||||||
|
import apiManagerInjectable from "../../../../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
|
import type { JsonPatch } from "../../../../../../common/k8s-api/kube-object.store";
|
||||||
|
import type { KubeObject } from "../../../../../../common/k8s-api/kube-object";
|
||||||
|
import assert from "assert";
|
||||||
|
import { getErrorMessage } from "../../../../../../common/utils/get-error-message";
|
||||||
|
|
||||||
|
export type CallForPatchResource = (
|
||||||
|
item: KubeObject,
|
||||||
|
patch: JsonPatch
|
||||||
|
) => Promise<AsyncResult<{ name: string; kind: string }>>;
|
||||||
|
|
||||||
|
const callForPatchResourceInjectable = getInjectable({
|
||||||
|
id: "call-for-patch-resource",
|
||||||
|
instantiate: (di): CallForPatchResource => {
|
||||||
|
const apiManager = di.inject(apiManagerInjectable);
|
||||||
|
|
||||||
|
return async (item, patch) => {
|
||||||
|
const store = apiManager.getStore(item.selfLink);
|
||||||
|
|
||||||
|
assert(store);
|
||||||
|
|
||||||
|
let kubeObject: KubeObject;
|
||||||
|
|
||||||
|
try {
|
||||||
|
kubeObject = await store.patch(item, patch);
|
||||||
|
} catch (e: any) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: getErrorMessage(e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: { name: kubeObject.getName(), kind: kubeObject.kind },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
causesSideEffects: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default callForPatchResourceInjectable;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getGlobalOverride } from "../../../../../../common/test-utils/get-global-override";
|
||||||
|
import callForResourceInjectable from "./call-for-resource.injectable";
|
||||||
|
|
||||||
|
export default getGlobalOverride(callForResourceInjectable, () => () => {
|
||||||
|
throw new Error(
|
||||||
|
"Tried to call for kube resource without explicit override.",
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { KubeObject } from "../../../../../../common/k8s-api/kube-object";
|
||||||
|
import { parseKubeApi } from "../../../../../../common/k8s-api/kube-api-parse";
|
||||||
|
import type { AsyncResult } from "../../../../../../common/utils/async-result";
|
||||||
|
import { getErrorMessage } from "../../../../../../common/utils/get-error-message";
|
||||||
|
import apiManagerInjectable from "../../../../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
|
import { waitUntilDefined } from "../../../../../../common/utils";
|
||||||
|
|
||||||
|
export type CallForResource = (
|
||||||
|
selfLink: string
|
||||||
|
) => Promise<AsyncResult<KubeObject | undefined>>;
|
||||||
|
|
||||||
|
const callForResourceInjectable = getInjectable({
|
||||||
|
id: "call-for-resource",
|
||||||
|
|
||||||
|
instantiate: (di): CallForResource => {
|
||||||
|
const apiManager = di.inject(apiManagerInjectable);
|
||||||
|
|
||||||
|
return async (apiPath: string) => {
|
||||||
|
const api = await waitUntilDefined(() => apiManager.getApi(apiPath));
|
||||||
|
|
||||||
|
const parsed = parseKubeApi(apiPath);
|
||||||
|
|
||||||
|
if (!api || !parsed.name) {
|
||||||
|
return { callWasSuccessful: false, error: "Invalid API path" };
|
||||||
|
}
|
||||||
|
|
||||||
|
let resource: KubeObject | null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
resource = await api.get({
|
||||||
|
name: parsed.name,
|
||||||
|
namespace: parsed.namespace,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return { callWasSuccessful: false, error: getErrorMessage(e) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { callWasSuccessful: true, response: resource || undefined };
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
causesSideEffects: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default callForResourceInjectable;
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import type { CallForResource } from "./call-for-resource/call-for-resource.injectable";
|
||||||
|
import callForResourceInjectable from "./call-for-resource/call-for-resource.injectable";
|
||||||
|
import { waitUntilDefined } from "../../../../../common/utils";
|
||||||
|
import editResourceTabStoreInjectable from "../store.injectable";
|
||||||
|
import type { EditingResource, EditResourceTabStore } from "../store";
|
||||||
|
import { action, computed, observable, runInAction } from "mobx";
|
||||||
|
import type { KubeObject } from "../../../../../common/k8s-api/kube-object";
|
||||||
|
import yaml from "js-yaml";
|
||||||
|
import assert from "assert";
|
||||||
|
import type { CallForPatchResource } from "./call-for-patch-resource/call-for-patch-resource.injectable";
|
||||||
|
import callForPatchResourceInjectable from "./call-for-patch-resource/call-for-patch-resource.injectable";
|
||||||
|
import { createPatch } from "rfc6902";
|
||||||
|
import type { ShowNotification } from "../../../notifications";
|
||||||
|
import showSuccessNotificationInjectable from "../../../notifications/show-success-notification.injectable";
|
||||||
|
import React from "react";
|
||||||
|
import showErrorNotificationInjectable from "../../../notifications/show-error-notification.injectable";
|
||||||
|
|
||||||
|
const editResourceModelInjectable = getInjectable({
|
||||||
|
id: "edit-resource-model",
|
||||||
|
|
||||||
|
instantiate: async (di, tabId: string) => {
|
||||||
|
const store = di.inject(editResourceTabStoreInjectable);
|
||||||
|
|
||||||
|
const model = new EditResourceModel({
|
||||||
|
callForResource: di.inject(callForResourceInjectable),
|
||||||
|
callForPatchResource: di.inject(callForPatchResourceInjectable),
|
||||||
|
showSuccessNotification: di.inject(showSuccessNotificationInjectable),
|
||||||
|
showErrorNotification: di.inject(showErrorNotificationInjectable),
|
||||||
|
store,
|
||||||
|
tabId,
|
||||||
|
|
||||||
|
waitForEditingResource: () =>
|
||||||
|
waitUntilDefined(() => store.getData(tabId)),
|
||||||
|
});
|
||||||
|
|
||||||
|
await model.load();
|
||||||
|
|
||||||
|
return model;
|
||||||
|
},
|
||||||
|
|
||||||
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
|
getInstanceKey: (di, tabId: string) => tabId,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default editResourceModelInjectable;
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
callForResource: CallForResource;
|
||||||
|
callForPatchResource: CallForPatchResource;
|
||||||
|
waitForEditingResource: () => Promise<EditingResource>;
|
||||||
|
showSuccessNotification: ShowNotification;
|
||||||
|
showErrorNotification: ShowNotification;
|
||||||
|
store: EditResourceTabStore;
|
||||||
|
tabId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditResourceModel {
|
||||||
|
constructor(private dependencies: Dependencies) {
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly configuration = {
|
||||||
|
value: computed(() => this.editingResource.draft || this.editingResource.firstDraft || ""),
|
||||||
|
|
||||||
|
onChange: action((value: string) => {
|
||||||
|
this.editingResource.draft = value;
|
||||||
|
this.configuration.error.value.set("");
|
||||||
|
}),
|
||||||
|
|
||||||
|
error: {
|
||||||
|
value: observable.box(""),
|
||||||
|
|
||||||
|
onChange: action((error: string) => {
|
||||||
|
this.configuration.error.value.set(error);
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@observable private _resource: KubeObject | undefined;
|
||||||
|
|
||||||
|
@computed get shouldShowErrorAboutNoResource() {
|
||||||
|
return !this._resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get resource() {
|
||||||
|
assert(this._resource, "Resource does not have data");
|
||||||
|
|
||||||
|
return this._resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get editingResource() {
|
||||||
|
const resource = this.dependencies.store.getData(this.dependencies.tabId);
|
||||||
|
|
||||||
|
assert(resource, "Resource is not present in the store");
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed private get selfLink() {
|
||||||
|
return this.editingResource.resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
load = async () => {
|
||||||
|
await this.dependencies.waitForEditingResource();
|
||||||
|
|
||||||
|
const result = await this.dependencies.callForResource(this.selfLink);
|
||||||
|
|
||||||
|
if (!result.callWasSuccessful) {
|
||||||
|
this.dependencies.showErrorNotification(
|
||||||
|
`Loading resource failed: ${result.error}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resource = result.response;
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this._resource = resource;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.editingResource.firstDraft = yaml.dump(resource.toPlainObject());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
get namespace() {
|
||||||
|
return this.resource.metadata.namespace || "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.resource.metadata.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get kind() {
|
||||||
|
return this.resource.kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
save = async () => {
|
||||||
|
const currentValue = this.configuration.value.get();
|
||||||
|
const currentVersion = yaml.load(currentValue);
|
||||||
|
const firstVersion = yaml.load(this.editingResource.firstDraft ?? currentValue);
|
||||||
|
const patches = createPatch(firstVersion, currentVersion);
|
||||||
|
|
||||||
|
const result = await this.dependencies.callForPatchResource(this.resource, patches);
|
||||||
|
|
||||||
|
if (!result.callWasSuccessful) {
|
||||||
|
this.dependencies.showErrorNotification(
|
||||||
|
<p>
|
||||||
|
Failed to save resource:
|
||||||
|
{" "}
|
||||||
|
{result.error}
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { kind, name } = result.response;
|
||||||
|
|
||||||
|
this.dependencies.showSuccessNotification(
|
||||||
|
<p>
|
||||||
|
{kind}
|
||||||
|
{" "}
|
||||||
|
<b>{name}</b>
|
||||||
|
{" updated."}
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.editingResource.firstDraft = currentValue;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -6,52 +6,52 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import editResourceTabStoreInjectable from "./store.injectable";
|
import editResourceTabStoreInjectable from "./store.injectable";
|
||||||
import dockStoreInjectable from "../dock/store.injectable";
|
import dockStoreInjectable from "../dock/store.injectable";
|
||||||
import type { KubeObject } from "../../../../common/k8s-api/kube-object";
|
import type { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||||
import type { DockStore, DockTabCreateSpecific, TabId } from "../dock/store";
|
import type { DockTabCreateSpecific, TabId } from "../dock/store";
|
||||||
import { TabKind } from "../dock/store";
|
import { TabKind } from "../dock/store";
|
||||||
import type { EditResourceTabStore } from "./store";
|
|
||||||
import { runInAction } from "mobx";
|
import { runInAction } from "mobx";
|
||||||
|
import getRandomIdForEditResourceTabInjectable from "./get-random-id-for-edit-resource-tab.injectable";
|
||||||
interface Dependencies {
|
|
||||||
dockStore: DockStore;
|
|
||||||
editResourceStore: EditResourceTabStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createEditResourceTab = ({ dockStore, editResourceStore }: Dependencies) => (object: KubeObject, tabParams: DockTabCreateSpecific = {}): TabId => {
|
|
||||||
// use existing tab if already opened
|
|
||||||
const tabId = editResourceStore.getTabIdByResource(object);
|
|
||||||
|
|
||||||
if (tabId) {
|
|
||||||
dockStore.open();
|
|
||||||
dockStore.selectTab(tabId);
|
|
||||||
|
|
||||||
return tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return runInAction(() => {
|
|
||||||
const tab = dockStore.createTab(
|
|
||||||
{
|
|
||||||
title: `${object.kind}: ${object.getName()}`,
|
|
||||||
...tabParams,
|
|
||||||
kind: TabKind.EDIT_RESOURCE,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
editResourceStore.setData(tab.id, {
|
|
||||||
resource: object.selfLink,
|
|
||||||
});
|
|
||||||
|
|
||||||
return tab.id;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createEditResourceTabInjectable = getInjectable({
|
const createEditResourceTabInjectable = getInjectable({
|
||||||
id: "create-edit-resource-tab",
|
id: "create-edit-resource-tab",
|
||||||
|
|
||||||
instantiate: (di) => createEditResourceTab({
|
instantiate: (di) => {
|
||||||
dockStore: di.inject(dockStoreInjectable),
|
const dockStore = di.inject(dockStoreInjectable);
|
||||||
editResourceStore: di.inject(editResourceTabStoreInjectable),
|
const editResourceStore = di.inject(editResourceTabStoreInjectable);
|
||||||
}),
|
const getRandomId = di.inject(getRandomIdForEditResourceTabInjectable);
|
||||||
|
|
||||||
|
return (
|
||||||
|
object: KubeObject,
|
||||||
|
tabParams: DockTabCreateSpecific = {},
|
||||||
|
): TabId => {
|
||||||
|
// use existing tab if already opened
|
||||||
|
const tabId = editResourceStore.getTabIdByResource(object);
|
||||||
|
|
||||||
|
if (tabId) {
|
||||||
|
dockStore.open();
|
||||||
|
dockStore.selectTab(tabId);
|
||||||
|
|
||||||
|
return tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return runInAction(() => {
|
||||||
|
const tab = dockStore.createTab(
|
||||||
|
{
|
||||||
|
id: getRandomId(),
|
||||||
|
title: `${object.kind}: ${object.getName()}`,
|
||||||
|
...tabParams,
|
||||||
|
kind: TabKind.EDIT_RESOURCE,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
editResourceStore.setData(tab.id, {
|
||||||
|
resource: object.selfLink,
|
||||||
|
});
|
||||||
|
|
||||||
|
return tab.id;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default createEditResourceTabInjectable;
|
export default createEditResourceTabInjectable;
|
||||||
|
|||||||
@ -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 getRandomIdInjectable from "../../../../common/utils/get-random-id.injectable";
|
||||||
|
|
||||||
|
const getRandomIdForEditResourceTabInjectable = getInjectable({
|
||||||
|
id: "get-random-id-for-edit-resource-tab",
|
||||||
|
instantiate: (di) => di.inject(getRandomIdInjectable),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getRandomIdForEditResourceTabInjectable;
|
||||||
@ -5,14 +5,12 @@
|
|||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { EditResourceTabStore } from "./store";
|
import { EditResourceTabStore } from "./store";
|
||||||
import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable";
|
import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable";
|
||||||
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
|
|
||||||
|
|
||||||
const editResourceTabStoreInjectable = getInjectable({
|
const editResourceTabStoreInjectable = getInjectable({
|
||||||
id: "edit-resource-tab-store",
|
id: "edit-resource-tab-store",
|
||||||
|
|
||||||
instantiate: (di) => new EditResourceTabStore({
|
instantiate: (di) => new EditResourceTabStore({
|
||||||
createStorage: di.inject(createStorageInjectable),
|
createStorage: di.inject(createStorageInjectable),
|
||||||
apiManager: di.inject(apiManagerInjectable),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,7 @@
|
|||||||
|
|
||||||
import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store";
|
import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store";
|
||||||
import { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
import { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
||||||
import type { TabId } from "../dock/store";
|
|
||||||
import type { KubeObject } from "../../../../common/k8s-api/kube-object";
|
import type { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||||
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
|
||||||
import type { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
|
||||||
|
|
||||||
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
|
||||||
@ -16,50 +13,14 @@ export interface EditingResource {
|
|||||||
firstDraft?: string;
|
firstDraft?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditResourceTabStoreDependencies extends DockTabStoreDependencies {
|
|
||||||
readonly apiManager: ApiManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EditResourceTabStore extends DockTabStore<EditingResource> {
|
export class EditResourceTabStore extends DockTabStore<EditingResource> {
|
||||||
constructor(protected readonly dependencies: EditResourceTabStoreDependencies) {
|
constructor(protected readonly dependencies: DockTabStoreDependencies) {
|
||||||
super(dependencies, {
|
super(dependencies, {
|
||||||
storageKey: "edit_resource_store",
|
storageKey: "edit_resource_store",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected finalizeDataForSave({ draft, ...data }: EditingResource): EditingResource {
|
|
||||||
return data; // skip saving draft to local-storage
|
|
||||||
}
|
|
||||||
|
|
||||||
isReady(tabId: TabId) {
|
|
||||||
return super.isReady(tabId) && Boolean(this.getResource(tabId)); // ready to edit resource
|
|
||||||
}
|
|
||||||
|
|
||||||
getStore(tabId: TabId): KubeObjectStore | undefined {
|
|
||||||
const apiPath = this.getResourcePath(tabId);
|
|
||||||
|
|
||||||
return apiPath
|
|
||||||
? this.dependencies.apiManager.getStore(apiPath)
|
|
||||||
: undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
getResource(tabId: TabId): KubeObject | undefined {
|
|
||||||
const apiPath = this.getResourcePath(tabId);
|
|
||||||
|
|
||||||
return apiPath
|
|
||||||
? this.dependencies.apiManager.getStore(apiPath)?.getByPath(apiPath)
|
|
||||||
: undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
getResourcePath(tabId: TabId): string | undefined {
|
|
||||||
return this.getData(tabId)?.resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTabIdByResource(object: KubeObject): string | undefined {
|
getTabIdByResource(object: KubeObject): string | undefined {
|
||||||
return this.findTabIdFromData(({ resource }) => object.selfLink === resource);
|
return this.findTabIdFromData(({ resource }) => object.selfLink === resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInitialDraft(tabId: TabId): void {
|
|
||||||
delete this.getData(tabId)?.firstDraft;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,169 +4,82 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { autorun, makeObservable, observable } from "mobx";
|
import { observer } from "mobx-react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import type { DockTab } from "../dock/store";
|
||||||
import yaml from "js-yaml";
|
import { Spinner } from "../../spinner";
|
||||||
import type { DockTab, TabId } from "../dock/store";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { EditingResource, EditResourceTabStore } from "./store";
|
import type { EditResourceModel } from "./edit-resource-model/edit-resource-model.injectable";
|
||||||
|
import editResourceModelInjectable from "./edit-resource-model/edit-resource-model.injectable";
|
||||||
|
import { EditorPanel } from "../editor-panel";
|
||||||
import { InfoPanel } from "../info-panel";
|
import { InfoPanel } from "../info-panel";
|
||||||
import { Badge } from "../../badge";
|
import { Badge } from "../../badge";
|
||||||
import { EditorPanel } from "../editor-panel";
|
import { Notice } from "../../+extensions/notice";
|
||||||
import { Spinner } from "../../spinner";
|
|
||||||
import type { KubeObject } from "../../../../common/k8s-api/kube-object";
|
|
||||||
import { createPatch } from "rfc6902";
|
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
|
||||||
import editResourceTabStoreInjectable from "./store.injectable";
|
|
||||||
import { noop, onceDefined } from "../../../utils";
|
|
||||||
import closeDockTabInjectable from "../dock/close-dock-tab.injectable";
|
|
||||||
import type { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
|
||||||
|
|
||||||
export interface EditResourceProps {
|
export interface EditResourceProps {
|
||||||
tab: DockTab;
|
tab: DockTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
editResourceStore: EditResourceTabStore;
|
model: EditResourceModel;
|
||||||
closeTab: (tabId: TabId) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SaveDraftArgs {
|
const NonInjectedEditResource = observer(
|
||||||
tabData: EditingResource;
|
({ model, tab: { id: tabId }}: EditResourceProps & Dependencies) => {
|
||||||
resource: KubeObject;
|
|
||||||
store: KubeObjectStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
|
||||||
class NonInjectedEditResource extends React.Component<EditResourceProps & Dependencies> {
|
|
||||||
@observable error = "";
|
|
||||||
@observable draft = "";
|
|
||||||
|
|
||||||
constructor(props: EditResourceProps & Dependencies) {
|
|
||||||
super(props);
|
|
||||||
makeObservable(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
disposeOnUnmount(this, [
|
|
||||||
onceDefined(
|
|
||||||
() => {
|
|
||||||
const tabData = this.tabData;
|
|
||||||
const resource = this.resource;
|
|
||||||
|
|
||||||
if (tabData && resource) {
|
|
||||||
return { tabData, resource };
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
({ tabData, resource }) => {
|
|
||||||
if (typeof tabData.draft === "string") {
|
|
||||||
this.draft = tabData.draft;
|
|
||||||
} else {
|
|
||||||
this.draft = tabData.firstDraft = yaml.dump(resource.toPlainObject());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
autorun(() => {
|
|
||||||
const store = this.store;
|
|
||||||
const tabData = this.tabData;
|
|
||||||
const resource = this.resource;
|
|
||||||
|
|
||||||
if (!resource && store && tabData) {
|
|
||||||
if (store.isLoaded) {
|
|
||||||
// auto-close tab when resource removed from store
|
|
||||||
this.props.closeTab(this.props.tab.id);
|
|
||||||
} else if (!store.isLoading) {
|
|
||||||
// preload resource for editing
|
|
||||||
store.loadFromPath(tabData.resource).catch(noop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
get tabId() {
|
|
||||||
return this.props.tab.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get store() {
|
|
||||||
return this.props.editResourceStore.getStore(this.props.tab.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
get resource() {
|
|
||||||
return this.props.editResourceStore.getResource(this.tabId);
|
|
||||||
}
|
|
||||||
|
|
||||||
get tabData() {
|
|
||||||
return this.props.editResourceStore.getData(this.tabId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async save({ resource, store, tabData }: SaveDraftArgs) {
|
|
||||||
if (this.error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentVersion = yaml.load(this.draft);
|
|
||||||
const firstVersion = yaml.load(tabData.firstDraft ?? this.draft);
|
|
||||||
const patches = createPatch(firstVersion, currentVersion);
|
|
||||||
const updatedResource = await store.patch(resource, patches);
|
|
||||||
|
|
||||||
this.props.editResourceStore.clearInitialDraft(this.tabId);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<p>
|
|
||||||
{updatedResource.kind}
|
|
||||||
{" "}
|
|
||||||
<b>{updatedResource.getName()}</b>
|
|
||||||
{" updated."}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { tabId, error, draft, tabData, resource, store } = this;
|
|
||||||
|
|
||||||
if (!tabData || !resource || !store) {
|
|
||||||
return <Spinner center />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="EditResource flex column">
|
<div className="EditResource flex column">
|
||||||
<InfoPanel
|
{model.shouldShowErrorAboutNoResource && (
|
||||||
tabId={tabId}
|
<Notice>
|
||||||
error={error}
|
Resource not found
|
||||||
submit={() => this.save({ resource, store, tabData })}
|
</Notice>
|
||||||
submitLabel="Save"
|
)}
|
||||||
submittingMessage="Applying.."
|
|
||||||
controls={(
|
{!model.shouldShowErrorAboutNoResource && (
|
||||||
<div className="resource-info flex gaps align-center">
|
<>
|
||||||
<span>Kind:</span>
|
<InfoPanel
|
||||||
<Badge label={resource.kind} />
|
tabId={tabId}
|
||||||
<span>Name:</span>
|
error={model.configuration.error.value.get()}
|
||||||
<Badge label={resource.getName()} />
|
submit={model.save}
|
||||||
<span>Namespace:</span>
|
showNotifications={false}
|
||||||
<Badge label={resource.getNs() || "global"} />
|
submitLabel="Save"
|
||||||
</div>
|
submittingMessage="Applying..."
|
||||||
)}
|
submitTestId={`save-edit-resource-from-tab-for-${tabId}`}
|
||||||
/>
|
submitAndCloseTestId={`save-and-close-edit-resource-from-tab-for-${tabId}`}
|
||||||
<EditorPanel
|
cancelTestId={`cancel-edit-resource-from-tab-for-${tabId}`}
|
||||||
tabId={tabId}
|
submittingTestId={`saving-edit-resource-from-tab-for-${tabId}`}
|
||||||
value={draft}
|
controls={(
|
||||||
onChange={draft => {
|
<div className="resource-info flex gaps align-center">
|
||||||
this.error = "";
|
<span>Kind:</span>
|
||||||
this.draft = tabData.draft = draft;
|
<Badge label={model.kind} />
|
||||||
}}
|
<span>Name:</span>
|
||||||
onError={error => this.error = String(error)}
|
<Badge label={model.name} />
|
||||||
/>
|
<span>Namespace:</span>
|
||||||
|
<Badge label={model.namespace} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<EditorPanel
|
||||||
|
tabId={tabId}
|
||||||
|
value={model.configuration.value.get()}
|
||||||
|
onChange={model.configuration.onChange}
|
||||||
|
onError={model.configuration.error.onChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
export const EditResource = withInjectables<Dependencies, EditResourceProps>(NonInjectedEditResource, {
|
export const EditResource = withInjectables<Dependencies, EditResourceProps>(
|
||||||
getProps: (di, props) => ({
|
NonInjectedEditResource,
|
||||||
editResourceStore: di.inject(editResourceTabStoreInjectable),
|
{
|
||||||
closeTab: di.inject(closeDockTabInjectable),
|
getPlaceholder: () => (
|
||||||
...props,
|
<Spinner center data-testid="edit-resource-tab-spinner" />
|
||||||
}),
|
),
|
||||||
});
|
|
||||||
|
getProps: async (di, props) => ({
|
||||||
|
model: await di.inject(editResourceModelInjectable, props.tab.id),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export interface OptionalProps {
|
|||||||
showNotifications?: boolean;
|
showNotifications?: boolean;
|
||||||
showStatusPanel?: boolean;
|
showStatusPanel?: boolean;
|
||||||
submitTestId?: string;
|
submitTestId?: string;
|
||||||
|
submitAndCloseTestId?: string;
|
||||||
cancelTestId?: string;
|
cancelTestId?: string;
|
||||||
submittingTestId?: string;
|
submittingTestId?: string;
|
||||||
}
|
}
|
||||||
@ -167,6 +168,7 @@ class NonInjectedInfoPanel extends Component<InfoPanelProps & Dependencies> {
|
|||||||
label={`${submitLabel} & Close`}
|
label={`${submitLabel} & Close`}
|
||||||
onClick={submitAndClose}
|
onClick={submitAndClose}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
data-testid={this.props.submitAndCloseTestId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class FakeMonacoEditor extends React.Component<MonacoEditorProps> {
|
|||||||
const { id, value, onChange, onError, language = "yaml" } = this.props;
|
const { id, value, onChange, onError, language = "yaml" } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<textarea
|
||||||
data-testid={`monaco-editor-for-${id}`}
|
data-testid={`monaco-editor-for-${id}`}
|
||||||
|
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||||
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
||||||
import type { IObservableArray, ObservableSet } from "mobx";
|
import type { ObservableSet } from "mobx";
|
||||||
import { computed, observable, runInAction } from "mobx";
|
import { computed, observable, runInAction } from "mobx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Router } from "react-router";
|
import { Router } from "react-router";
|
||||||
@ -36,7 +36,6 @@ import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-f
|
|||||||
import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable";
|
import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable";
|
||||||
import startFrameInjectable from "../../start-frame/start-frame.injectable";
|
import startFrameInjectable from "../../start-frame/start-frame.injectable";
|
||||||
import type { NamespaceStore } from "../+namespaces/store";
|
import type { NamespaceStore } from "../+namespaces/store";
|
||||||
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
|
||||||
import historyInjectable from "../../navigation/history.injectable";
|
import historyInjectable from "../../navigation/history.injectable";
|
||||||
import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable";
|
import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable";
|
||||||
import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable";
|
import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable";
|
||||||
@ -61,6 +60,8 @@ import { ClusterFrame } from "../../frames/cluster-frame/cluster-frame";
|
|||||||
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
|
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
|
||||||
import activeKubernetesClusterInjectable from "../../cluster-frame-context/active-kubernetes-cluster.injectable";
|
import activeKubernetesClusterInjectable from "../../cluster-frame-context/active-kubernetes-cluster.injectable";
|
||||||
import { catalogEntityFromCluster } from "../../../main/cluster-manager";
|
import { catalogEntityFromCluster } from "../../../main/cluster-manager";
|
||||||
|
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
||||||
|
import { isAllowedResource } from "../../../common/cluster/is-allowed-resource";
|
||||||
|
|
||||||
type Callback = (dis: DiContainers) => void | Promise<void>;
|
type Callback = (dis: DiContainers) => void | Promise<void>;
|
||||||
|
|
||||||
@ -208,7 +209,7 @@ export const getApplicationBuilder = () => {
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let allowedResourcesState: IObservableArray<KubeResource>;
|
let allowedResourcesState: KubeResource[];
|
||||||
let rendered: RenderResult;
|
let rendered: RenderResult;
|
||||||
|
|
||||||
const enableExtensionsFor = <T extends ObservableSet>(
|
const enableExtensionsFor = <T extends ObservableSet>(
|
||||||
@ -398,16 +399,27 @@ export const getApplicationBuilder = () => {
|
|||||||
|
|
||||||
const clusterStub = {
|
const clusterStub = {
|
||||||
accessibleNamespaces: [],
|
accessibleNamespaces: [],
|
||||||
|
isAllowedResource: isAllowedResource(allowedResourcesState),
|
||||||
} as unknown as Cluster;
|
} as unknown as Cluster;
|
||||||
|
|
||||||
rendererDi.override(activeKubernetesClusterInjectable, () =>
|
rendererDi.override(activeKubernetesClusterInjectable, () =>
|
||||||
computed(() => catalogEntityFromCluster(clusterStub)),
|
computed(() => catalogEntityFromCluster(clusterStub)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Figure out a way to remove this stub.
|
||||||
const namespaceStoreStub = {
|
const namespaceStoreStub = {
|
||||||
|
isLoaded: true,
|
||||||
contextNamespaces: [],
|
contextNamespaces: [],
|
||||||
|
contextItems: [],
|
||||||
|
api: {
|
||||||
|
kind: "Namespace",
|
||||||
|
},
|
||||||
items: [],
|
items: [],
|
||||||
selectNamespaces: () => {},
|
selectNamespaces: () => {},
|
||||||
|
getByPath: () => undefined,
|
||||||
|
pickOnlySelected: () => [],
|
||||||
|
isSelectedAll: () => false,
|
||||||
|
getTotalCount: () => 0,
|
||||||
} as unknown as NamespaceStore;
|
} as unknown as NamespaceStore;
|
||||||
|
|
||||||
const clusterFrameContextFake = new ClusterFrameContext(
|
const clusterFrameContextFake = new ClusterFrameContext(
|
||||||
|
|||||||
@ -22,5 +22,7 @@ export const controlWhenStoragesAreReady = (di: DiContainer) => {
|
|||||||
// TODO: Remove when typing is added to the library
|
// TODO: Remove when typing is added to the library
|
||||||
(di as any).decorateFunction(createStorageInjectable, decorated);
|
(di as any).decorateFunction(createStorageInjectable, decorated);
|
||||||
|
|
||||||
return async () => void await Promise.all(storagesAreReady);
|
return async () => {
|
||||||
|
await Promise.all(storagesAreReady);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user