mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Persist column size changes in UserStore
Signed-off-by: Alex Culliere <alozhkin@mirantis.com>
This commit is contained in:
parent
74785e2fbc
commit
40a54a886c
@ -45,18 +45,6 @@ describe("user store tests", () => {
|
|||||||
expect(us.seenContexts.has("bar")).toBe(true);
|
expect(us.seenContexts.has("bar")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows setting and getting preferences", () => {
|
|
||||||
const us = UserStore.getInstance<UserStore>();
|
|
||||||
|
|
||||||
us.preferences.httpsProxy = "abcd://defg";
|
|
||||||
|
|
||||||
expect(us.preferences.httpsProxy).toBe("abcd://defg");
|
|
||||||
expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme);
|
|
||||||
|
|
||||||
us.preferences.colorTheme = "light";
|
|
||||||
expect(us.preferences.colorTheme).toBe("light");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("correctly resets theme to default value", async () => {
|
it("correctly resets theme to default value", async () => {
|
||||||
const us = UserStore.getInstance<UserStore>();
|
const us = UserStore.getInstance<UserStore>();
|
||||||
|
|
||||||
@ -77,6 +65,32 @@ describe("user store tests", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("preferences", () => {
|
||||||
|
it("allows setting and getting preferences", () => {
|
||||||
|
const us = UserStore.getInstance<UserStore>();
|
||||||
|
|
||||||
|
us.preferences.httpsProxy = "abcd://defg";
|
||||||
|
|
||||||
|
expect(us.preferences.httpsProxy).toBe("abcd://defg");
|
||||||
|
expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme);
|
||||||
|
|
||||||
|
us.preferences.colorTheme = "light";
|
||||||
|
expect(us.preferences.colorTheme).toBe("light");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows setting and getting table column sizes", () => {
|
||||||
|
const us = UserStore.getInstance<UserStore>();
|
||||||
|
const [clusterId, tableId] = ["foo", "bar"];
|
||||||
|
|
||||||
|
expect( us.getTableSizing(clusterId, tableId) ).toStrictEqual([]);
|
||||||
|
|
||||||
|
const sizes = [100, 150, 70, 400];
|
||||||
|
|
||||||
|
us.setTableSizing(clusterId, tableId, sizes);
|
||||||
|
expect( us.getTableSizing(clusterId, tableId) ).toStrictEqual(sizes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("migrations", () => {
|
describe("migrations", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
UserStore.resetInstance();
|
UserStore.resetInstance();
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import { ClusterId } from "./cluster-store";
|
import { ClusterId } from "./cluster-store";
|
||||||
|
|
||||||
export type TableId = string;
|
|
||||||
export type TableSizeRecord = Record<TableId, number[]>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a configuration of table column sizes, set by the user,
|
* Stores a configuration of table column sizes, set by the user,
|
||||||
* for each table by `TableId`, for each cluster by `ClusterId`
|
* for each talbe by `tableId`
|
||||||
|
*/
|
||||||
|
export type TableSizeRecord = Record<string, number[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a configuration of table column sizes, set by the user,
|
||||||
|
* for each table by `tableId`, for each cluster by `ClusterId`
|
||||||
*/
|
*/
|
||||||
export type TableSizeConfig = Record<ClusterId, TableSizeRecord>;
|
export type TableSizeConfig = Record<ClusterId, TableSizeRecord>;
|
||||||
|
|||||||
@ -92,6 +92,23 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
return semver.gt(getAppVersion(), this.lastSeenAppVersion);
|
return semver.gt(getAppVersion(), this.lastSeenAppVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setTableSizing(clusterId: string, tableId: string, sizes: number[]) {
|
||||||
|
const { tableSizeConfig: config } = this.preferences;
|
||||||
|
|
||||||
|
if (!config[clusterId]) {
|
||||||
|
config[clusterId] = { [tableId]: sizes };
|
||||||
|
} else {
|
||||||
|
config[clusterId][tableId] = sizes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableSizing(clusterId: string, tableId: string): number[] {
|
||||||
|
const { tableSizeConfig: config } = this.preferences;
|
||||||
|
|
||||||
|
return config[clusterId]?.[tableId] || [];
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
setHiddenTableColumns(tableId: string, names: Set<string> | string[]) {
|
setHiddenTableColumns(tableId: string, names: Set<string> | string[]) {
|
||||||
this.preferences.hiddenTableColumns[tableId] = Array.from(names);
|
this.preferences.hiddenTableColumns[tableId] = Array.from(names);
|
||||||
|
|||||||
@ -51,6 +51,31 @@ import { CommandContainer } from "./command-palette/command-container";
|
|||||||
import { KubeObjectStore } from "../kube-object.store";
|
import { KubeObjectStore } from "../kube-object.store";
|
||||||
import { clusterContext } from "./context";
|
import { clusterContext } from "./context";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hacking into document event listeners to detect leaks
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
|
(function watchEvent() {
|
||||||
|
const addOne = document.addEventListener;
|
||||||
|
const removeOne = document.removeEventListener;
|
||||||
|
|
||||||
|
(document as any)["listeners"] = new Map<any, any>();
|
||||||
|
|
||||||
|
document.addEventListener = (type: string, listener: any) => {
|
||||||
|
const registry: Map<any, any> = (document as any)["listeners"];
|
||||||
|
|
||||||
|
registry.set(listener, type);
|
||||||
|
addOne(type, listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.removeEventListener = (type: string, listener: any) => {
|
||||||
|
const registry: Map<any, any> = (document as any)["listeners"];
|
||||||
|
|
||||||
|
registry.delete(listener);
|
||||||
|
removeOne(type, listener);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class App extends React.Component {
|
export class App extends React.Component {
|
||||||
static async init() {
|
static async init() {
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export interface IHeaderPlaceholders {
|
|||||||
|
|
||||||
export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
||||||
tableId?: string;
|
tableId?: string;
|
||||||
|
clusterId?: string;
|
||||||
className: IClassName;
|
className: IClassName;
|
||||||
items?: T[];
|
items?: T[];
|
||||||
store: ItemStore<T>;
|
store: ItemStore<T>;
|
||||||
@ -112,6 +113,18 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observable cellSizes: number[];
|
@observable cellSizes: number[];
|
||||||
|
get persistentCellSizes(): number[] {
|
||||||
|
const { clusterId, tableId, renderTableHeader: { length } } = this.props;
|
||||||
|
const savedSizes = userStore.getTableSizing(clusterId, tableId);
|
||||||
|
|
||||||
|
return savedSizes.length !== length ? new Array<number>(length) : savedSizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
set persistentCellSizes(sizes: number[]) {
|
||||||
|
const { clusterId, tableId } = this.props;
|
||||||
|
|
||||||
|
userStore.setTableSizing(clusterId, tableId, sizes);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props: ItemListLayoutProps) {
|
constructor(props: ItemListLayoutProps) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -121,12 +134,16 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const { isClusterScoped, isConfigurable, tableId, preloadStores } = this.props;
|
const { isClusterScoped, isConfigurable, tableId, preloadStores, isResizable } = this.props;
|
||||||
|
|
||||||
if (isConfigurable && !tableId) {
|
if (isConfigurable && !tableId) {
|
||||||
throw new Error("[ItemListLayout]: configurable list require props.tableId to be specified");
|
throw new Error("[ItemListLayout]: configurable list require props.tableId to be specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isResizable) {
|
||||||
|
this.cellSizes = this.persistentCellSizes;
|
||||||
|
}
|
||||||
|
|
||||||
if (preloadStores) {
|
if (preloadStores) {
|
||||||
this.loadStores();
|
this.loadStores();
|
||||||
|
|
||||||
@ -218,6 +235,11 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
return this.applyFilters(filterItems.concat(this.props.filterItems), items);
|
return this.applyFilters(filterItems.concat(this.props.filterItems), items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
persistCellSizes() {
|
||||||
|
console.log("Persisting sizes");
|
||||||
|
this.persistentCellSizes = this.cellSizes;
|
||||||
|
}
|
||||||
|
|
||||||
handleCellResize(index: number, width: number) {
|
handleCellResize(index: number, width: number) {
|
||||||
this.cellSizes[index] = width;
|
this.cellSizes[index] = width;
|
||||||
}
|
}
|
||||||
@ -268,6 +290,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
|
|
||||||
if (resizable) {
|
if (resizable) {
|
||||||
cellProps._onResize = width => this.handleCellResize(index, width);
|
cellProps._onResize = width => this.handleCellResize(index, width);
|
||||||
|
cellProps._onResizeComplete = () => this.persistCellSizes();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!headCell || !this.isHiddenColumn(headCell)) {
|
if (!headCell || !this.isHiddenColumn(headCell)) {
|
||||||
@ -404,7 +427,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderTableHeader() {
|
renderTableHeader() {
|
||||||
const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store, isResizable: resizable } = this.props;
|
const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store, isResizable } = this.props;
|
||||||
|
|
||||||
if (!renderTableHeader) {
|
if (!renderTableHeader) {
|
||||||
return;
|
return;
|
||||||
@ -423,9 +446,13 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
)}
|
)}
|
||||||
{renderTableHeader.map((cellProps, index) => {
|
{renderTableHeader.map((cellProps, index) => {
|
||||||
const cellSize = this.cellSizes[index];
|
const cellSize = this.cellSizes[index];
|
||||||
const _cellProps = resizable ?
|
const _cellProps = isResizable ?
|
||||||
{ ...cellProps, _onResize: (width: number) => this.handleCellResize(index, width), resizable } :
|
{
|
||||||
cellProps;
|
...cellProps,
|
||||||
|
_onResize: (width: number) => this.handleCellResize(index, width),
|
||||||
|
_onResizeComplete: () => this.persistCellSizes(),
|
||||||
|
isResizable
|
||||||
|
} : cellProps;
|
||||||
|
|
||||||
if (cellSize !== undefined) {
|
if (cellSize !== undefined) {
|
||||||
_cellProps.size = cellSize;
|
_cellProps.size = cellSize;
|
||||||
|
|||||||
@ -49,6 +49,7 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
|
|||||||
isResizable
|
isResizable
|
||||||
{...layoutProps}
|
{...layoutProps}
|
||||||
className={cssNames("KubeObjectListLayout", className)}
|
className={cssNames("KubeObjectListLayout", className)}
|
||||||
|
clusterId={store.context.cluster.id}
|
||||||
store={store}
|
store={store}
|
||||||
items={items}
|
items={items}
|
||||||
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
|
|||||||
_sort?(sortBy: TableSortBy): void; // <Table> sort function, don't use this prop outside (!)
|
_sort?(sortBy: TableSortBy): void; // <Table> sort function, don't use this prop outside (!)
|
||||||
_nowrap?: boolean; // indicator, might come from parent <TableHead>, don't use this prop outside (!)
|
_nowrap?: boolean; // indicator, might come from parent <TableHead>, don't use this prop outside (!)
|
||||||
_onResize?(width: number): void; // <Table> resize callbalck, don't use this prop outside (!)
|
_onResize?(width: number): void; // <Table> resize callbalck, don't use this prop outside (!)
|
||||||
|
_onResizeComplete?(): void; // triggers a callback when user stops resizing
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResizeHandlerState = {
|
type ResizeHandlerState = {
|
||||||
@ -104,6 +105,8 @@ export class TableCell extends React.Component<TableCellProps> {
|
|||||||
|
|
||||||
mouseUpHandler() {
|
mouseUpHandler() {
|
||||||
this.removeMouseEventListeners();
|
this.removeMouseEventListeners();
|
||||||
|
console.log((document as any)["listeners"]);
|
||||||
|
this.props?._onResizeComplete();
|
||||||
this.resizeHandlerState = undefined;
|
this.resizeHandlerState = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user