mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
* Implement a lot of technical requirements for behavioural unit tests Note: the crux of this was to make routing env-agnostic, and not based on URLs as magic strings, but instead something type-enforced. Note: extension-based routes comply to same exact interface by "late-registering" their routes when installed. Routes are just injectables. Note: another chunk of global shared state is no more. Note: a lot of explicit side effects have been cornered to injectables. Note: a lot of stuff has become reactive as part if this. Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make a directory commonly available Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Require id for <Select /> to prevent non-deterministic renders This was caused by global state in a 3rd party lib: "react-select". Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Specify id for all <Select /> to satisfy previous commit Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Prevent explicit side effect in component by using existing dependency instead Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Extract instantiation of "conf" as injectables for causing side effects Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce a legacy-helper to make gradual refactoring of inheritors of Singleton easier Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make legacy unit tests for hotbar green and more simple by using the new legacy helper Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Temporarily kludge all unit tests green with a disclaimer about allowing side-effects Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove kludge in previous commit by explicitly permitting specific side effects where old unit tests require it Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Prevent old unit test with side effects from accessing file system Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Migrate to actual typing for di.permitSideEffects Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Prevent unit tests from failing because of non-standard method of HTML-element not present in js-dom Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Adapt integration tests to recent changes Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Fix code style Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Fix artifact from bad rebase Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Add a deprecation from a review comment Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove change that is not required Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant comment Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix code style Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant file Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix bad merge Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Improve variable name Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Tweak logger interface to be more descriptive Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make injecting legacy singleton always provide new instance Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove conditional typing when not needed Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Improve naming of variable Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove unnecessary code style changes Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove flag for causing side effects from too broad scope Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Override side-effects in unit test using injectable instead of monkey patching Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Flag some side-effects and add general overrides Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Fix unit tests in CI by removing explicit side-effect Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove explicit side-effect from getting default shell Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce abstraction for getting absolute paths Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using abstraction for getting absolute path to control explicit side effect Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce abstraction for joining paths Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using abstraction for joining paths to control explicit side effect Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix fake implementation for join paths Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix test after removing explicit side effect Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove explicit side effects from kubeconfig-syncs Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix arguments after removing explicit side effect Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make registrators not async for not being needed anymore Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make generalCatalogEntities non-observable, as there is no requirement Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Remove redundant code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify logic for registering general catalog entity sources Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add TODO Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Replace function for getting application menu items with reactive solution Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix typo in interface name Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove global shared state usages of hot bar store Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant enum Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
255 lines
7.2 KiB
TypeScript
255 lines
7.2 KiB
TypeScript
/**
|
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
*/
|
|
import styles from "./delete-cluster-dialog.module.scss";
|
|
|
|
import { computed, makeObservable, observable } from "mobx";
|
|
import { observer } from "mobx-react";
|
|
import React from "react";
|
|
|
|
import { Button } from "../button";
|
|
import { saveKubeconfig } from "./save-config";
|
|
import { Notifications } from "../notifications";
|
|
import { boundMethod } from "autobind-decorator";
|
|
import { Dialog } from "../dialog";
|
|
import { Icon } from "../icon";
|
|
import { Select } from "../select";
|
|
import { Checkbox } from "../checkbox";
|
|
import { requestClearClusterAsDeleting, requestDeleteCluster, requestSetClusterAsDeleting } from "../../ipc";
|
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
|
import hotbarStoreInjectable from "../../../common/hotbar-store.injectable";
|
|
import type { DeleteClusterDialogModel } from "./delete-cluster-dialog-model/delete-cluster-dialog-model";
|
|
import deleteClusterDialogModelInjectable from "./delete-cluster-dialog-model/delete-cluster-dialog-model.injectable";
|
|
import type { HotbarStore } from "../../../common/hotbar-store";
|
|
|
|
interface Dependencies {
|
|
hotbarStore: HotbarStore;
|
|
model: DeleteClusterDialogModel;
|
|
}
|
|
|
|
@observer
|
|
class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
|
|
@observable showContextSwitch = false;
|
|
@observable newCurrentContext = "";
|
|
|
|
constructor(props: Dependencies) {
|
|
super(props);
|
|
makeObservable(this);
|
|
}
|
|
|
|
@boundMethod
|
|
onOpen() {
|
|
this.newCurrentContext = "";
|
|
|
|
if (this.isCurrentContext()) {
|
|
this.showContextSwitch = true;
|
|
}
|
|
}
|
|
|
|
@boundMethod
|
|
onClose() {
|
|
this.props.model.close();
|
|
this.showContextSwitch = false;
|
|
}
|
|
|
|
removeContext() {
|
|
this.props.model.config.contexts = this.props.model.config.contexts.filter(item =>
|
|
item.name !== this.props.model.cluster.contextName,
|
|
);
|
|
}
|
|
|
|
changeCurrentContext() {
|
|
if (this.newCurrentContext && this.showContextSwitch) {
|
|
this.props.model.config.currentContext = this.newCurrentContext;
|
|
}
|
|
}
|
|
|
|
@boundMethod
|
|
async onDelete() {
|
|
const { cluster, config } = this.props.model;
|
|
|
|
await requestSetClusterAsDeleting(cluster.id);
|
|
this.removeContext();
|
|
this.changeCurrentContext();
|
|
|
|
try {
|
|
await saveKubeconfig(config, cluster.kubeConfigPath);
|
|
this.props.hotbarStore.removeAllHotbarItems(cluster.id);
|
|
await requestDeleteCluster(cluster.id);
|
|
} catch(error) {
|
|
Notifications.error(`Cannot remove cluster, failed to process config file. ${error}`);
|
|
} finally {
|
|
await requestClearClusterAsDeleting(cluster.id);
|
|
}
|
|
|
|
this.onClose();
|
|
}
|
|
|
|
@computed get disableDelete() {
|
|
const { cluster, config } = this.props.model;
|
|
const noContextsAvailable = config.contexts.filter(context => context.name !== cluster.contextName).length == 0;
|
|
const newContextNotSelected = this.newCurrentContext === "";
|
|
|
|
if (noContextsAvailable) {
|
|
return false;
|
|
}
|
|
|
|
return this.showContextSwitch && newContextNotSelected;
|
|
}
|
|
|
|
isCurrentContext() {
|
|
return this.props.model.config.currentContext == this.props.model.cluster.contextName;
|
|
}
|
|
|
|
renderCurrentContextSwitch() {
|
|
if (!this.showContextSwitch) return null;
|
|
const { cluster, config } = this.props.model;
|
|
const contexts = config.contexts.filter(context => context.name !== cluster.contextName);
|
|
|
|
const options = [
|
|
...contexts.map(context => ({
|
|
label: context.name,
|
|
value: context.name,
|
|
})),
|
|
];
|
|
|
|
return (
|
|
<div className="mt-4">
|
|
<Select
|
|
id="delete-cluster-input"
|
|
options={options}
|
|
value={this.newCurrentContext}
|
|
onChange={({ value }) => this.newCurrentContext = value}
|
|
themeName="light"
|
|
className="ml-[1px] mr-[1px]"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderDeleteMessage() {
|
|
const { cluster } = this.props.model;
|
|
|
|
if (cluster.isInLocalKubeconfig()) {
|
|
return (
|
|
<div>
|
|
Delete the <b>{cluster.getMeta().name}</b> context from Lens's internal kubeconfig?
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
Delete the <b>{cluster.getMeta().name}</b> context from <b>{cluster.kubeConfigPath}</b>?
|
|
</div>
|
|
);
|
|
}
|
|
|
|
getWarningMessage() {
|
|
const { cluster, config } = this.props.model;
|
|
const contexts = config.contexts.filter(context => context.name !== cluster.contextName);
|
|
|
|
if (!contexts.length) {
|
|
return (
|
|
<p data-testid="no-more-contexts-warning">
|
|
This will remove the last context in kubeconfig. There will be no active context.
|
|
</p>
|
|
);
|
|
}
|
|
|
|
if (this.isCurrentContext()) {
|
|
return (
|
|
<p data-testid="current-context-warning">
|
|
This will remove active context in kubeconfig. Use drop down below to select a different one.
|
|
</p>
|
|
);
|
|
}
|
|
|
|
if (cluster.isInLocalKubeconfig()) {
|
|
return (
|
|
<p data-testid="internal-kubeconfig-warning">
|
|
Are you sure you want to delete it? It can be re-added through the copy/paste mechanism.
|
|
</p>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<p data-testid="kubeconfig-change-warning">The contents of kubeconfig file will be changed!</p>
|
|
);
|
|
}
|
|
|
|
renderWarning() {
|
|
return (
|
|
<div className={styles.warning}>
|
|
<Icon material="warning_amber" className={styles.warningIcon}/>
|
|
{this.getWarningMessage()}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { cluster, config, isOpen } = this.props.model;
|
|
|
|
if (!cluster || !config) return null;
|
|
|
|
const contexts = config.contexts.filter(context => context.name !== cluster.contextName);
|
|
|
|
return (
|
|
<Dialog
|
|
className={styles.dialog}
|
|
isOpen={isOpen}
|
|
close={this.onClose}
|
|
onOpen={this.onOpen}
|
|
>
|
|
<div className={styles.dialogContent}>
|
|
{this.renderDeleteMessage()}
|
|
{this.renderWarning()}
|
|
<hr className={styles.hr}/>
|
|
{contexts.length > 0 && (
|
|
<>
|
|
<div className="mt-4">
|
|
<Checkbox
|
|
data-testid="context-switch"
|
|
label={(
|
|
<>
|
|
<span className="font-semibold">Select current-context</span>{" "}
|
|
{!this.isCurrentContext() && "(optional)"}
|
|
</>
|
|
)}
|
|
value={this.showContextSwitch}
|
|
onChange={value => this.showContextSwitch = this.isCurrentContext() ? true : value}
|
|
/>
|
|
</div>
|
|
{this.renderCurrentContextSwitch()}
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className={styles.dialogButtons}>
|
|
<Button
|
|
onClick={this.onClose} plain
|
|
label="Cancel"
|
|
/>
|
|
<Button
|
|
onClick={this.onDelete}
|
|
autoFocus accent
|
|
label="Delete Context"
|
|
disabled={this.disableDelete}
|
|
/>
|
|
</div>
|
|
</Dialog>
|
|
);
|
|
}
|
|
}
|
|
|
|
export const DeleteClusterDialog = withInjectables<Dependencies>(
|
|
NonInjectedDeleteClusterDialog,
|
|
|
|
{
|
|
getProps: (di) => ({
|
|
hotbarStore: di.inject(hotbarStoreInjectable),
|
|
model: di.inject(deleteClusterDialogModelInjectable),
|
|
}),
|
|
},
|
|
);
|