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);
|
||||
});
|
||||
|
||||
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 () => {
|
||||
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", () => {
|
||||
beforeEach(() => {
|
||||
UserStore.resetInstance();
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
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,
|
||||
* 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>;
|
||||
|
||||
@ -92,6 +92,23 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
||||
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
|
||||
setHiddenTableColumns(tableId: string, names: Set<string> | string[]) {
|
||||
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 { 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
|
||||
export class App extends React.Component {
|
||||
static async init() {
|
||||
|
||||
@ -37,6 +37,7 @@ export interface IHeaderPlaceholders {
|
||||
|
||||
export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
||||
tableId?: string;
|
||||
clusterId?: string;
|
||||
className: IClassName;
|
||||
items?: T[];
|
||||
store: ItemStore<T>;
|
||||
@ -112,6 +113,18 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
}
|
||||
|
||||
@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) {
|
||||
super(props);
|
||||
@ -121,12 +134,16 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { isClusterScoped, isConfigurable, tableId, preloadStores } = this.props;
|
||||
const { isClusterScoped, isConfigurable, tableId, preloadStores, isResizable } = this.props;
|
||||
|
||||
if (isConfigurable && !tableId) {
|
||||
throw new Error("[ItemListLayout]: configurable list require props.tableId to be specified");
|
||||
}
|
||||
|
||||
if (isResizable) {
|
||||
this.cellSizes = this.persistentCellSizes;
|
||||
}
|
||||
|
||||
if (preloadStores) {
|
||||
this.loadStores();
|
||||
|
||||
@ -218,6 +235,11 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
return this.applyFilters(filterItems.concat(this.props.filterItems), items);
|
||||
}
|
||||
|
||||
persistCellSizes() {
|
||||
console.log("Persisting sizes");
|
||||
this.persistentCellSizes = this.cellSizes;
|
||||
}
|
||||
|
||||
handleCellResize(index: number, width: number) {
|
||||
this.cellSizes[index] = width;
|
||||
}
|
||||
@ -268,6 +290,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
|
||||
if (resizable) {
|
||||
cellProps._onResize = width => this.handleCellResize(index, width);
|
||||
cellProps._onResizeComplete = () => this.persistCellSizes();
|
||||
}
|
||||
|
||||
if (!headCell || !this.isHiddenColumn(headCell)) {
|
||||
@ -404,7 +427,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
}
|
||||
|
||||
renderTableHeader() {
|
||||
const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store, isResizable: resizable } = this.props;
|
||||
const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store, isResizable } = this.props;
|
||||
|
||||
if (!renderTableHeader) {
|
||||
return;
|
||||
@ -423,9 +446,13 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
)}
|
||||
{renderTableHeader.map((cellProps, index) => {
|
||||
const cellSize = this.cellSizes[index];
|
||||
const _cellProps = resizable ?
|
||||
{ ...cellProps, _onResize: (width: number) => this.handleCellResize(index, width), resizable } :
|
||||
cellProps;
|
||||
const _cellProps = isResizable ?
|
||||
{
|
||||
...cellProps,
|
||||
_onResize: (width: number) => this.handleCellResize(index, width),
|
||||
_onResizeComplete: () => this.persistCellSizes(),
|
||||
isResizable
|
||||
} : cellProps;
|
||||
|
||||
if (cellSize !== undefined) {
|
||||
_cellProps.size = cellSize;
|
||||
|
||||
@ -49,6 +49,7 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
|
||||
isResizable
|
||||
{...layoutProps}
|
||||
className={cssNames("KubeObjectListLayout", className)}
|
||||
clusterId={store.context.cluster.id}
|
||||
store={store}
|
||||
items={items}
|
||||
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 (!)
|
||||
_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 (!)
|
||||
_onResizeComplete?(): void; // triggers a callback when user stops resizing
|
||||
}
|
||||
|
||||
type ResizeHandlerState = {
|
||||
@ -104,6 +105,8 @@ export class TableCell extends React.Component<TableCellProps> {
|
||||
|
||||
mouseUpHandler() {
|
||||
this.removeMouseEventListeners();
|
||||
console.log((document as any)["listeners"]);
|
||||
this.props?._onResizeComplete();
|
||||
this.resizeHandlerState = undefined;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user