Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New deployment forms: changes in operator-related views #5411

Merged
merged 4 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ beforeEach(() => {
})),
});

// mock the window.ResizeObserver, required by the MonacoEditor for the layout
// mock the window.ResizeObserver, required by the MonacoDiffEditor for the layout
Object.defineProperty(window, "ResizeObserver", {
writable: true,
configurable: true,
Expand All @@ -89,7 +89,7 @@ beforeEach(() => {
})),
});

// mock the window.HTMLCanvasElement.getContext(), required by the MonacoEditor for the layout
// mock the window.HTMLCanvasElement.getContext(), required by the MonacoDiffEditor for the layout
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
writable: true,
configurable: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

import actions from "actions";
import AdvancedDeploymentForm from "components/DeploymentFormBody/AdvancedDeploymentForm";
import Alert from "components/js/Alert";
import OperatorInstanceFormBody from "components/OperatorInstanceFormBody/OperatorInstanceFormBody";
import OperatorHeader from "components/OperatorView/OperatorHeader";
Expand All @@ -11,6 +10,7 @@ import * as ReactRedux from "react-redux";
import { defaultStore, getStore, initialState, mountWrapper } from "shared/specs/mountWrapper";
import { FetchError, IClusterServiceVersion, IStoreState } from "shared/types";
import OperatorInstanceForm, { IOperatorInstanceFormProps } from "./OperatorInstanceForm";
import OperatorAdvancedDeploymentForm from "../OperatorInstanceFormBody/OperatorAdvancedDeploymentForm/OperatorAdvancedDeploymentForm";

const defaultProps: IOperatorInstanceFormProps = {
csvName: "foo",
Expand Down Expand Up @@ -57,7 +57,7 @@ beforeEach(() => {
})),
});

// mock the window.ResizeObserver, required by the MonacoEditor for the layout
// mock the window.ResizeObserver, required by the MonacoDiffEditor for the layout
Object.defineProperty(window, "ResizeObserver", {
writable: true,
configurable: true,
Expand All @@ -68,7 +68,7 @@ beforeEach(() => {
})),
});

// mock the window.HTMLCanvasElement.getContext(), required by the MonacoEditor for the layout
// mock the window.HTMLCanvasElement.getContext(), required by the MonacoDiffEditor for the layout
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
writable: true,
configurable: true,
Expand Down Expand Up @@ -168,7 +168,7 @@ it("should submit the form", () => {
);

act(() => {
(wrapper.find(AdvancedDeploymentForm).prop("handleValuesChange") as any)(
(wrapper.find(OperatorAdvancedDeploymentForm).prop("handleValuesChange") as any)(
"apiVersion: v1\nmetadata:\n name: foo",
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2021-2022 the Kubeapps contributors.
// SPDX-License-Identifier: Apache-2.0

import { SupportedThemes } from "shared/Config";
import { defaultStore, getStore, mountWrapper } from "shared/specs/mountWrapper";
import { IStoreState } from "shared/types";
import OperatorAdvancedDeploymentForm from "./OperatorAdvancedDeploymentForm";

beforeEach(() => {
// mock the window.matchMedia for selecting the theme
Object.defineProperty(window, "matchMedia", {
writable: true,
configurable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});

// mock the window.ResizeObserver, required by the MonacoDiffEditor for the layout
Object.defineProperty(window, "ResizeObserver", {
writable: true,
configurable: true,
value: jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
})),
});

// mock the window.HTMLCanvasElement.getContext(), required by the MonacoDiffEditor for the layout
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
writable: true,
configurable: true,
value: jest.fn().mockImplementation(() => ({
clearRect: jest.fn(),
})),
});
});

afterEach(() => {
jest.restoreAllMocks();
});

const defaultProps = {
handleValuesChange: jest.fn(),
};

it("includes values", () => {
const wrapper = mountWrapper(
defaultStore,
<OperatorAdvancedDeploymentForm {...defaultProps} appValues="foo: bar" />,
);
expect(wrapper.find("MonacoDiffEditor").prop("value")).toBe("foo: bar");
});

it("sets light theme by default", () => {
const wrapper = mountWrapper(defaultStore, <OperatorAdvancedDeploymentForm {...defaultProps} />);
wrapper.update();
expect(wrapper.find("MonacoDiffEditor").prop("theme")).toBe("light");
});

