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

Allow extension reactively hide preference tabs

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-07-05 14:59:10 +03:00
parent 16b87062a7
commit 6c7c0244a1
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
4 changed files with 772 additions and 1 deletions

View File

@ -0,0 +1,665 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`preferences: extension adding preference tabs given in preferences, when extension with preference tabs is enabled renders 1`] = `
<body>
<div>
<div
class="ClusterManager"
>
<div
class="topBar"
>
<div
class="items"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<main>
<div
id="lens-views"
/>
<div
class="SettingLayout showNavigation Preferences"
data-testid="application-preferences-page"
>
<nav
class="sidebarRegion"
>
<div
class="sidebar"
>
<div
class="Tabs flex column"
>
<div
class="header"
>
Preferences
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-extension-some-extension-nav-item-some-other-preference-tab-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Some other title
</div>
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-extension-some-extension-nav-item-some-preference-tab-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Some title
</div>
</div>
<div
class="Tab flex gaps align-center active"
data-testid="tab-link-for-application"
role="tab"
tabindex="0"
>
<div
class="label"
>
App
</div>
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-proxy"
role="tab"
tabindex="0"
>
<div
class="label"
>
Proxy
</div>
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-kubernetes"
role="tab"
tabindex="0"
>
<div
class="label"
>
Kubernetes
</div>
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-editor"
role="tab"
tabindex="0"
>
<div
class="label"
>
Editor
</div>
</div>
<div
class="Tab flex gaps align-center"
data-testid="tab-link-for-terminal"
role="tab"
tabindex="0"
>
<div
class="label"
>
Terminal
</div>
</div>
</div>
</div>
</nav>
<div
class="contentRegion"
id="ScrollSpyRoot"
>
<div
class="content"
>
<section
id="application"
>
<h2
data-testid="application-header"
>
Application
</h2>
<section
id="appearance"
>
<div
class="SubTitle"
>
Theme
</div>
<div
class="Select theme-lens css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-theme-input-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-theme-input-placeholder"
>
Select...
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-theme-input-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="theme-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
</section>
<hr />
<section
id="extensionRegistryUrl"
>
<div
class="SubTitle"
>
Extension Install Registry
</div>
<div
class="Select theme-lens css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-extension-install-registry-input-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-extension-install-registry-input-placeholder"
>
Select...
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-extension-install-registry-input-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="extension-install-registry-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
<p
class="mt-4 mb-5 leading-relaxed"
>
This setting is to change the registry URL for installing extensions by name.
If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
<b>
.npmrc
</b>
file or in the input below.
</p>
<div
class="Input theme round black disabled invalid"
>
<label
class="input-area flex gaps align-center"
id=""
>
<input
class="input box grow"
disabled=""
placeholder="Custom Extension Registry URL..."
spellcheck="false"
value="some-custom-url"
/>
</label>
<div
class="input-info flex gaps"
/>
</div>
</section>
<hr />
<section
id="other"
>
<div
class="SubTitle"
>
Start-up
</div>
<label
class="Switch"
data-testid="switch"
>
Automatically start Lens on login
<input
role="switch"
type="checkbox"
/>
</label>
</section>
<hr />
<section
id="update-channel"
>
<div
class="SubTitle"
>
Update Channel
</div>
<div
class="Select theme-lens css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-update-channel-input-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
>
<div
class="Select__single-value css-qc6sy-singleValue"
>
Stable
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="update-channel-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
</section>
<hr />
<section
id="locale"
>
<div
class="SubTitle"
>
Locale Timezone
</div>
<div
class="Select theme-lens css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-timezone-input-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-timezone-input-placeholder"
>
Select...
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-timezone-input-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="timezone-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
</section>
</section>
</div>
<div
class="toolsRegion"
>
<div
class="fixed top-[60px]"
>
<div
data-testid="close-preferences"
>
<div
aria-label="Close"
class="closeButton"
role="button"
>
<i
class="Icon icon material focusable"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
<div
aria-hidden="true"
class="esc"
>
ESC
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
/>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
</body>
`;

View File

@ -0,0 +1,95 @@
/**
* 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 type { IObservableValue } from "mobx";
import { runInAction, computed, observable } from "mobx";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../renderer/components/test-utils/get-extension-fake";
describe("preferences: extension adding preference tabs", () => {
let builder: ApplicationBuilder;
beforeEach(() => {
builder = getApplicationBuilder();
});
describe("given in preferences, when extension with preference tabs is enabled", () => {
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
beforeEach(async () => {
rendered = await builder.render();
builder.preferences.navigate();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false);
const testExtension = getExtensionFake({
id: "some-extension-id",
name: "some-extension",
rendererOptions: {
appPreferenceTabs: [
{
title: "Some title",
id: "some-preference-tab-id",
orderNumber: 2,
},
{
title: "Some other title",
id: "some-other-preference-tab-id",
orderNumber: 1,
},
{
title: "Some title for item with controlled visibility",
id: "some-preference-tab-id-with-controlled-visibility",
orderNumber: 3,
visible: computed(() => someObservable.get()),
},
],
},
});
builder.extensions.enable(testExtension);
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows tabs in order", () => {
const actual = rendered.queryAllByTestId(/tab-link-for-extension-some-extension-nav-item-(.*)/).map(x => x.dataset.testid);
expect(actual).toEqual([
"tab-link-for-extension-some-extension-nav-item-some-other-preference-tab-id",
"tab-link-for-extension-some-extension-nav-item-some-preference-tab-id",
]);
});
it("does not show hidden tab", () => {
const actual = rendered.queryByTestId(
"tab-link-for-extension-some-extension-nav-item-some-preference-tab-id-with-controlled-visibility",
);
expect(actual).not.toBeInTheDocument();
});
it("when item becomes visible, shows the tab", () => {
runInAction(() => {
someObservable.set(true);
});
const actual = rendered.queryByTestId(
"tab-link-for-extension-some-extension-nav-item-some-preference-tab-id-with-controlled-visibility",
);
expect(actual).toBeInTheDocument();
});
});
});

View File

@ -3,9 +3,12 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { IComputedValue } from "mobx";
export interface AppPreferenceTabRegistration {
title: string;
id: string;
orderNumber?: number;
visible?: IComputedValue<boolean>;
}

View File

@ -46,7 +46,15 @@ const extensionSpecificTabNavigationItemRegistratorInjectable = getInjectable({
parent: "general",
orderNumber: tab.orderNumber || 100,
navigate: () => navigateToExtensionPreferences(extension.sanitizedExtensionId, tab.id),
isVisible: computed(() => true),
isVisible: computed(() => {
if (!tab.visible) {
return true;
}
return tab.visible.get();
}),
isActive,
}),
});