diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b9b41ddd58..fb91a82103 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,6 +8,9 @@ jobs: build: name: Deploy docs runs-on: ubuntu-latest + strategy: + matrix: + node-version: [12.x] steps: - name: Set up Python 3.7 uses: actions/setup-python@v2 @@ -31,8 +34,19 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git pull - - + + - name: Using Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Generate Extensions API Reference using typedocs + run: | + yarn install + yarn typedocs-extensions-api + for filename in docs/extensions/api/**/*.md; do [ -e "$filename" ] || continue; sed -i '1s/^/---\ntitle: API Reference\n---\n/' $filename; done + + - name: mkdocs deploy latest run: | mike deploy --push latest diff --git a/.gitignore b/.gitignore index c6f54c7dea..8a1a574c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ src/extensions/*/*.d.ts types/extension-api.d.ts types/extension-renderer-api.d.ts extensions/*/dist +docs/extensions/api \ No newline at end of file diff --git a/docs/contributing/promotion.md b/docs/contributing/promotion.md index 9e88caa5fa..84b457914e 100644 --- a/docs/contributing/promotion.md +++ b/docs/contributing/promotion.md @@ -1,4 +1,4 @@ -# Promotiion +# Promotion Help promote Lens! If you are not a developer (or even if you are), you can still contribute to the project, a lot, by helping us promote it. As we are a free open source project, the community is our most important asset, so here are some ways that you can help the project continue to grow. diff --git a/docs/extensions/api/README.md b/docs/extensions/api/README.md deleted file mode 100644 index e751aa7a19..0000000000 --- a/docs/extensions/api/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Lens Extension API Reference - -TBD diff --git a/docs/extensions/capabilities/common-capabilities.md b/docs/extensions/capabilities/common-capabilities.md index d59a8d2c53..3372dcb25c 100644 --- a/docs/extensions/capabilities/common-capabilities.md +++ b/docs/extensions/capabilities/common-capabilities.md @@ -245,7 +245,7 @@ import { LensRendererExtension } from "@k8slens/extensions"; import { CustomKindDetails, CustomKindDetailsProps } from "./src/custom-kind-details" export default class ExampleExtension extends LensRendererExtension { - kubeObjectMenuItems = [ + kubeObjectDetailItems = [ { kind: "CustomKind", apiVersions: ["custom.acme.org/v1"], diff --git a/mkdocs.yml b/mkdocs.yml index a22052988d..c61e4d798d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,7 +35,7 @@ nav: - Testing extensions: extensions/testing-and-publishing/testing.md - Publishing extensions: extensions/testing-and-publishing/publishing.md - Bundling extensions: extensions/testing-and-publishing/bundling.md - - API reference: extensions/api/README.md + - API reference: extensions/api/modules/_src_extensions_extension_api_.md - Contributing: - Overview: contributing/README.md - Development: contributing/development.md diff --git a/package.json b/package.json index 15bf712c1e..62bb57f232 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "kontena-lens", "productName": "Lens", "description": "Lens - The Kubernetes IDE", - "version": "4.0.0-alpha.4", + "version": "4.0.0-alpha.5", "main": "static/build/main.js", "copyright": "© 2020, Mirantis, Inc.", "license": "MIT", @@ -38,7 +38,8 @@ "download:helm": "yarn run ts-node build/download_helm.ts", "build:tray-icons": "yarn run ts-node build/build_tray_icon.ts", "lint": "eslint $@ --ext js,ts,tsx --max-warnings=0 src/", - "mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest" + "mkdocs-serve-local": "yarn typedocs-extensions-api && docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", + "typedocs-extensions-api": "npx typedoc --plugin typedoc-plugin-markdown --readme none --name @k8slens/extensions --ignoreCompilerErrors --out docs/extensions/api --mode modules --excludePrivate --includes src/ src/extensions/extension-api.ts" }, "config": { "bundledKubectlVersion": "1.17.11", @@ -280,7 +281,6 @@ "@types/electron-window-state": "^2.0.34", "@types/fs-extra": "^9.0.1", "@types/hapi": "^18.0.3", - "@types/hard-source-webpack-plugin": "^1.0.1", "@types/hoist-non-react-statics": "^3.3.1", "@types/html-webpack-plugin": "^3.2.3", "@types/http-proxy": "^1.17.4", @@ -342,7 +342,6 @@ "file-loader": "^6.0.0", "flex.box": "^3.4.4", "fork-ts-checker-webpack-plugin": "^5.0.0", - "hard-source-webpack-plugin": "^0.13.1", "hoist-non-react-statics": "^3.3.2", "html-webpack-plugin": "^4.3.0", "identity-obj-proxy": "^3.0.0", @@ -382,6 +381,8 @@ "ts-loader": "^7.0.5", "ts-node": "^8.10.2", "type-fest": "^0.18.0", + "typedoc": "^0.19.2", + "typedoc-plugin-markdown": "^3.0.11", "typeface-roboto": "^0.0.75", "typescript": "^4.0.2", "url-loader": "^4.1.0", @@ -389,6 +390,7 @@ "webpack-cli": "^3.3.11", "webpack-dev-server": "^3.11.0", "webpack-node-externals": "^1.7.2", + "what-input": "^5.2.10", "xterm": "^4.6.0", "xterm-addon-fit": "^0.4.0" } diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index e361397565..593992415f 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -57,11 +57,12 @@ describe("user store tests", () => { expect(us.preferences.colorTheme).toBe('light') }) - it("correctly resets theme to default value", () => { + it("correctly resets theme to default value", async () => { const us = UserStore.getInstance(); + us.isLoaded = true; us.preferences.colorTheme = "some other theme"; - us.resetTheme(); + await us.resetTheme(); expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme); }) diff --git a/src/common/user-store.ts b/src/common/user-store.ts index b03616c1d2..6a988d4004 100644 --- a/src/common/user-store.ts +++ b/src/common/user-store.ts @@ -88,7 +88,8 @@ export class UserStore extends BaseStore { } @action - resetTheme() { + async resetTheme() { + await this.whenLoaded; this.preferences.colorTheme = UserStore.defaultTheme; } diff --git a/src/common/utils/saveToAppFiles.ts b/src/common/utils/saveToAppFiles.ts index 9092767ccf..e6fab1cfa9 100644 --- a/src/common/utils/saveToAppFiles.ts +++ b/src/common/utils/saveToAppFiles.ts @@ -1,7 +1,8 @@ // Save file to electron app directory (e.g. "/Users/$USER/Library/Application Support/Lens" for MacOS) import path from "path"; import { app, remote } from "electron"; -import { ensureDirSync, writeFileSync, WriteFileOptions } from "fs-extra"; +import { ensureDirSync, writeFileSync } from "fs-extra"; +import { WriteFileOptions } from "fs" export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string { const absPath = path.resolve((app || remote.app).getPath("userData"), filePath); diff --git a/src/extensions/core-api/index.ts b/src/extensions/core-api/index.ts index 3882763681..1a2c59759a 100644 --- a/src/extensions/core-api/index.ts +++ b/src/extensions/core-api/index.ts @@ -9,7 +9,6 @@ import * as App from "./app" import * as EventBus from "./event-bus" import * as Store from "./stores" import * as Util from "./utils" -import * as Registry from "../registries" import * as ClusterFeature from "./cluster-feature" // TODO: allow to expose windowManager.navigate() as Navigation.navigate() in runtime @@ -21,5 +20,4 @@ export { ClusterFeature, Store, Util, - Registry, } diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index eb118bd7b3..5271bd7915 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -29,3 +29,4 @@ export { Role, roleApi } from "../../renderer/api/endpoints"; export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; +export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index 0b066f37e1..a0d90f4a13 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -14,7 +14,7 @@ export class ApiManager { return this.apis.get(pathOrCallback) || this.apis.get(KubeApi.parseApi(pathOrCallback).apiBase); } - return Array.from(this.apis.values()).find(pathOrCallback); + return Array.from(this.apis.values()).find(pathOrCallback ?? ((api: KubeApi) => true)); } registerApi(apiBase: string, api: KubeApi) { diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 7744276e74..7b561041f7 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -9,7 +9,7 @@ type AdditionalPrinterColumnsCommon = { description: string; } -type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { +export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; } @@ -120,9 +120,9 @@ export class CustomResourceDefinition extends KubeObject { return JSON.stringify(this.spec.conversion); } - getPrinterColumns(ignorePriority = true) { + getPrinterColumns(ignorePriority = true): AdditionalPrinterColumnsV1[] { const columns = this.spec.versions.find(a => this.getVersion() == a.name)?.additionalPrinterColumns - ?? this.spec.additionalPrinterColumns?.map(({JSONPath, ...rest}) => ({ ...rest, jsonPath: JSONPath })) // map to V1 shape + ?? this.spec.additionalPrinterColumns?.map(({ JSONPath, ...rest }) => ({ ...rest, jsonPath: JSONPath })) // map to V1 shape ?? []; return columns .filter(column => column.name != "Age") @@ -149,4 +149,3 @@ export class CustomResourceDefinition extends KubeObject { export const crdApi = new VersionedKubeApi({ objectConstructor: CustomResourceDefinition }); - diff --git a/src/renderer/api/endpoints/index.ts b/src/renderer/api/endpoints/index.ts index 3d69068e30..337d193043 100644 --- a/src/renderer/api/endpoints/index.ts +++ b/src/renderer/api/endpoints/index.ts @@ -5,6 +5,7 @@ export * from "./cluster.api" export * from "./cluster-role.api" export * from "./cluster-role-binding.api" export * from "./configmap.api" +export * from "./crd.api" export * from "./cron-job.api" export * from "./daemon-set.api" export * from "./deployment.api" diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index 4525240396..883fba2fd4 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -12,67 +12,83 @@ import { KubeObjectDetailsProps } from "../kube-object"; import { crdStore } from "./crd.store"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Input } from "../input"; -import { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; interface Props extends KubeObjectDetailsProps { } -function CrdColumnValue({ value }: { value: any[] | {} | string }) { +function convertSpecValue(value: any): any { if (Array.isArray(value)) { - return <>{value.map((item, index) => )} + return value.map(convertSpecValue) } - if (typeof(value) === 'object') return ( - - ); - return {value}; + + if (typeof value === "object") { + return ( + + ) + } + + return value } + @observer export class CrdResourceDetails extends React.Component { @computed get crd() { return crdStore.getByObject(this.props.object); } + renderAdditionalColumns(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { + return columns.map(({ name, jsonPath: jp }) => ( + + {convertSpecValue(jsonPath.value(crd, jp.slice(1)))} + + )) + } + + renderStatus(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { + const showStatus = !columns.find(column => column.name == "Status") && crd.status?.conditions; + if (!showStatus) { + return null + } + + const conditions = crd.status.conditions + .filter(({ type, reason }) => type || reason) + .map(({ type, reason, message, status }) => ({ kind: type || reason, message, status })) + .map(({ kind, message, status }, index) => ( + + )) + + return ( + Status} className="status" labelsOnly> + {conditions} + + ) + } + render() { - const { object } = this.props; - const { crd } = this; - if (!object || !crd) return null; + const { props: { object }, crd } = this; + if (!object || !crd) { + return null; + } + const className = cssNames("CrdResourceDetails", crd.getResourceKind()); const extraColumns = crd.getPrinterColumns(); - const showStatus = !extraColumns.find(column => column.name == "Status") && object.status?.conditions; + return (
- - {extraColumns.map(column => { - const { name } = column; - const value = jsonPath.query(object, (column.jsonPath).slice(1)); - return ( - - - - ) - })} - {showStatus && ( - Status} className="status" labelsOnly> - {object.status.conditions.map((condition, index) => { - const { type, reason, message, status } = condition; - const kind = type || reason; - if (!kind) return null; - return ( - - ); - })} - - )} + + {this.renderAdditionalColumns(object, extraColumns)} + {this.renderStatus(object, extraColumns)}
) } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index 3a7d726b59..e36fef532d 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -56,11 +56,11 @@ export class CrdResources extends React.Component { [sortBy.age]: (item: KubeObject) => item.metadata.creationTimestamp, } extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.query(item, column.jsonPath.slice(1)) + sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)) }) - const ListView = KubeObjectListLayout; + return ( - { renderTableContents={(crdInstance: KubeObject) => [ crdInstance.getName(), isNamespaced && crdInstance.getNs(), - ...extraColumns.map(column => { - return jsonPath.query(crdInstance, (column.jsonPath).slice(1)) - }), + ...extraColumns.map(column => ({ + renderBoolean: true, + children: jsonPath.value(crdInstance, column.jsonPath.slice(1)), + })), crdInstance.getAge(), ]} /> diff --git a/src/renderer/components/app.scss b/src/renderer/components/app.scss index 5d3b65f5e9..b7c492c9f5 100755 --- a/src/renderer/components/app.scss +++ b/src/renderer/components/app.scss @@ -23,7 +23,6 @@ --font-weight-thin: 300; --font-weight-normal: 400; --font-weight-bold: 500; - --mainBackground: #1e2124; --main-layout-header: 40px; --drag-region-height: 22px } diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 5ad908a528..a5ebe554d1 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -38,7 +38,8 @@ import { webFrame } from "electron"; import { clusterPageRegistry } from "../../extensions/registries/page-registry"; import { DynamicPage } from "../../extensions/dynamic-page"; import { extensionLoader } from "../../extensions/extension-loader"; -import { appEventBus } from "../../common/event-bus" +import { appEventBus } from "../../common/event-bus"; +import whatInput from 'what-input'; @observer export class App extends React.Component { @@ -57,6 +58,7 @@ export class App extends React.Component { window.addEventListener("online", () => { window.location.reload() }) + whatInput.ask() // Start to monitor user input device } get startURL() { diff --git a/src/renderer/components/drawer/drawer-item.tsx b/src/renderer/components/drawer/drawer-item.tsx index da38dd4a46..e50619fe5d 100644 --- a/src/renderer/components/drawer/drawer-item.tsx +++ b/src/renderer/components/drawer/drawer-item.tsx @@ -1,6 +1,6 @@ import "./drawer-item.scss"; import React from "react"; -import { cssNames } from "../../utils"; +import { cssNames, displayBooleans } from "../../utils"; export interface DrawerItemProps extends React.HTMLAttributes { name: React.ReactNode; @@ -8,18 +8,21 @@ export interface DrawerItemProps extends React.HTMLAttributes { title?: string; labelsOnly?: boolean; hidden?: boolean; + renderBoolean?: boolean; // show "true" or "false" for all of the children elements are "typeof boolean" } export class DrawerItem extends React.Component { render() { - const { name, title, labelsOnly, children, hidden, ...elemProps } = this.props - let { className } = this.props; + const { name, title, labelsOnly, children, hidden, className, renderBoolean, ...elemProps } = this.props if (hidden) return null - className = cssNames("DrawerItem", className, { labelsOnly }); + + const classNames = cssNames("DrawerItem", className, { labelsOnly }); + const content = displayBooleans(renderBoolean, children) + return ( -
+
{name} - {children} + {content}
) } diff --git a/src/renderer/components/drawer/drawer.scss b/src/renderer/components/drawer/drawer.scss index 72a2f10eb1..488a890f2c 100644 --- a/src/renderer/components/drawer/drawer.scss +++ b/src/renderer/components/drawer/drawer.scss @@ -3,6 +3,7 @@ --size: 50%; --full-size: 75%; --spacing: #{$padding * 3}; + --icon-focus-color: white; position: absolute; background: $contentColor; diff --git a/src/renderer/components/icon/icon.scss b/src/renderer/components/icon/icon.scss index 253423bd4c..e581ccbbdc 100644 --- a/src/renderer/components/icon/icon.scss +++ b/src/renderer/components/icon/icon.scss @@ -5,6 +5,7 @@ --big-size: 32px; --color-active: #{$iconActiveColor}; --bgc-active: #{$iconActiveBackground}; + --focus-color: var(--icon-focus-color, #{$lensBlue}); display: inline-flex; flex-shrink: 0; @@ -106,7 +107,7 @@ &.active { color: var(--color-active); - box-shadow: 0 0 0 3px $iconActiveBackground; + box-shadow: 0 0 0 2px $iconActiveBackground; background-color: $iconActiveBackground; } @@ -115,8 +116,16 @@ transition: 250ms color, 250ms opacity, 150ms background-color, 150ms box-shadow; border-radius: 50%; - &.focusable:focus { - @extend .active; + &.focusable:focus:not(:hover) { + box-shadow: 0 0 0 2px var(--focus-color); + + [data-whatintent='mouse'] & { + box-shadow: none; + + &.active { + box-shadow: 0 0 0 2px $iconActiveBackground; + } + } } &:hover { diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index 0ff8201e05..fa99b3405b 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -235,7 +235,7 @@ export class ItemListLayout extends React.Component { cellProps.className = cssNames(cellProps.className, headCell.className); } } - return + return }) } {renderItemMenu && ( @@ -277,7 +277,7 @@ export class ItemListLayout extends React.Component { if (!isReady || !filters.length || hideFilters || !userSettings.showAppliedFilters) { return; } - return + return } renderNoItems() { @@ -297,7 +297,7 @@ export class ItemListLayout extends React.Component { ) } - return + return } renderHeaderContent(placeholders: IHeaderPlaceholders): ReactNode { @@ -344,12 +344,12 @@ export class ItemListLayout extends React.Component { title:
{title}
, info: this.renderInfo(), filters: <> - {!isClusterScoped && } + {!isClusterScoped && } + }} /> , - search: , + search: , } let header = this.renderHeaderContent(placeholders); if (customizeHeader) { @@ -381,7 +381,7 @@ export class ItemListLayout extends React.Component { return (
{!isReady && ( - + )} {isReady && ( { onClick={prevDefault(() => store.toggleSelectionAll(items))} /> )} - {renderTableHeader.map((cellProps, index) => )} - {renderItemMenu && } + {renderTableHeader.map((cellProps, index) => )} + {renderItemMenu && } )} { diff --git a/src/renderer/components/kube-object/kube-object-menu.tsx b/src/renderer/components/kube-object/kube-object-menu.tsx index fa008f1bac..0333bf6f9c 100644 --- a/src/renderer/components/kube-object/kube-object-menu.tsx +++ b/src/renderer/components/kube-object/kube-object-menu.tsx @@ -57,11 +57,11 @@ export class KubeObjectMenu extends React.Component { render() { const { remove, update, renderRemoveMessage, isEditable, isRemovable } = this; - const { className, object, editable, removable, ...menuProps } = this.props; + const { className, object, editable, removable, toolbar, ...menuProps } = this.props; if (!object) return null; const menuItems = kubeObjectMenuRegistry.getItemsForKind(object.kind, object.apiVersion).map((item, index) => { - return + return }) return ( { updateAction={isEditable ? update : undefined} removeAction={isRemovable ? remove : undefined} removeConfirmationMessage={renderRemoveMessage} + toolbar={toolbar} {...menuProps} > {menuItems} diff --git a/src/renderer/components/layout/main-layout.tsx b/src/renderer/components/layout/main-layout.tsx index 67c6c08bce..e66fed3d17 100755 --- a/src/renderer/components/layout/main-layout.tsx +++ b/src/renderer/components/layout/main-layout.tsx @@ -38,6 +38,7 @@ export class MainLayout extends React.Component { (sidebarWidth) => this.storage.merge({ sidebarWidth }) ); + toggleSidebar = () => { this.isPinned = !this.isPinned; this.isAccessible = false; diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 4619e48de7..8bce1a32c8 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -27,8 +27,9 @@ import { crdStore } from "../+custom-resources/crd.store"; import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resources"; import { CustomResources } from "../+custom-resources/custom-resources"; import { navigation } from "../../navigation"; -import { isAllowedResource } from "../../../common/rbac" import { clusterPageRegistry } from "../../../extensions/registries/page-registry"; +import { isAllowedResource } from "../../../common/rbac"; +import { Spinner } from "../spinner"; const SidebarContext = React.createContext({ pinned: false }); type SidebarContextValue = { @@ -50,6 +51,10 @@ export class Sidebar extends React.Component { } renderCustomResources() { + if (crdStore.isLoading) { + return + } + return Object.entries(crdStore.groups).map(([group, crds]) => { const submenus = crds.map((crd) => { return { @@ -80,7 +85,7 @@ export class Sidebar extends React.Component {
- +
Lens
{ isHidden={!isAllowedResource("nodes")} url={clusterURL()} text={Cluster} - icon={} + icon={} /> Nodes} - icon={} + icon={} /> { routePath={workloadsRoute.path} subMenus={Workloads.tabRoutes} text={Workloads} - icon={} + icon={} /> { routePath={configRoute.path} subMenus={Config.tabRoutes} text={Configuration} - icon={} + icon={} /> { routePath={networkRoute.path} subMenus={Network.tabRoutes} text={Network} - icon={} + icon={} /> { url={storageURL({ query })} routePath={storageRoute.path} subMenus={Storage.tabRoutes} - icon={} + icon={} text={Storage} /> } + icon={} text={Namespaces} /> { isHidden={!isAllowedResource("events")} url={eventsURL({ query })} routePath={eventRoute.path} - icon={} + icon={} text={Events} /> { url={appsURL({ query })} subMenus={Apps.tabRoutes} routePath={appsRoute.path} - icon={} + icon={} text={Apps} /> { url={usersManagementURL({ query })} routePath={usersManagementRoute.path} subMenus={UserManagement.tabRoutes} - icon={} + icon={} text={Access Control} /> { url={crdURL()} subMenus={CustomResources.tabRoutes} routePath={crdRoute.path} - icon={} + icon={} text={Custom Resources} > {this.renderCustomResources()} @@ -194,7 +199,7 @@ export class Sidebar extends React.Component { url={url} routePath={path} text={title} - icon={} + icon={} /> ) })} @@ -257,7 +262,7 @@ class SidebarNavItem extends React.Component {
{icon} {text} - +
    {subMenus.map(({ title, url }) => ( diff --git a/src/renderer/components/spinner/spinner.scss b/src/renderer/components/spinner/spinner.scss index 802ef27bfc..b8843b542d 100644 --- a/src/renderer/components/spinner/spinner.scss +++ b/src/renderer/components/spinner/spinner.scss @@ -34,6 +34,12 @@ margin-top: calc(var(--spinner-size) / -2); } + &.centerHorizontal { + position: absolute; + left: 50%; + margin-left: calc(var(--spinner-size) / -2); + } + @keyframes rotate { 0% { transform: rotate(0deg); @@ -60,4 +66,4 @@ @include spinner-color(#4285F4); } } -} \ No newline at end of file +} diff --git a/src/renderer/components/spinner/spinner.tsx b/src/renderer/components/spinner/spinner.tsx index 771784a905..0edb2665b1 100644 --- a/src/renderer/components/spinner/spinner.tsx +++ b/src/renderer/components/spinner/spinner.tsx @@ -6,23 +6,19 @@ import { cssNames } from "../../utils"; export interface SpinnerProps extends React.HTMLProps { singleColor?: boolean; center?: boolean; + centerHorizontal?: boolean; } export class Spinner extends React.Component { - private elem: HTMLElement; - static defaultProps = { singleColor: true, center: false, }; render() { - const { center, singleColor, ...props } = this.props; - let { className } = this.props; - className = cssNames('Spinner', className, { - singleColor: singleColor, - center: center, - }); - return
    this.elem = e}/>; + const { center, singleColor, centerHorizontal, className, ...props } = this.props; + const classNames = cssNames('Spinner', className, { singleColor, center, centerHorizontal }); + + return
    ; } } diff --git a/src/renderer/components/table/table-cell.tsx b/src/renderer/components/table/table-cell.tsx index a56f144bc0..d278ad41d8 100644 --- a/src/renderer/components/table/table-cell.tsx +++ b/src/renderer/components/table/table-cell.tsx @@ -2,7 +2,7 @@ import "./table-cell.scss"; import type { TableSortBy, TableSortParams } from "./table"; import React, { ReactNode } from "react"; -import { autobind, cssNames } from "../../utils"; +import { autobind, cssNames, displayBooleans } from "../../utils"; import { Icon } from "../icon"; import { Checkbox } from "../checkbox"; @@ -13,6 +13,7 @@ export interface TableCellProps extends React.DOMAttributes { title?: ReactNode; checkbox?: boolean; // render cell with a checkbox isChecked?: boolean; // mark checkbox as checked or not + renderBoolean?: boolean; // show "true" or "false" for all of the children elements are "typeof boolean" sortBy?: TableSortBy; // column name, must be same as key in sortable object
_sorting?: Partial; //
sorting state, don't use this prop outside (!) _sort?(sortBy: TableSortBy): void; //
sort function, don't use this prop outside (!) @@ -52,20 +53,20 @@ export class TableCell extends React.Component { const { checkbox, isChecked } = this.props; const showCheckbox = isChecked !== undefined; if (checkbox && showCheckbox) { - return + return } } render() { - const { className, checkbox, isChecked, sortBy, _sort, _sorting, _nowrap, children, title, ...cellProps } = this.props; + const { className, checkbox, isChecked, sortBy, _sort, _sorting, _nowrap, children, title, renderBoolean: displayBoolean, ...cellProps } = this.props; const classNames = cssNames("TableCell", className, { checkbox: checkbox, nowrap: _nowrap, sorting: this.isSortable, }); - const content = title || children; + const content = displayBooleans(displayBoolean, title || children) return ( -
+
{this.renderCheckbox()} {_nowrap ?
{content}
: content} {this.renderSortIcon()} diff --git a/src/renderer/theme.store.ts b/src/renderer/theme.store.ts index e96bc1f873..4b8dc5fffd 100644 --- a/src/renderer/theme.store.ts +++ b/src/renderer/theme.store.ts @@ -48,6 +48,7 @@ export class ThemeStore { await this.loadTheme(themeId); this.applyTheme(); } catch (err) { + logger.error(err); userStore.resetTheme(); } }, { @@ -79,7 +80,7 @@ export class ThemeStore { } return existingTheme; } catch (err) { - logger.error(`Can't load theme "${themeId}": ${err}`); + throw new Error(`Can't load theme "${themeId}": ${err}`); } } @@ -90,7 +91,7 @@ export class ThemeStore { document.head.prepend(this.styles); } const cssVars = Object.entries(theme.colors).map(([cssName, color]) => { - return `--${cssName}: ${color} !important;` + return `--${cssName}: ${color};`; }); this.styles.textContent = `:root {\n${cssVars.join("\n")}}`; // Adding universal theme flag which can be used in component styles diff --git a/src/renderer/utils/__tests__/display-booleans.test.tsx b/src/renderer/utils/__tests__/display-booleans.test.tsx new file mode 100644 index 0000000000..29fdd0574b --- /dev/null +++ b/src/renderer/utils/__tests__/display-booleans.test.tsx @@ -0,0 +1,18 @@ +import React from "react" +import { displayBooleans } from "../display-booleans" + +describe("displayBooleans tests", () => { + it("should not do anything to div's if shouldShow is false", () => { + expect(displayBooleans(false,
)).toStrictEqual(
) + }) + + it("should not do anything to booleans's if shouldShow is false", () => { + expect(displayBooleans(false, true)).toStrictEqual(true) + expect(displayBooleans(false, false)).toStrictEqual(false) + }) + + it("should stringify booleans when shouldShow is true", () => { + expect(displayBooleans(true, true)).toStrictEqual("true") + expect(displayBooleans(true, false)).toStrictEqual("false") + }) +}) diff --git a/src/renderer/utils/display-booleans.ts b/src/renderer/utils/display-booleans.ts new file mode 100644 index 0000000000..c50b7cdf9b --- /dev/null +++ b/src/renderer/utils/display-booleans.ts @@ -0,0 +1,15 @@ +import React from "react" + +export function displayBooleans(shouldShow: boolean, from: React.ReactNode): React.ReactNode { + if (shouldShow) { + if (typeof from === "boolean") { + return from.toString() + } + + if (Array.isArray(from)) { + return from.map(node => displayBooleans(shouldShow, node)) + } + } + + return from +} diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index d8c9d692c4..0c2df22c91 100755 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -18,3 +18,4 @@ export * from "./isReactNode" export * from "./convertMemory" export * from "./convertCpu" export * from "./metricUnitsToNumber" +export * from "./display-booleans" diff --git a/static/RELEASE_NOTES.md b/static/RELEASE_NOTES.md index 8012c2c35c..64c57a673a 100644 --- a/static/RELEASE_NOTES.md +++ b/static/RELEASE_NOTES.md @@ -2,15 +2,17 @@ Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights! -## 4.0.0-alpha.4 (current version) +## 4.0.0-alpha.5 (current version) - Extension API - Improved pod logs +- Mechanism for users to specify accessible namespaces - Tray icon - Add last-status information for container - Add LoadBalancer information to Ingress view - Move tracker to an extension - Add support page (as an extension) +- Ability to restart deployment - Status bar visual fixes - Fix proxy upgrade socket timeouts - Fix UI staleness after network issues diff --git a/tsconfig.json b/tsconfig.json index 5a61e2ca3e..9cfbd543a8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,11 @@ "jsx": "react", "target": "ES2017", "module": "ESNext", - "lib": ["ESNext", "DOM", "DOM.Iterable"], + "lib": [ + "ESNext", + "DOM", + "DOM.Iterable" + ], "moduleResolution": "Node", "sourceMap": true, "strict": false, diff --git a/webpack.main.ts b/webpack.main.ts index 29e724d711..c388466cdc 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -4,7 +4,6 @@ import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin" import { isDevelopment, isProduction, mainDir, buildDir } from "./src/common/vars"; import nodeExternals from "webpack-node-externals"; import ProgressBarPlugin from "progress-bar-webpack-plugin"; -import HardSourceWebpackPlugin from 'hard-source-webpack-plugin'; export default function (): webpack.Configuration { console.info('WEBPACK:main', require("./src/common/vars")) @@ -48,7 +47,6 @@ export default function (): webpack.Configuration { plugins: [ new ProgressBarPlugin(), new ForkTsCheckerPlugin(), - isDevelopment && new HardSourceWebpackPlugin(), ].filter(Boolean) } } diff --git a/webpack.renderer.ts b/webpack.renderer.ts index 27fe6eb039..ea2b5f622c 100755 --- a/webpack.renderer.ts +++ b/webpack.renderer.ts @@ -6,7 +6,6 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin"; import TerserPlugin from "terser-webpack-plugin"; import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin" import ProgressBarPlugin from "progress-bar-webpack-plugin"; -import HardSourceWebpackPlugin from 'hard-source-webpack-plugin'; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' export default [ @@ -187,7 +186,6 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura filename: "[name].css", }), - isDevelopment && new HardSourceWebpackPlugin(), isDevelopment && new webpack.HotModuleReplacementPlugin(), isDevelopment && new ReactRefreshWebpackPlugin(), diff --git a/yarn.lock b/yarn.lock index 1207cd0729..7a237053b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1967,13 +1967,6 @@ "@types/podium" "*" "@types/shot" "*" -"@types/hard-source-webpack-plugin@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/hard-source-webpack-plugin/-/hard-source-webpack-plugin-1.0.1.tgz#4aecca35bafb7939bcf318bbf5a2710c3163cdd4" - integrity sha512-5eTPERZQj5RZLADk5o2Ip/XRLwgxOUeKzlIM3+czrhwA9pnVJAUYOm2fovbxkrIEQhuozQwc17fyH1ZXnSR/8g== - dependencies: - "@types/webpack" "*" - "@types/history@*", "@types/history@^4.7.3": version "4.7.6" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.6.tgz#ed8fc802c45b8e8f54419c2d054e55c9ea344356" @@ -5204,7 +5197,7 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-indent@^5.0.0, detect-indent@~5.0.0: +detect-indent@~5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= @@ -6359,7 +6352,7 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: +find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== @@ -7035,25 +7028,6 @@ har-validator@~5.1.3: ajv "^6.5.5" har-schema "^2.0.0" -hard-source-webpack-plugin@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/hard-source-webpack-plugin/-/hard-source-webpack-plugin-0.13.1.tgz#a99071e25b232f1438a5bc3c99f10a3869e4428e" - integrity sha512-r9zf5Wq7IqJHdVAQsZ4OP+dcUSvoHqDMxJlIzaE2J0TZWn3UjMMrHqwDHR8Jr/pzPfG7XxSe36E7Y8QGNdtuAw== - dependencies: - chalk "^2.4.1" - find-cache-dir "^2.0.0" - graceful-fs "^4.1.11" - lodash "^4.15.0" - mkdirp "^0.5.1" - node-object-hash "^1.2.0" - parse-json "^4.0.0" - pkg-dir "^3.0.0" - rimraf "^2.6.2" - semver "^5.6.0" - tapable "^1.0.0-beta.5" - webpack-sources "^1.0.1" - write-json-file "^2.3.0" - harmony-reflect@^1.4.6: version "1.6.1" resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9" @@ -7168,6 +7142,11 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +highlight.js@^10.2.0: + version "10.3.2" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.3.2.tgz#135fd3619a00c3cbb8b4cd6dbc78d56bfcbc46f1" + integrity sha512-3jRT7OUYsVsKvukNKZCtnvRcFyCJqSEIuIMsEybAXRiFSwpt65qjPd/Pr+UOdYt7WJlt+lj3+ypUsHiySBp/Jw== + history@^4.10.1, history@^4.9.0: version "4.10.1" resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" @@ -9317,7 +9296,7 @@ lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.1 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -lodash@^4.15.0, lodash@^4.17.19: +lodash@^4.17.19, lodash@^4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -9402,6 +9381,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + lz-string@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" @@ -9499,6 +9483,11 @@ marked@^1.1.0: resolved "https://registry.yarnpkg.com/marked/-/marked-1.1.0.tgz#62504ad4d11550c942935ccc5e39d64e5a4c4e50" integrity sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA== +marked@^1.1.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.3.tgz#58817ba348a7c9398cb94d40d12e0d08df83af57" + integrity sha512-RQuL2i6I6Gn+9n81IDNGbL0VHnta4a+8ZhqvryXEniTb/hQNtf3i26hi1XWUhzb9BgVyWHKR3UO8MaHtKoYibw== + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -9740,7 +9729,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@^3.0.4, minimatch@~3.0.2: +minimatch@^3.0.0, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -10150,11 +10139,6 @@ node-notifier@^7.0.0: uuid "^7.0.3" which "^2.0.2" -node-object-hash@^1.2.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/node-object-hash/-/node-object-hash-1.4.2.tgz#385833d85b229902b75826224f6077be969a9e94" - integrity sha512-UdS4swXs85fCGWWf6t6DMGgpN/vnlKeSGEQ7hJcrs7PBFoxoKLmibc3QRb7fwiYsjdL7PX8iI/TMSlZ90dgHhQ== - node-pty@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0.tgz#8f9bcc0d1c5b970a3184ffd533d862c7eb6590a6" @@ -12921,7 +12905,7 @@ shell-env@^3.0.0: execa "^1.0.0" strip-ansi "^5.2.0" -shelljs@^0.8.2: +shelljs@^0.8.2, shelljs@^0.8.4: version "0.8.4" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== @@ -13673,7 +13657,7 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" -tapable@^1.0.0, tapable@^1.0.0-beta.5, tapable@^1.1.3: +tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== @@ -14196,6 +14180,35 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typedoc-default-themes@^0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.11.4.tgz#1bc55b7c8d1132844616ff6f570e1e2cd0eb7343" + integrity sha512-Y4Lf+qIb9NTydrexlazAM46SSLrmrQRqWiD52593g53SsmUFioAsMWt8m834J6qsp+7wHRjxCXSZeiiW5cMUdw== + +typedoc-plugin-markdown@^3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.0.11.tgz#358c32f4a0086c1dd2da7f56c4b46ade8a63204b" + integrity sha512-/BE/PqnIVbQJ525czM+T3CVaA1gVN9X1Le100z8TV/Lze8LZVkuAUiHRIgw9BKYFm9IQaB88W55k4EV6uUVwYQ== + dependencies: + handlebars "^4.7.6" + +typedoc@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.19.2.tgz#842a63a581f4920f76b0346bb80eb2a49afc2c28" + integrity sha512-oDEg1BLEzi1qvgdQXc658EYgJ5qJLVSeZ0hQ57Eq4JXy6Vj2VX4RVo18qYxRWz75ifAaYuYNBUCnbhjd37TfOg== + dependencies: + fs-extra "^9.0.1" + handlebars "^4.7.6" + highlight.js "^10.2.0" + lodash "^4.17.20" + lunr "^2.3.9" + marked "^1.1.1" + minimatch "^3.0.0" + progress "^2.0.3" + semver "^7.3.2" + shelljs "^0.8.4" + typedoc-default-themes "^0.11.4" + typeface-roboto@^0.0.75: version "0.0.75" resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" @@ -14743,7 +14756,7 @@ webpack-node-externals@^1.7.2: resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3" integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg== -webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -14806,6 +14819,11 @@ wgxpath@~1.0.0: resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690" integrity sha1-7vikudVYzEla06mit1FZfs2a9pA= +what-input@^5.2.10: + version "5.2.10" + resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.10.tgz#f79f5b65cf95d75e55e6d580bb0a6b98174cad4e" + integrity sha512-7AQoIMGq7uU8esmKniOtZG3A+pzlwgeyFpkS3f/yzRbxknSL68tvn5gjE6bZ4OMFxCPjpaBd2udUTqlZ0HwrXQ== + whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" @@ -14985,18 +15003,6 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-json-file@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.3.0.tgz#2b64c8a33004d54b8698c76d585a77ceb61da32f" - integrity sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8= - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - pify "^3.0.0" - sort-keys "^2.0.0" - write-file-atomic "^2.0.0" - write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"