it("changes theme", () => {
const wrapper = mountWrapper(
getStore({ config: { theme: SupportedThemes.dark } } as Partial<IStoreState>),
<OperatorAdvancedDeploymentForm {...defaultProps} />,
);
wrapper.update();
expect(wrapper.find("MonacoDiffEditor").prop("theme")).toBe("vs-dark");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2019-2022 the Kubeapps contributors.
// SPDX-License-Identifier: Apache-2.0

import { MonacoDiffEditor } from "react-monaco-editor";
import { useSelector } from "react-redux";
import { SupportedThemes } from "shared/Config";
import { IStoreState } from "shared/types";

export interface IOperatorAdvancedDeploymentFormProps {
appValues?: string;
oldAppValues?: string;
handleValuesChange: (value: string) => void;
children?: JSX.Element;
}

function OperatorAdvancedDeploymentForm(props: IOperatorAdvancedDeploymentFormProps) {
let timeout: NodeJS.Timeout;
const onChange = (value: string) => {
// Gather changes before submitting
clearTimeout(timeout);
timeout = setTimeout(() => props.handleValuesChange(value), 500);
};
const {
config: { theme },
} = useSelector((state: IStoreState) => state);

return (
<div className="deployment-form-tabs-data">
<MonacoDiffEditor
value={props.appValues}
original={props.oldAppValues}
className="editor"
height="90vh"
language="yaml"
onChange={onChange}
theme={theme === SupportedThemes.dark ? "vs-dark" : "light"}
options={{
renderSideBySide: false,
automaticLayout: true,
}}
/>
{props.children}
</div>
);
}

export default OperatorAdvancedDeploymentForm;
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright 2020-2022 the Kubeapps contributors.
// SPDX-License-Identifier: Apache-2.0

import { CdsButton } from "@cds/react/button";
import ConfirmDialog from "components/ConfirmDialog/ConfirmDialog";
import AdvancedDeploymentForm from "components/DeploymentFormBody/AdvancedDeploymentForm";
import Alert from "components/js/Alert";
import LoadingWrapper from "components/LoadingWrapper";
import { act } from "react-dom/test-utils";
import { defaultStore, mountWrapper } from "shared/specs/mountWrapper";
import OperatorAdvancedDeploymentForm from "./OperatorAdvancedDeploymentForm/OperatorAdvancedDeploymentForm";
import OperatorInstanceFormBody, { IOperatorInstanceFormProps } from "./OperatorInstanceFormBody";

beforeEach(() => {
Expand All @@ -26,7 +27,7 @@ beforeEach(() => {
})),
});

// mock the window.ResizeObserver, required by the MonacoEditor for the layout
// mock the window.ResizeObserver, required by the MonacoDiffEditor for the layout
Object.defineProperty(window, "ResizeObserver", {
writable: true,
configurable: true,
Expand All @@ -37,7 +38,7 @@ beforeEach(() => {
})),
});

// mock the window.HTMLCanvasElement.getContext(), required by the MonacoEditor for the layout
// mock the window.HTMLCanvasElement.getContext(), required by the MonacoDiffEditor for the layout
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
writable: true,
configurable: true,
Expand Down Expand Up @@ -70,7 +71,7 @@ it("set default values", () => {
defaultStore,
<OperatorInstanceFormBody {...defaultProps} defaultValues="foo" />,
);
expect(wrapper.find(AdvancedDeploymentForm).prop("appValues")).toBe("foo");
expect(wrapper.find(OperatorAdvancedDeploymentForm).prop("appValues")).toBe("foo");
});

