mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge 67370c14ca into f1a960fd78
This commit is contained in:
commit
4bbf1f8dcb
@ -214,6 +214,7 @@
|
|||||||
"@k8slens/routing": "^1.0.0",
|
"@k8slens/routing": "^1.0.0",
|
||||||
"@k8slens/run-many": "^1.0.0",
|
"@k8slens/run-many": "^1.0.0",
|
||||||
"@k8slens/startable-stoppable": "^1.0.0",
|
"@k8slens/startable-stoppable": "^1.0.0",
|
||||||
|
"@k8slens/table": "6.5.0",
|
||||||
"@k8slens/tooltip": "^1.0.0",
|
"@k8slens/tooltip": "^1.0.0",
|
||||||
"@k8slens/utilities": "^1.0.0",
|
"@k8slens/utilities": "^1.0.0",
|
||||||
"@kubernetes/client-node": "^0.18.1",
|
"@kubernetes/client-node": "^0.18.1",
|
||||||
|
|||||||
11
open-lens/src/renderer/add-remove-buttons.injectable.ts
Normal file
11
open-lens/src/renderer/add-remove-buttons.injectable.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { AddRemoveButtons } from "@k8slens/core/renderer";
|
||||||
|
import { addOrRemoveButtonsInjectionToken } from "@k8slens/table";
|
||||||
|
|
||||||
|
const addRemoveButtonsInjectable = getInjectable({
|
||||||
|
id: "add-remove-buttons-component",
|
||||||
|
instantiate: () => ({ Component: AddRemoveButtons }),
|
||||||
|
injectionToken: addOrRemoveButtonsInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default addRemoveButtonsInjectable
|
||||||
10
open-lens/src/renderer/create-table-state.injectable.ts
Normal file
10
open-lens/src/renderer/create-table-state.injectable.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { createTableStateInjectionToken } from "@k8slens/table";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
const createTableStateInjectable = getInjectable({
|
||||||
|
id: "open-lens-table-state",
|
||||||
|
instantiate: () => () => {},
|
||||||
|
injectionToken: createTableStateInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createTableStateInjectable
|
||||||
11
open-lens/src/renderer/table.injectable.ts
Normal file
11
open-lens/src/renderer/table.injectable.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { tableComponentInjectionToken } from "@k8slens/table";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { Table } from "@k8slens/core/renderer";
|
||||||
|
|
||||||
|
const tableComponentInjectable = getInjectable({
|
||||||
|
id: "table-component",
|
||||||
|
instantiate: () => ({ Component: Table }),
|
||||||
|
injectionToken: tableComponentInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tableComponentInjectable
|
||||||
19
package-lock.json
generated
19
package-lock.json
generated
@ -3883,6 +3883,10 @@
|
|||||||
"resolved": "packages/utility-features/startable-stoppable",
|
"resolved": "packages/utility-features/startable-stoppable",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@k8slens/table": {
|
||||||
|
"resolved": "packages/table",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@k8slens/test-utils": {
|
"node_modules/@k8slens/test-utils": {
|
||||||
"resolved": "packages/utility-features/test-utils",
|
"resolved": "packages/utility-features/test-utils",
|
||||||
"link": true
|
"link": true
|
||||||
@ -34013,6 +34017,7 @@
|
|||||||
"@k8slens/routing": "^1.0.0",
|
"@k8slens/routing": "^1.0.0",
|
||||||
"@k8slens/run-many": "^1.0.0",
|
"@k8slens/run-many": "^1.0.0",
|
||||||
"@k8slens/startable-stoppable": "^1.0.0",
|
"@k8slens/startable-stoppable": "^1.0.0",
|
||||||
|
"@k8slens/table": "6.5.0",
|
||||||
"@k8slens/tooltip": "^1.0.0",
|
"@k8slens/tooltip": "^1.0.0",
|
||||||
"@k8slens/utilities": "^1.0.0",
|
"@k8slens/utilities": "^1.0.0",
|
||||||
"@kubernetes/client-node": "^0.18.1",
|
"@kubernetes/client-node": "^0.18.1",
|
||||||
@ -34216,6 +34221,7 @@
|
|||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@k8slens/core",
|
"name": "@k8slens/core",
|
||||||
"version": "6.5.0",
|
"version": "6.5.0",
|
||||||
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@async-fn/jest": "1.6.4",
|
"@async-fn/jest": "1.6.4",
|
||||||
@ -34357,6 +34363,7 @@
|
|||||||
"@k8slens/routing": "^1.0.0-alpha.5",
|
"@k8slens/routing": "^1.0.0-alpha.5",
|
||||||
"@k8slens/run-many": "^1.0.0-alpha.1",
|
"@k8slens/run-many": "^1.0.0-alpha.1",
|
||||||
"@k8slens/startable-stoppable": "^1.0.0-alpha.1",
|
"@k8slens/startable-stoppable": "^1.0.0-alpha.1",
|
||||||
|
"@k8slens/table": "6.5.0",
|
||||||
"@k8slens/tooltip": "^1.0.0-alpha.5",
|
"@k8slens/tooltip": "^1.0.0-alpha.5",
|
||||||
"@k8slens/utilities": "^1.0.0-alpha.1",
|
"@k8slens/utilities": "^1.0.0-alpha.1",
|
||||||
"@kubernetes/client-node": "^0.18.1",
|
"@kubernetes/client-node": "^0.18.1",
|
||||||
@ -35383,6 +35390,18 @@
|
|||||||
"rimraf": "^4.4.1"
|
"rimraf": "^4.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"packages/table": {
|
||||||
|
"name": "@k8slens/table",
|
||||||
|
"version": "6.5.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@k8slens/webpack": "^6.5.0-alpha.8",
|
||||||
|
"rimraf": "^4.4.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@ogre-tools/injectable": "^17.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/technical-features/application/agnostic": {
|
"packages/technical-features/application/agnostic": {
|
||||||
"name": "@k8slens/application",
|
"name": "@k8slens/application",
|
||||||
"version": "6.5.0",
|
"version": "6.5.0",
|
||||||
|
|||||||
@ -55,7 +55,8 @@
|
|||||||
"test:unit": "jest --testPathIgnorePatterns integration",
|
"test:unit": "jest --testPathIgnorePatterns integration",
|
||||||
"test:watch": "func() { jest ${1} --watch --testPathIgnorePatterns integration; }; func",
|
"test:watch": "func() { jest ${1} --watch --testPathIgnorePatterns integration; }; func",
|
||||||
"lint": "PROD=true eslint --ext js,ts,tsx --max-warnings=0 .",
|
"lint": "PROD=true eslint --ext js,ts,tsx --max-warnings=0 .",
|
||||||
"lint:fix": "npm run lint -- --fix"
|
"lint:fix": "npm run lint -- --fix",
|
||||||
|
"postinstall": "linkable"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"k8sProxyVersion": "0.3.0",
|
"k8sProxyVersion": "0.3.0",
|
||||||
@ -238,6 +239,7 @@
|
|||||||
"@k8slens/run-many": "^1.0.0-alpha.1",
|
"@k8slens/run-many": "^1.0.0-alpha.1",
|
||||||
"@k8slens/spinner": "^1.0.0",
|
"@k8slens/spinner": "^1.0.0",
|
||||||
"@k8slens/startable-stoppable": "^1.0.0-alpha.1",
|
"@k8slens/startable-stoppable": "^1.0.0-alpha.1",
|
||||||
|
"@k8slens/table": "6.5.0",
|
||||||
"@k8slens/tooltip": "^1.0.0-alpha.5",
|
"@k8slens/tooltip": "^1.0.0-alpha.5",
|
||||||
"@k8slens/utilities": "^1.0.0-alpha.1",
|
"@k8slens/utilities": "^1.0.0-alpha.1",
|
||||||
"@kubernetes/client-node": "^0.18.1",
|
"@kubernetes/client-node": "^0.18.1",
|
||||||
|
|||||||
@ -11,14 +11,12 @@ import { computed, makeObservable } from "mobx";
|
|||||||
import { Observer, observer } from "mobx-react";
|
import { Observer, observer } from "mobx-react";
|
||||||
import type { ConfirmDialogParams } from "../confirm-dialog";
|
import type { ConfirmDialogParams } from "../confirm-dialog";
|
||||||
import type { TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
import type { TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
||||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
import { TableCell, TableHead, TableRow } from "../table";
|
||||||
import type { IClassName, StrictReactNode } from "@k8slens/utilities";
|
import type { IClassName, StrictReactNode } from "@k8slens/utilities";
|
||||||
import { cssNames, isDefined, isReactNode, noop, prevDefault, stopPropagation } from "@k8slens/utilities";
|
import { cssNames, isDefined, isReactNode, noop, prevDefault, stopPropagation } from "@k8slens/utilities";
|
||||||
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
|
||||||
import { AddRemoveButtons } from "../add-remove-buttons";
|
|
||||||
import { NoItems } from "../no-items";
|
import { NoItems } from "../no-items";
|
||||||
import { Spinner } from "@k8slens/spinner";
|
import { Spinner } from "@k8slens/spinner";
|
||||||
import type { ItemObject, TableCellProps } from "@k8slens/list-layout";
|
import type { GeneralKubeObjectListLayoutColumn, ItemObject, TableCellProps } from "@k8slens/list-layout";
|
||||||
import type { Filter, PageFiltersStore } from "./page-filters/store";
|
import type { Filter, PageFiltersStore } from "./page-filters/store";
|
||||||
import type { LensTheme } from "../../themes/lens-theme";
|
import type { LensTheme } from "../../themes/lens-theme";
|
||||||
import { MenuActions } from "../menu/menu-actions";
|
import { MenuActions } from "../menu/menu-actions";
|
||||||
@ -35,6 +33,9 @@ import type { ToggleTableColumnVisibility } from "../../../features/user-prefere
|
|||||||
import toggleTableColumnVisibilityInjectable from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable";
|
import toggleTableColumnVisibilityInjectable from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable";
|
||||||
import type { IsTableColumnHidden } from "../../../features/user-preferences/common/is-table-column-hidden.injectable";
|
import type { IsTableColumnHidden } from "../../../features/user-preferences/common/is-table-column-hidden.injectable";
|
||||||
import isTableColumnHiddenInjectable from "../../../features/user-preferences/common/is-table-column-hidden.injectable";
|
import isTableColumnHiddenInjectable from "../../../features/user-preferences/common/is-table-column-hidden.injectable";
|
||||||
|
import type { AddOrRemoveButtons, AddRemoveButtonsProps, TableComponent } from "@k8slens/table";
|
||||||
|
import { addOrRemoveButtonsInjectionToken, tableComponentInjectionToken } from "@k8slens/table";
|
||||||
|
import { tableStateInjectable } from "../table/table-state.injectable";
|
||||||
|
|
||||||
export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStores extends boolean> {
|
export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStores extends boolean> {
|
||||||
getFilters: () => Filter[];
|
getFilters: () => Filter[];
|
||||||
@ -54,6 +55,7 @@ export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStor
|
|||||||
customizeTableRowProps?: (item: Item) => Partial<TableRowProps<Item>>;
|
customizeTableRowProps?: (item: Item) => Partial<TableRowProps<Item>>;
|
||||||
addRemoveButtons?: Partial<AddRemoveButtonsProps>;
|
addRemoveButtons?: Partial<AddRemoveButtonsProps>;
|
||||||
virtual?: boolean;
|
virtual?: boolean;
|
||||||
|
columns?: GeneralKubeObjectListLayoutColumn[];
|
||||||
|
|
||||||
// item details view
|
// item details view
|
||||||
hasDetailsView?: boolean;
|
hasDetailsView?: boolean;
|
||||||
@ -79,6 +81,9 @@ interface Dependencies {
|
|||||||
openConfirmDialog: OpenConfirmDialog;
|
openConfirmDialog: OpenConfirmDialog;
|
||||||
toggleTableColumnVisibility: ToggleTableColumnVisibility;
|
toggleTableColumnVisibility: ToggleTableColumnVisibility;
|
||||||
isTableColumnHidden: IsTableColumnHidden;
|
isTableColumnHidden: IsTableColumnHidden;
|
||||||
|
table: TableComponent;
|
||||||
|
addOrRemoveButtons: AddOrRemoveButtons;
|
||||||
|
tableState: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -299,6 +304,7 @@ class NonInjectedItemListLayoutContent<
|
|||||||
const {
|
const {
|
||||||
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks,
|
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks,
|
||||||
detailsItem, className, tableProps = {}, tableId, getItems, activeTheme,
|
detailsItem, className, tableProps = {}, tableId, getItems, activeTheme,
|
||||||
|
table, addOrRemoveButtons, tableState,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const selectedItemId = detailsItem && detailsItem.getId();
|
const selectedItemId = detailsItem && detailsItem.getId();
|
||||||
const classNames = cssNames(className, "box", "grow", activeTheme.get().type);
|
const classNames = cssNames(className, "box", "grow", activeTheme.get().type);
|
||||||
@ -307,7 +313,7 @@ class NonInjectedItemListLayoutContent<
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="items box grow flex column">
|
<div className="items box grow flex column">
|
||||||
<Table
|
<table.Component
|
||||||
tableId={tableId}
|
tableId={tableId}
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
selectable={hasDetailsView}
|
selectable={hasDetailsView}
|
||||||
@ -318,15 +324,16 @@ class NonInjectedItemListLayoutContent<
|
|||||||
selectedItemId={selectedItemId}
|
selectedItemId={selectedItemId}
|
||||||
noItems={this.renderNoItems()}
|
noItems={this.renderNoItems()}
|
||||||
className={classNames}
|
className={classNames}
|
||||||
|
state={tableState}
|
||||||
{...tableProps}
|
{...tableProps}
|
||||||
>
|
>
|
||||||
{this.renderTableHeader()}
|
{this.renderTableHeader()}
|
||||||
{this.renderItems()}
|
{this.renderItems()}
|
||||||
</Table>
|
</table.Component>
|
||||||
|
|
||||||
<Observer>
|
<Observer>
|
||||||
{() => (
|
{() => (
|
||||||
<AddRemoveButtons
|
<addOrRemoveButtons.Component
|
||||||
onRemove={
|
onRemove={
|
||||||
(store.removeItems || store.removeSelectedItems) && selectedItems.length > 0
|
(store.removeItems || store.removeSelectedItems) && selectedItems.length > 0
|
||||||
? () => this.removeItemsDialog(selectedItems)
|
? () => this.removeItemsDialog(selectedItems)
|
||||||
@ -385,5 +392,8 @@ export const ItemListLayoutContent = withInjectables<Dependencies, ItemListLayou
|
|||||||
openConfirmDialog: di.inject(openConfirmDialogInjectable),
|
openConfirmDialog: di.inject(openConfirmDialogInjectable),
|
||||||
toggleTableColumnVisibility: di.inject(toggleTableColumnVisibilityInjectable),
|
toggleTableColumnVisibility: di.inject(toggleTableColumnVisibilityInjectable),
|
||||||
isTableColumnHidden: di.inject(isTableColumnHiddenInjectable),
|
isTableColumnHidden: di.inject(isTableColumnHiddenInjectable),
|
||||||
|
table: di.inject(tableComponentInjectionToken),
|
||||||
|
addOrRemoveButtons: di.inject(addOrRemoveButtonsInjectionToken),
|
||||||
|
tableState: di.inject(tableStateInjectable, props),
|
||||||
}),
|
}),
|
||||||
}) as <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;
|
}) as <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import type { TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
|||||||
import type { IClassName, StrictReactNode, SingleOrMany } from "@k8slens/utilities";
|
import type { IClassName, StrictReactNode, SingleOrMany } from "@k8slens/utilities";
|
||||||
import { cssNames, noop } from "@k8slens/utilities";
|
import { cssNames, noop } from "@k8slens/utilities";
|
||||||
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
||||||
import type { ItemObject, TableCellProps } from "@k8slens/list-layout";
|
import type { ItemObject, TableCellProps, GeneralKubeObjectListLayoutColumn } from "@k8slens/list-layout";
|
||||||
import type { SearchInputUrlProps } from "../input";
|
import type { SearchInputUrlProps } from "../input";
|
||||||
import type { PageFiltersStore } from "./page-filters/store";
|
import type { PageFiltersStore } from "./page-filters/store";
|
||||||
import { FilterType } from "./page-filters/store";
|
import { FilterType } from "./page-filters/store";
|
||||||
@ -98,6 +98,7 @@ export type ItemListLayoutProps<Item extends ItemObject, PreLoadStores extends b
|
|||||||
headerClassName?: IClassName;
|
headerClassName?: IClassName;
|
||||||
renderHeaderTitle?: RenderHeaderTitle<Item, PreLoadStores>;
|
renderHeaderTitle?: RenderHeaderTitle<Item, PreLoadStores>;
|
||||||
customizeHeader?: HeaderCustomizer | HeaderCustomizer[];
|
customizeHeader?: HeaderCustomizer | HeaderCustomizer[];
|
||||||
|
columns?: GeneralKubeObjectListLayoutColumn[];
|
||||||
|
|
||||||
// items list configuration
|
// items list configuration
|
||||||
isReady?: boolean; // show loading indicator while not ready
|
isReady?: boolean; // show loading indicator while not ready
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export interface KubeObjectListLayoutProps<
|
|||||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts, @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line unused-imports/no-unused-vars-ts, @typescript-eslint/no-unused-vars
|
||||||
A extends KubeApi<K, D>,
|
A extends KubeApi<K, D>,
|
||||||
D extends KubeJsonApiDataFor<K>,
|
D extends KubeJsonApiDataFor<K>,
|
||||||
> extends Omit<ItemListLayoutProps<K, false>, "getItems" | "dependentStores" | "preloadStores"> {
|
> extends Omit<ItemListLayoutProps<K, false>, "getItems" | "dependentStores" | "preloadStores" | "columns"> {
|
||||||
items?: K[];
|
items?: K[];
|
||||||
getItems?: () => K[];
|
getItems?: () => K[];
|
||||||
store: KubeItemListStore<K>;
|
store: KubeItemListStore<K>;
|
||||||
@ -193,6 +193,7 @@ class NonInjectedKubeObjectListLayout<
|
|||||||
getItems={() => this.props.items || store.contextItems}
|
getItems={() => this.props.items || store.contextItems}
|
||||||
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
||||||
detailsItem={this.selectedItem}
|
detailsItem={this.selectedItem}
|
||||||
|
columns={targetColumns as GeneralKubeObjectListLayoutColumn[]}
|
||||||
customizeHeader={[
|
customizeHeader={[
|
||||||
({ filters, searchProps, info, ...headerPlaceHolders }) => ({
|
({ filters, searchProps, info, ...headerPlaceHolders }) => ({
|
||||||
filters: (
|
filters: (
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import type { KubeObject } from "@k8slens/kube-object";
|
||||||
|
import type {
|
||||||
|
BaseKubeObjectListLayoutColumn,
|
||||||
|
GeneralKubeObjectListLayoutColumn,
|
||||||
|
SpecificKubeListLayoutColumn,
|
||||||
|
} from "@k8slens/list-layout";
|
||||||
|
import type { ItemListLayoutContentProps } from "../item-object-list/content";
|
||||||
|
|
||||||
|
export type TableContextRequiredDataFromComponentsLayerAbove<
|
||||||
|
K extends KubeObject,
|
||||||
|
> = Pick<
|
||||||
|
ItemListLayoutContentProps<K, any>,
|
||||||
|
| "tableId"
|
||||||
|
| "getFilters"
|
||||||
|
| "renderItemMenu"
|
||||||
|
| "store"
|
||||||
|
| "onDetails"
|
||||||
|
| "hasDetailsView"
|
||||||
|
| "getItems"
|
||||||
|
| "renderTableHeader"
|
||||||
|
| "renderTableContents"
|
||||||
|
| "sortingCallbacks"
|
||||||
|
| "isSelectable"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export interface TableDataContextValue<K extends KubeObject>
|
||||||
|
extends TableContextRequiredDataFromComponentsLayerAbove<K> {
|
||||||
|
columns?: (
|
||||||
|
| BaseKubeObjectListLayoutColumn<K>
|
||||||
|
| SpecificKubeListLayoutColumn<K>
|
||||||
|
| GeneralKubeObjectListLayoutColumn
|
||||||
|
)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TableDataContext = React.createContext<
|
||||||
|
TableDataContextValue<KubeObject>
|
||||||
|
>({} as any);
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MenuActions, MenuItem } from "../menu";
|
||||||
|
import React from "react";
|
||||||
|
import { action, computed } from "mobx";
|
||||||
|
import { isReactNode, stopPropagation } from "@k8slens/utilities";
|
||||||
|
import type { KubeObject } from "@k8slens/kube-object";
|
||||||
|
import { Checkbox } from "../checkbox";
|
||||||
|
import type { TableCellProps } from "@k8slens/list-layout";
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import type { TableDataContextValue } from "./table-data-context";
|
||||||
|
import type { CreateTableState } from "@k8slens/table";
|
||||||
|
import { createTableStateInjectionToken } from "@k8slens/table";
|
||||||
|
|
||||||
|
interface TableDataRow<DataItem = any> {
|
||||||
|
id: string;
|
||||||
|
data: DataItem;
|
||||||
|
index?: number;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableDataColumn<DataItem = any> {
|
||||||
|
id: string;
|
||||||
|
title: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
size?: string;
|
||||||
|
minSize?: number;
|
||||||
|
resizable?: boolean;
|
||||||
|
draggable?: boolean;
|
||||||
|
sortable?: boolean;
|
||||||
|
renderValue?: (row: TableDataRow<DataItem>) => React.ReactNode;
|
||||||
|
sortValue?: (row: TableDataRow<DataItem>, col: TableDataColumn<DataItem>) => string | number;
|
||||||
|
searchValue?: (row: TableDataRow<DataItem>) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createLensTableState<K extends KubeObject>({
|
||||||
|
tableId,
|
||||||
|
getFilters,
|
||||||
|
renderItemMenu,
|
||||||
|
store,
|
||||||
|
onDetails,
|
||||||
|
hasDetailsView,
|
||||||
|
getItems,
|
||||||
|
renderTableHeader,
|
||||||
|
renderTableContents,
|
||||||
|
sortingCallbacks,
|
||||||
|
isSelectable,
|
||||||
|
columns: contextColumns,
|
||||||
|
}: TableDataContextValue<K>, createState: CreateTableState) {
|
||||||
|
const headers = renderTableHeader as Required<TableCellProps>[];
|
||||||
|
|
||||||
|
let headingColumns: TableDataColumn[] = headers.map(
|
||||||
|
({ id: columnId, className, title }, index) => ({
|
||||||
|
id: columnId ?? className,
|
||||||
|
className,
|
||||||
|
resizable: !!columnId,
|
||||||
|
sortable: !!columnId,
|
||||||
|
draggable: !!columnId, // e.g. warning-icon column in pods
|
||||||
|
title,
|
||||||
|
renderValue(row: TableDataRow) {
|
||||||
|
const content =
|
||||||
|
renderTableContents?.(row.data)[index] ??
|
||||||
|
contextColumns
|
||||||
|
?.find((col) => col.id === columnId)
|
||||||
|
?.content?.(row.data);
|
||||||
|
|
||||||
|
if (isReactNode(content)) {
|
||||||
|
return content;
|
||||||
|
} else {
|
||||||
|
const { className, title } = content as TableCellProps;
|
||||||
|
|
||||||
|
return <div className={className}>{title}</div>;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sortValue(row: TableDataRow, col: any) {
|
||||||
|
return sortingCallbacks?.[col.id]?.(row.data) as string;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const checkboxColumn: TableDataColumn = {
|
||||||
|
id: "checkbox",
|
||||||
|
className: "checkbox",
|
||||||
|
draggable: false,
|
||||||
|
sortable: false,
|
||||||
|
resizable: false,
|
||||||
|
get title() {
|
||||||
|
return (
|
||||||
|
<div onClick={stopPropagation}>
|
||||||
|
<Checkbox
|
||||||
|
value={tableState.isSelectedAll.get()}
|
||||||
|
onChange={() => tableState.toggleRowSelectionAll()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
renderValue({ id: rowId }: { id: string | number | symbol }) {
|
||||||
|
return (
|
||||||
|
<div onClick={stopPropagation}>
|
||||||
|
<Checkbox
|
||||||
|
value={tableState.selectedRowsId.has(rowId)}
|
||||||
|
onChange={action(() => {
|
||||||
|
if (tableState.selectedRowsId.has(rowId)) {
|
||||||
|
tableState.selectedRowsId.delete(rowId);
|
||||||
|
} else {
|
||||||
|
tableState.selectedRowsId.add(rowId);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuColumn: TableDataColumn = {
|
||||||
|
id: "menu",
|
||||||
|
className: "menu",
|
||||||
|
resizable: false,
|
||||||
|
sortable: false,
|
||||||
|
draggable: false,
|
||||||
|
get title() {
|
||||||
|
return (
|
||||||
|
<MenuActions
|
||||||
|
id={`menu-actions-for-item-object-list-content-${tableId}`}
|
||||||
|
className="ItemListLayoutVisibilityMenu"
|
||||||
|
toolbar={false}
|
||||||
|
autoCloseOnSelect={false}
|
||||||
|
>
|
||||||
|
{headers
|
||||||
|
.filter((headerCell) => !headerCell.showWithColumn)
|
||||||
|
.map(({ id: columnId, title, className }) => (
|
||||||
|
<MenuItem key={columnId} className="input">
|
||||||
|
<Checkbox
|
||||||
|
label={title ?? className}
|
||||||
|
value={!tableState.hiddenColumns.has(columnId)}
|
||||||
|
onChange={action(() => {
|
||||||
|
if (tableState.hiddenColumns.has(columnId)) {
|
||||||
|
tableState.hiddenColumns.delete(columnId);
|
||||||
|
} else {
|
||||||
|
tableState.hiddenColumns.add(columnId);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</MenuActions>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
renderValue(row: any) {
|
||||||
|
return (
|
||||||
|
<div onClick={stopPropagation}>{renderItemMenu?.(row.data, store)}</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isSelectable) {
|
||||||
|
headingColumns = [checkboxColumn, ...headingColumns];
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableState = createState({
|
||||||
|
dataItems: computed(getItems),
|
||||||
|
headingColumns: [...headingColumns, menuColumn],
|
||||||
|
|
||||||
|
searchBox: computed(() => {
|
||||||
|
return getFilters().find((item) => item.type === "search")?.value ?? "";
|
||||||
|
}),
|
||||||
|
|
||||||
|
customizeRows: () => ({
|
||||||
|
className: `${hasDetailsView ? "withDetails" : ""}`,
|
||||||
|
onSelect(row: any, evt: any) {
|
||||||
|
if (evt.isPropagationStopped()) {
|
||||||
|
return; // e.g. click on `checkbox` (== select row)
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.stopPropagation();
|
||||||
|
evt.preventDefault();
|
||||||
|
onDetails?.(row.data);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return tableState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tableStateInjectable = getInjectable({
|
||||||
|
id: "table-state",
|
||||||
|
instantiate(di, context: TableDataContextValue<any>) {
|
||||||
|
const createState = di.inject(createTableStateInjectionToken);
|
||||||
|
|
||||||
|
return createLensTableState(context, createState);
|
||||||
|
},
|
||||||
|
lifecycle: lifecycleEnum.transient,
|
||||||
|
});
|
||||||
@ -22,3 +22,5 @@ export * as ReactRouterDom from "react-router-dom";
|
|||||||
export * as rendererExtensionApi from "../extensions/renderer-api";
|
export * as rendererExtensionApi from "../extensions/renderer-api";
|
||||||
export * as commonExtensionApi from "../extensions/common-api";
|
export * as commonExtensionApi from "../extensions/common-api";
|
||||||
export { metricsFeature } from "../features/metrics/metrics-feature";
|
export { metricsFeature } from "../features/metrics/metrics-feature";
|
||||||
|
export * from "./components/table";
|
||||||
|
export * from "./components/add-remove-buttons";
|
||||||
|
|||||||
15
packages/core/src/test-env/add-remove-buttons.injectable.ts
Normal file
15
packages/core/src/test-env/add-remove-buttons.injectable.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* 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 { addOrRemoveButtonsInjectionToken } from "@k8slens/table";
|
||||||
|
import { AddRemoveButtons } from "../renderer/components/add-remove-buttons";
|
||||||
|
|
||||||
|
const addRemoveButtonsInjectable = getInjectable({
|
||||||
|
id: "add-remove-buttons-component",
|
||||||
|
instantiate: () => ({ Component: AddRemoveButtons }),
|
||||||
|
injectionToken: addOrRemoveButtonsInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default addRemoveButtonsInjectable;
|
||||||
14
packages/core/src/test-env/create-table-state.injectable.ts
Normal file
14
packages/core/src/test-env/create-table-state.injectable.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { createTableStateInjectionToken } from "@k8slens/table";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
const createTableStateInjectable = getInjectable({
|
||||||
|
id: "open-lens-table-state",
|
||||||
|
instantiate: () => () => {},
|
||||||
|
injectionToken: createTableStateInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createTableStateInjectable;
|
||||||
15
packages/core/src/test-env/table.injectable.ts
Normal file
15
packages/core/src/test-env/table.injectable.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { tableComponentInjectionToken } from "@k8slens/table";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { Table } from "../renderer/components/table";
|
||||||
|
|
||||||
|
const tableComponentInjectable = getInjectable({
|
||||||
|
id: "table-component",
|
||||||
|
instantiate: () => ({ Component: Table }),
|
||||||
|
injectionToken: tableComponentInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tableComponentInjectable;
|
||||||
3
packages/table/README.md
Normal file
3
packages/table/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Description
|
||||||
|
|
||||||
|
The package exports tokens needed for table configuration.
|
||||||
61
packages/table/index.ts
Normal file
61
packages/table/index.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { KubeObject } from "@k8slens/kube-object";
|
||||||
|
import type {
|
||||||
|
BaseKubeObjectListLayoutColumn,
|
||||||
|
GeneralKubeObjectListLayoutColumn,
|
||||||
|
SpecificKubeListLayoutColumn,
|
||||||
|
} from "@k8slens/list-layout";
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import type { IComputedValue, IObservableValue } from "mobx";
|
||||||
|
|
||||||
|
type Column = (
|
||||||
|
| BaseKubeObjectListLayoutColumn<KubeObject>
|
||||||
|
| SpecificKubeListLayoutColumn<KubeObject>
|
||||||
|
| GeneralKubeObjectListLayoutColumn
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface TableComponentProps {
|
||||||
|
tableId?: string;
|
||||||
|
columns?: Column[];
|
||||||
|
save?: (state: object) => void;
|
||||||
|
load?: (tableId: string) => object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableComponent {
|
||||||
|
Component: React.ComponentType<TableComponentProps & { state: any }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddRemoveButtonsProps extends React.HTMLAttributes<any> {
|
||||||
|
onAdd?: () => void;
|
||||||
|
onRemove?: () => void;
|
||||||
|
addTooltip?: React.ReactNode;
|
||||||
|
removeTooltip?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddOrRemoveButtons {
|
||||||
|
Component: React.ComponentType<AddRemoveButtonsProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateTableState = (params: {
|
||||||
|
dataItems: IComputedValue<any[]>;
|
||||||
|
headingColumns: object[];
|
||||||
|
customizeRows?: (row: object) => object;
|
||||||
|
getRowId?: (dataItem: any) => string | number | symbol;
|
||||||
|
searchBox?: IComputedValue<string> | IObservableValue<string>;
|
||||||
|
}) => any;
|
||||||
|
|
||||||
|
export const tableComponentInjectionToken = getInjectionToken<TableComponent>({
|
||||||
|
id: "table-component-injection-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addOrRemoveButtonsInjectionToken = getInjectionToken<AddOrRemoveButtons>({
|
||||||
|
id: "add-or-remove-buttons-injection-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createTableStateInjectionToken = getInjectionToken<CreateTableState>({
|
||||||
|
id: "create-table-state-injection-token",
|
||||||
|
})
|
||||||
28
packages/table/package.json
Normal file
28
packages/table/package.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "@k8slens/table",
|
||||||
|
"version": "6.5.0",
|
||||||
|
"description": "Injection tokens for table and related components",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "commonjs",
|
||||||
|
"private": false,
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"registry": "https://registry.npmjs.org/"
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist/",
|
||||||
|
"build": "lens-webpack-build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@k8slens/webpack": "^6.5.0-alpha.8",
|
||||||
|
"rimraf": "^4.4.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@ogre-tools/injectable": "^17.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
4
packages/table/tsconfig.json
Normal file
4
packages/table/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "@k8slens/typescript/config/base.json",
|
||||||
|
"include": ["**/*.ts"]
|
||||||
|
}
|
||||||
1
packages/table/webpack.config.js
Normal file
1
packages/table/webpack.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("@k8slens/webpack").configForNode;
|
||||||
Loading…
Reference in New Issue
Block a user