it("restores the default values", async () => {
Expand All @@ -80,13 +81,13 @@ it("restores the default values", async () => {
);

act(() => {
(wrapper.find(AdvancedDeploymentForm).prop("handleValuesChange") as any)("not-foo");
(wrapper.find(OperatorAdvancedDeploymentForm).prop("handleValuesChange") as any)("not-foo");
});
wrapper.update();
expect(wrapper.find(AdvancedDeploymentForm).prop("appValues")).toBe("not-foo");
expect(wrapper.find(OperatorAdvancedDeploymentForm).prop("appValues")).toBe("not-foo");

const restoreButton = wrapper
.find("button")
.find(CdsButton)
.filterWhere(b => b.text().includes("Restore Defaults"));
act(() => {
restoreButton.simulate("click");
Expand All @@ -96,7 +97,7 @@ it("restores the default values", async () => {
});
wrapper.update();

expect(wrapper.find(AdvancedDeploymentForm).prop("appValues")).toBe("foo");
expect(wrapper.find(OperatorAdvancedDeploymentForm).prop("appValues")).toBe("foo");
});

it("should submit the form", () => {
Expand All @@ -108,7 +109,7 @@ it("should submit the form", () => {

const values = "apiVersion: v1\nmetadata:\n name: foo";
act(() => {
(wrapper.find(AdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
(wrapper.find(OperatorAdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
});
const form = wrapper.find("form");
form.simulate("submit", { preventDefault: jest.fn() });
Expand All @@ -131,7 +132,7 @@ it("should catch a syntax error in the form", () => {

const values = "metadata: invalid!\n name: foo";
act(() => {
(wrapper.find(AdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
(wrapper.find(OperatorAdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
});
const form = wrapper.find("form");
form.simulate("submit", { preventDefault: jest.fn() });
Expand All @@ -149,7 +150,7 @@ it("should throw an eror if the element doesn't contain an apiVersion", () => {

const values = "metadata:\nname: foo";
act(() => {
(wrapper.find(AdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
(wrapper.find(OperatorAdvancedDeploymentForm).prop("handleValuesChange") as any)(values);
});
const form = wrapper.find("form");
form.simulate("submit", { preventDefault: jest.fn() });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@

import { CdsButton } from "@cds/react/button";
import { CdsIcon } from "@cds/react/icon";
import DifferentialTab from "components/DeploymentFormBody/DifferentialTab";
import ConfirmDialog from "components/ConfirmDialog";
import Alert from "components/js/Alert";
import LoadingWrapper from "components/LoadingWrapper";
import Tabs from "components/Tabs";
import * as yaml from "js-yaml";
import { useEffect, useState } from "react";
import { IResource } from "shared/types";
import ConfirmDialog from "../ConfirmDialog/ConfirmDialog";
import AdvancedDeploymentForm from "../DeploymentFormBody/AdvancedDeploymentForm";
import Differential from "../DeploymentFormBody/Differential";
import LoadingWrapper from "../LoadingWrapper";
import OperatorAdvancedDeploymentForm from "./OperatorAdvancedDeploymentForm/OperatorAdvancedDeploymentForm";

export interface IOperatorInstanceFormProps {
isFetching: boolean;
Expand Down Expand Up @@ -98,54 +96,24 @@ function DeploymentFormBody({
<div className="deployment-form-tabs">
<Tabs
id="deployment-form-body-tabs"
columns={[
"YAML",
<DifferentialTab
key="differential-selector"
deploymentEvent={deployedValues ? "upgrade" : "install"}
defaultValues={defaultValues}
deployedValues={deployedValues || ""}
appValues={values}
/>,
]}
columns={["YAML editor"]}
data={[
<AdvancedDeploymentForm
<OperatorAdvancedDeploymentForm
appValues={values}
oldAppValues={deployedValues || defaultValues}
handleValuesChange={handleValuesChange}
key="advanced-deployment-form"
/>,
<Differential
oldValues={deployedValues || defaultValues}
newValues={values}
emptyDiffElement={
deployedValues ? (
<span>No changes detected from deployed values</span>
) : (
<span>No changes detected from example defaults</span>
)
}
key="differential-selector"
/>,
]}
/>
</div>
<div className="deployment-form-control-buttons">
<CdsButton status="primary" type="submit">
<CdsIcon shape="deploy" /> Deploy
</CdsButton>
{/* TODO(andresmgot): CdsButton "type" property doesn't work, so we need to use a normal <button>
https://github.com/vmware/clarity/issues/5038
*/}
<span className="color-icon-info">
<button
className="btn btn-info-outline"
type="button"
onClick={openModal}
style={{ marginTop: "-22px" }}
>
<CdsIcon shape="backup-restore" /> Restore Defaults
</button>
</span>
<CdsButton type="button" status="primary" action="outline" onClick={openModal}>
<CdsIcon shape="backup-restore" /> Restore Defaults
</CdsButton>
</div>
</form>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ beforeEach(() => {
})),
});

// mock the window.ResizeObserver, required by the MonacoEditor for the layout
// mock the window.ResizeObserver, required by the MonacoDiffEditor for the layout
Object.defineProperty(window, "ResizeObserver", {
writable: true,
configurable: true,
Expand All @@ -84,7 +84,7 @@ beforeEach(() => {
})),
});

// mock the window.HTMLCanvasElement.getContext(), required by the MonacoEditor for the layout
// mock the window.HTMLCanvasElement.getContext(), required by the MonacoDiffEditor for the layout
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
writable: true,
configurable: true,
Expand Down
Loading