mirror of https://github.com/apache/superset.git
chore: Refactor localstorage into typesafe version (#17832)
This commit is contained in:
parent
e3b44f4825
commit
6edc183c5f
|
@ -237,14 +237,14 @@ const config: ControlPanelConfig = {
|
||||||
],
|
],
|
||||||
renderTrigger: true,
|
renderTrigger: true,
|
||||||
description: (
|
description: (
|
||||||
<React.Fragment>
|
<>
|
||||||
<div>{t('Change order of rows.')}</div>
|
<div>{t('Change order of rows.')}</div>
|
||||||
<div>{t('Available sorting modes:')}</div>
|
<div>{t('Available sorting modes:')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>{t('By key: use row names as sorting key')}</li>
|
<li>{t('By key: use row names as sorting key')}</li>
|
||||||
<li>{t('By value: use metric values as sorting key')}</li>
|
<li>{t('By value: use metric values as sorting key')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</React.Fragment>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -265,14 +265,14 @@ const config: ControlPanelConfig = {
|
||||||
],
|
],
|
||||||
renderTrigger: true,
|
renderTrigger: true,
|
||||||
description: (
|
description: (
|
||||||
<React.Fragment>
|
<>
|
||||||
<div>{t('Change order of columns.')}</div>
|
<div>{t('Change order of columns.')}</div>
|
||||||
<div>{t('Available sorting modes:')}</div>
|
<div>{t('Available sorting modes:')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>{t('By key: use column names as sorting key')}</li>
|
<li>{t('By key: use column names as sorting key')}</li>
|
||||||
<li>{t('By value: use metric values as sorting key')}</li>
|
<li>{t('By value: use metric values as sorting key')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</React.Fragment>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,13 +36,13 @@ import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||||
import { addWarningToast } from 'src/components/MessageToasts/actions';
|
import { addWarningToast } from 'src/components/MessageToasts/actions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import {
|
import {
|
||||||
FILTER_BOX_MIGRATION_STATES,
|
FILTER_BOX_MIGRATION_STATES,
|
||||||
FILTER_BOX_TRANSITION_SNOOZE_DURATION,
|
FILTER_BOX_TRANSITION_SNOOZE_DURATION,
|
||||||
FILTER_BOX_TRANSITION_SNOOZED_AT,
|
|
||||||
} from 'src/explore/constants';
|
} from 'src/explore/constants';
|
||||||
import { URL_PARAMS } from 'src/constants';
|
import { URL_PARAMS } from 'src/constants';
|
||||||
import { getUrlParam } from 'src/utils/urlUtils';
|
import { getUrlParam } from 'src/utils/urlUtils';
|
||||||
|
@ -126,8 +126,10 @@ const DashboardPage: FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// has cookie?
|
// has cookie?
|
||||||
const snoozeDash =
|
const snoozeDash = getItem(
|
||||||
getFromLocalStorage(FILTER_BOX_TRANSITION_SNOOZED_AT, 0) || {};
|
LocalStorageKeys.filter_box_transition_snoozed_at,
|
||||||
|
{},
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
Date.now() - (snoozeDash[id] || 0) <
|
Date.now() - (snoozeDash[id] || 0) <
|
||||||
FILTER_BOX_TRANSITION_SNOOZE_DURATION
|
FILTER_BOX_TRANSITION_SNOOZE_DURATION
|
||||||
|
@ -210,9 +212,11 @@ const DashboardPage: FC = () => {
|
||||||
setFilterboxMigrationState(FILTER_BOX_MIGRATION_STATES.REVIEWING);
|
setFilterboxMigrationState(FILTER_BOX_MIGRATION_STATES.REVIEWING);
|
||||||
}}
|
}}
|
||||||
onClickSnooze={() => {
|
onClickSnooze={() => {
|
||||||
const snoozedDash =
|
const snoozedDash = getItem(
|
||||||
getFromLocalStorage(FILTER_BOX_TRANSITION_SNOOZED_AT, 0) || {};
|
LocalStorageKeys.filter_box_transition_snoozed_at,
|
||||||
setInLocalStorage(FILTER_BOX_TRANSITION_SNOOZED_AT, {
|
{},
|
||||||
|
);
|
||||||
|
setItem(LocalStorageKeys.filter_box_transition_snoozed_at, {
|
||||||
...snoozedDash,
|
...snoozedDash,
|
||||||
[id]: Date.now(),
|
[id]: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,8 +25,9 @@ import TableView, { EmptyWrapperType } from 'src/components/TableView';
|
||||||
import { getChartDataRequest } from 'src/chart/chartAction';
|
import { getChartDataRequest } from 'src/chart/chartAction';
|
||||||
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
|
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import {
|
import {
|
||||||
CopyToClipboardButton,
|
CopyToClipboardButton,
|
||||||
|
@ -49,10 +50,6 @@ const NULLISH_RESULTS_STATE = {
|
||||||
|
|
||||||
const DATA_TABLE_PAGE_SIZE = 50;
|
const DATA_TABLE_PAGE_SIZE = 50;
|
||||||
|
|
||||||
const STORAGE_KEYS = {
|
|
||||||
isOpen: 'is_datapanel_open',
|
|
||||||
};
|
|
||||||
|
|
||||||
const DATAPANEL_KEY = 'data';
|
const DATAPANEL_KEY = 'data';
|
||||||
|
|
||||||
const TableControlsWrapper = styled.div`
|
const TableControlsWrapper = styled.div`
|
||||||
|
@ -200,7 +197,7 @@ export const DataTablesPane = ({
|
||||||
[RESULT_TYPES.samples]?: boolean;
|
[RESULT_TYPES.samples]?: boolean;
|
||||||
}>(NULLISH_RESULTS_STATE);
|
}>(NULLISH_RESULTS_STATE);
|
||||||
const [panelOpen, setPanelOpen] = useState(
|
const [panelOpen, setPanelOpen] = useState(
|
||||||
getFromLocalStorage(STORAGE_KEYS.isOpen, false),
|
getItem(LocalStorageKeys.is_datapanel_open, false),
|
||||||
);
|
);
|
||||||
|
|
||||||
const formattedData = useMemo(
|
const formattedData = useMemo(
|
||||||
|
@ -283,7 +280,7 @@ export const DataTablesPane = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInLocalStorage(STORAGE_KEYS.isOpen, panelOpen);
|
setItem(LocalStorageKeys.is_datapanel_open, panelOpen);
|
||||||
}, [panelOpen]);
|
}, [panelOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -24,8 +24,9 @@ import { useResizeDetector } from 'react-resize-detector';
|
||||||
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
||||||
import ChartContainer from 'src/chart/ChartContainer';
|
import ChartContainer from 'src/chart/ChartContainer';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import ConnectedExploreChartHeader from './ExploreChartHeader';
|
import ConnectedExploreChartHeader from './ExploreChartHeader';
|
||||||
import { DataTablesPane } from './DataTablesPane';
|
import { DataTablesPane } from './DataTablesPane';
|
||||||
|
@ -64,10 +65,6 @@ const CHART_PANEL_PADDING_HORIZ = 30;
|
||||||
const CHART_PANEL_PADDING_VERTICAL = 15;
|
const CHART_PANEL_PADDING_VERTICAL = 15;
|
||||||
const HEADER_PADDING = 15;
|
const HEADER_PADDING = 15;
|
||||||
|
|
||||||
const STORAGE_KEYS = {
|
|
||||||
sizes: 'chart_split_sizes',
|
|
||||||
};
|
|
||||||
|
|
||||||
const INITIAL_SIZES = [90, 10];
|
const INITIAL_SIZES = [90, 10];
|
||||||
const MIN_SIZES = [300, 50];
|
const MIN_SIZES = [300, 50];
|
||||||
const DEFAULT_SOUTH_PANE_HEIGHT_PERCENT = 40;
|
const DEFAULT_SOUTH_PANE_HEIGHT_PERCENT = 40;
|
||||||
|
@ -126,7 +123,7 @@ const ExploreChartPanel = props => {
|
||||||
refreshRate: 300,
|
refreshRate: 300,
|
||||||
});
|
});
|
||||||
const [splitSizes, setSplitSizes] = useState(
|
const [splitSizes, setSplitSizes] = useState(
|
||||||
getFromLocalStorage(STORAGE_KEYS.sizes, INITIAL_SIZES),
|
getItem(LocalStorageKeys.chart_split_sizes, INITIAL_SIZES),
|
||||||
);
|
);
|
||||||
const { slice } = props;
|
const { slice } = props;
|
||||||
const updateQueryContext = useCallback(
|
const updateQueryContext = useCallback(
|
||||||
|
@ -192,7 +189,7 @@ const ExploreChartPanel = props => {
|
||||||
}, [recalcPanelSizes, splitSizes]);
|
}, [recalcPanelSizes, splitSizes]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInLocalStorage(STORAGE_KEYS.sizes, splitSizes);
|
setItem(LocalStorageKeys.chart_split_sizes, splitSizes);
|
||||||
}, [splitSizes]);
|
}, [splitSizes]);
|
||||||
|
|
||||||
const onDragEnd = sizes => {
|
const onDragEnd = sizes => {
|
||||||
|
|
|
@ -32,8 +32,9 @@ import { usePrevious } from 'src/common/hooks/usePrevious';
|
||||||
import { useComponentDidMount } from 'src/common/hooks/useComponentDidMount';
|
import { useComponentDidMount } from 'src/common/hooks/useComponentDidMount';
|
||||||
import Icons from 'src/components/Icons';
|
import Icons from 'src/components/Icons';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import { URL_PARAMS } from 'src/constants';
|
import { URL_PARAMS } from 'src/constants';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
|
@ -183,11 +184,6 @@ function ExploreViewContainer(props) {
|
||||||
? `${props.forcedHeight}px`
|
? `${props.forcedHeight}px`
|
||||||
: `${windowSize.height - navHeight}px`;
|
: `${windowSize.height - navHeight}px`;
|
||||||
|
|
||||||
const storageKeys = {
|
|
||||||
controlsWidth: 'controls_width',
|
|
||||||
dataSourceWidth: 'datasource_width',
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultSidebarsWidth = {
|
const defaultSidebarsWidth = {
|
||||||
controls_width: 320,
|
controls_width: 320,
|
||||||
datasource_width: 300,
|
datasource_width: 300,
|
||||||
|
@ -455,12 +451,12 @@ function ExploreViewContainer(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSidebarWidths(key) {
|
function getSidebarWidths(key) {
|
||||||
return getFromLocalStorage(key, defaultSidebarsWidth[key]);
|
return getItem(key, defaultSidebarsWidth[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSidebarWidths(key, dimension) {
|
function setSidebarWidths(key, dimension) {
|
||||||
const newDimension = Number(getSidebarWidths(key)) + dimension.width;
|
const newDimension = Number(getSidebarWidths(key)) + dimension.width;
|
||||||
setInLocalStorage(key, newDimension);
|
setItem(key, newDimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.standalone) {
|
if (props.standalone) {
|
||||||
|
@ -504,13 +500,13 @@ function ExploreViewContainer(props) {
|
||||||
)}
|
)}
|
||||||
<Resizable
|
<Resizable
|
||||||
onResizeStop={(evt, direction, ref, d) =>
|
onResizeStop={(evt, direction, ref, d) =>
|
||||||
setSidebarWidths(storageKeys.dataSourceWidth, d)
|
setSidebarWidths(LocalStorageKeys.datasource_width, d)
|
||||||
}
|
}
|
||||||
defaultSize={{
|
defaultSize={{
|
||||||
width: getSidebarWidths(storageKeys.dataSourceWidth),
|
width: getSidebarWidths(LocalStorageKeys.datasource_width),
|
||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
minWidth={defaultSidebarsWidth[storageKeys.dataSourceWidth]}
|
minWidth={defaultSidebarsWidth[LocalStorageKeys.datasource_width]}
|
||||||
maxWidth="33%"
|
maxWidth="33%"
|
||||||
enable={{ right: true }}
|
enable={{ right: true }}
|
||||||
className={
|
className={
|
||||||
|
@ -564,13 +560,13 @@ function ExploreViewContainer(props) {
|
||||||
) : null}
|
) : null}
|
||||||
<Resizable
|
<Resizable
|
||||||
onResizeStop={(evt, direction, ref, d) =>
|
onResizeStop={(evt, direction, ref, d) =>
|
||||||
setSidebarWidths(storageKeys.controlsWidth, d)
|
setSidebarWidths(LocalStorageKeys.controls_width, d)
|
||||||
}
|
}
|
||||||
defaultSize={{
|
defaultSize={{
|
||||||
width: getSidebarWidths(storageKeys.controlsWidth),
|
width: getSidebarWidths(LocalStorageKeys.controls_width),
|
||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
minWidth={defaultSidebarsWidth[storageKeys.controlsWidth]}
|
minWidth={defaultSidebarsWidth[LocalStorageKeys.controls_width]}
|
||||||
maxWidth="33%"
|
maxWidth="33%"
|
||||||
enable={{ right: true }}
|
enable={{ right: true }}
|
||||||
className="col-sm-3 explore-column controls-column"
|
className="col-sm-3 explore-column controls-column"
|
||||||
|
|
|
@ -151,8 +151,6 @@ export enum FILTER_BOX_MIGRATION_STATES {
|
||||||
UNDECIDED = 'UNDECIDED',
|
UNDECIDED = 'UNDECIDED',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FILTER_BOX_TRANSITION_SNOOZED_AT =
|
|
||||||
'filter_box_transition_snoozed_at';
|
|
||||||
export const FILTER_BOX_TRANSITION_SNOOZE_DURATION = 24 * 60 * 60 * 1000; // 24 hours
|
export const FILTER_BOX_TRANSITION_SNOOZE_DURATION = 24 * 60 * 60 * 1000; // 24 hours
|
||||||
|
|
||||||
export const POPOVER_INITIAL_HEIGHT = 240;
|
export const POPOVER_INITIAL_HEIGHT = 240;
|
||||||
|
|
|
@ -16,9 +16,28 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
import {
|
||||||
|
getItem,
|
||||||
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
|
} from 'src/utils/localStorageHelpers';
|
||||||
|
|
||||||
// storage keys for welcome page sticky tabs and tables
|
describe('localStorageHelpers', () => {
|
||||||
export const HOMEPAGE_CHART_FILTER = 'homepage_chart_filter';
|
beforeEach(() => {
|
||||||
export const HOMEPAGE_ACTIVITY_FILTER = 'homepage_activity_filter';
|
localStorage.clear();
|
||||||
export const HOMEPAGE_DASHBOARD_FILTER = 'homepage_dashboard_filter';
|
});
|
||||||
export const HOMEPAGE_COLLAPSE_STATE = 'homepage_collapse_state';
|
|
||||||
|
afterAll(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets a value that was set', () => {
|
||||||
|
setItem(LocalStorageKeys.is_datapanel_open, false);
|
||||||
|
|
||||||
|
expect(getItem(LocalStorageKeys.is_datapanel_open, true)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the default value for an unset value', () => {
|
||||||
|
expect(getItem(LocalStorageKeys.is_datapanel_open, true)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -17,19 +17,98 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const getFromLocalStorage = (key: string, defaultValue: any) => {
|
import { TableTabTypes } from 'src/views/CRUD/types';
|
||||||
|
import { SetTabType } from 'src/views/CRUD/welcome/ActivityTable';
|
||||||
|
|
||||||
|
export enum LocalStorageKeys {
|
||||||
|
/**
|
||||||
|
* START LEGACY LOCAL STORAGE KEYS
|
||||||
|
*
|
||||||
|
* Do not follow the patterns here for key names. Keys should instead be namespaced to avoid
|
||||||
|
* collisions.
|
||||||
|
*
|
||||||
|
* TODO: Update all local storage keys to follow the new pattern. This is a breaking change,
|
||||||
|
* and therefore should be done in a major release.
|
||||||
|
*/
|
||||||
|
filter_box_transition_snoozed_at = 'filter_box_transition_snoozed_at',
|
||||||
|
chart_split_sizes = 'chart_split_sizes',
|
||||||
|
controls_width = 'controls_width',
|
||||||
|
datasource_width = 'datasource_width',
|
||||||
|
is_datapanel_open = 'is_datapanel_open',
|
||||||
|
homepage_chart_filter = 'homepage_chart_filter',
|
||||||
|
homepage_dashboard_filter = 'homepage_dashboard_filter',
|
||||||
|
homepage_collapse_state = 'homepage_collapse_state',
|
||||||
|
homepage_activity_filter = 'homepage_activity_filter',
|
||||||
|
/** END LEGACY LOCAL STORAGE KEYS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New local storage keys should be namespaced to avoid collisions. Keys should be named in the
|
||||||
|
* form [namespace]__[key].
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* sqllab__is_autocomplete_enabled
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LocalStorageValues = {
|
||||||
|
filter_box_transition_snoozed_at: Record<number, number>;
|
||||||
|
chart_split_sizes: [number, number];
|
||||||
|
controls_width: number;
|
||||||
|
datasource_width: number;
|
||||||
|
is_datapanel_open: boolean;
|
||||||
|
homepage_chart_filter: TableTabTypes;
|
||||||
|
homepage_dashboard_filter: TableTabTypes;
|
||||||
|
homepage_collapse_state: string[];
|
||||||
|
homepage_activity_filter: SetTabType | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getItem<K extends LocalStorageKeys>(
|
||||||
|
key: K,
|
||||||
|
defaultValue: LocalStorageValues[K],
|
||||||
|
): LocalStorageValues[K] {
|
||||||
|
return dangerouslyGetItemDoNotUse(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setItem<K extends LocalStorageKeys>(
|
||||||
|
key: K,
|
||||||
|
value: LocalStorageValues[K],
|
||||||
|
): void {
|
||||||
|
dangerouslySetItemDoNotUse(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function should not be used directly, as it doesn't provide any type safety or any
|
||||||
|
* guarantees that the globally namespaced localstorage key is correct.
|
||||||
|
*
|
||||||
|
* Instead, use getItem and setItem. Any legacy uses should be updated/migrated in future
|
||||||
|
* Superset versions (as they may require breaking changes).
|
||||||
|
* */
|
||||||
|
export function dangerouslyGetItemDoNotUse(
|
||||||
|
key: string,
|
||||||
|
defaultValue: any,
|
||||||
|
): any {
|
||||||
try {
|
try {
|
||||||
const value = localStorage.getItem(key);
|
const value = localStorage.getItem(key);
|
||||||
return JSON.parse(value || 'null') || defaultValue;
|
if (value === null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return JSON.parse(value);
|
||||||
} catch {
|
} catch {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const setInLocalStorage = (key: string, value: any) => {
|
/*
|
||||||
|
* This function should not be used directly, as it doesn't provide any type safety or any
|
||||||
|
* guarantees that the globally namespaced localstorage key is correct.
|
||||||
|
*
|
||||||
|
* Instead, use getItem and setItem. Any legacy uses should be updated/migrated in future
|
||||||
|
* Superset versions (as they may require breaking changes).
|
||||||
|
* */
|
||||||
|
export function dangerouslySetItemDoNotUse(key: string, value: any): void {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(key, JSON.stringify(value));
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
} catch {
|
} catch {
|
||||||
// Catch in case localStorage is unavailable
|
// Catch in case localStorage is unavailable
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ import ListView, {
|
||||||
SelectOption,
|
SelectOption,
|
||||||
} from 'src/components/ListView';
|
} from 'src/components/ListView';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import { getFromLocalStorage } from 'src/utils/localStorageHelpers';
|
import { dangerouslyGetItemDoNotUse } from 'src/utils/localStorageHelpers';
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||||
import ImportModelsModal from 'src/components/ImportModal/index';
|
import ImportModelsModal from 'src/components/ImportModal/index';
|
||||||
|
@ -164,7 +164,10 @@ function ChartList(props: ChartListProps) {
|
||||||
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
||||||
|
|
||||||
const { userId } = props.user;
|
const { userId } = props.user;
|
||||||
const userKey = getFromLocalStorage(userId?.toString(), null);
|
// TODO: Fix usage of localStorage keying on the user id
|
||||||
|
const userSettings = dangerouslyGetItemDoNotUse(userId?.toString(), null) as {
|
||||||
|
thumbnails: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const openChartImportModal = () => {
|
const openChartImportModal = () => {
|
||||||
showImportModal(true);
|
showImportModal(true);
|
||||||
|
@ -574,8 +577,8 @@ function ChartList(props: ChartListProps) {
|
||||||
<ChartCard
|
<ChartCard
|
||||||
chart={chart}
|
chart={chart}
|
||||||
showThumbnails={
|
showThumbnails={
|
||||||
userKey
|
userSettings
|
||||||
? userKey.thumbnails
|
? userSettings.thumbnails
|
||||||
: isFeatureEnabled(FeatureFlag.THUMBNAILS)
|
: isFeatureEnabled(FeatureFlag.THUMBNAILS)
|
||||||
}
|
}
|
||||||
hasPerm={hasPerm}
|
hasPerm={hasPerm}
|
||||||
|
@ -680,8 +683,8 @@ function ChartList(props: ChartListProps) {
|
||||||
pageSize={PAGE_SIZE}
|
pageSize={PAGE_SIZE}
|
||||||
renderCard={renderCard}
|
renderCard={renderCard}
|
||||||
showThumbnails={
|
showThumbnails={
|
||||||
userKey
|
userSettings
|
||||||
? userKey.thumbnails
|
? userSettings.thumbnails
|
||||||
: isFeatureEnabled(FeatureFlag.THUMBNAILS)
|
: isFeatureEnabled(FeatureFlag.THUMBNAILS)
|
||||||
}
|
}
|
||||||
defaultViewMode={
|
defaultViewMode={
|
||||||
|
|
|
@ -37,7 +37,7 @@ import ListView, {
|
||||||
Filters,
|
Filters,
|
||||||
FilterOperator,
|
FilterOperator,
|
||||||
} from 'src/components/ListView';
|
} from 'src/components/ListView';
|
||||||
import { getFromLocalStorage } from 'src/utils/localStorageHelpers';
|
import { dangerouslyGetItemDoNotUse } from 'src/utils/localStorageHelpers';
|
||||||
import Owner from 'src/types/Owner';
|
import Owner from 'src/types/Owner';
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||||
import FacePile from 'src/components/FacePile';
|
import FacePile from 'src/components/FacePile';
|
||||||
|
@ -144,7 +144,8 @@ function DashboardList(props: DashboardListProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const { userId } = props.user;
|
const { userId } = props.user;
|
||||||
const userKey = getFromLocalStorage(userId?.toString(), null);
|
// TODO: Fix usage of localStorage keying on the user id
|
||||||
|
const userKey = dangerouslyGetItemDoNotUse(userId?.toString(), null);
|
||||||
|
|
||||||
const canCreate = hasPerm('can_write');
|
const canCreate = hasPerm('can_write');
|
||||||
const canEdit = hasPerm('can_write');
|
const canEdit = hasPerm('can_write');
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { styled, t } from '@superset-ui/core';
|
||||||
import { setInLocalStorage } from 'src/utils/localStorageHelpers';
|
import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers';
|
||||||
|
|
||||||
import ListViewCard from 'src/components/ListViewCard';
|
import ListViewCard from 'src/components/ListViewCard';
|
||||||
import SubMenu from 'src/components/Menu/SubMenu';
|
import SubMenu from 'src/components/Menu/SubMenu';
|
||||||
|
@ -29,7 +29,6 @@ import {
|
||||||
CardStyles,
|
CardStyles,
|
||||||
getEditedObjects,
|
getEditedObjects,
|
||||||
} from 'src/views/CRUD/utils';
|
} from 'src/views/CRUD/utils';
|
||||||
import { HOMEPAGE_ACTIVITY_FILTER } from 'src/views/CRUD/storageKeys';
|
|
||||||
import { Chart } from 'src/types/Chart';
|
import { Chart } from 'src/types/Chart';
|
||||||
import { Dashboard, SavedQueryObject } from 'src/views/CRUD/types';
|
import { Dashboard, SavedQueryObject } from 'src/views/CRUD/types';
|
||||||
|
|
||||||
|
@ -58,7 +57,7 @@ interface RecentDashboard extends RecentActivity {
|
||||||
item_type: 'dashboard';
|
item_type: 'dashboard';
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SetTabType {
|
export enum SetTabType {
|
||||||
EDITED = 'Edited',
|
EDITED = 'Edited',
|
||||||
CREATED = 'Created',
|
CREATED = 'Created',
|
||||||
VIEWED = 'Viewed',
|
VIEWED = 'Viewed',
|
||||||
|
@ -161,7 +160,7 @@ export default function ActivityTable({
|
||||||
label: t('Edited'),
|
label: t('Edited'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Edited');
|
setActiveChild('Edited');
|
||||||
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.EDITED);
|
setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.EDITED);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -169,7 +168,7 @@ export default function ActivityTable({
|
||||||
label: t('Created'),
|
label: t('Created'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Created');
|
setActiveChild('Created');
|
||||||
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.CREATED);
|
setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.CREATED);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -180,7 +179,7 @@ export default function ActivityTable({
|
||||||
label: t('Viewed'),
|
label: t('Viewed'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveChild('Viewed');
|
setActiveChild('Viewed');
|
||||||
setInLocalStorage(HOMEPAGE_ACTIVITY_FILTER, SetTabType.VIEWED);
|
setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.VIEWED);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,9 @@ import {
|
||||||
useListViewResource,
|
useListViewResource,
|
||||||
} from 'src/views/CRUD/hooks';
|
} from 'src/views/CRUD/hooks';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
@ -34,7 +35,6 @@ import { TableTabTypes } from 'src/views/CRUD/types';
|
||||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||||
import { User } from 'src/types/bootstrapTypes';
|
import { User } from 'src/types/bootstrapTypes';
|
||||||
import { CardContainer, PAGE_SIZE } from 'src/views/CRUD/utils';
|
import { CardContainer, PAGE_SIZE } from 'src/views/CRUD/utils';
|
||||||
import { HOMEPAGE_CHART_FILTER } from 'src/views/CRUD/storageKeys';
|
|
||||||
import { LoadingCards } from 'src/views/CRUD/welcome/Welcome';
|
import { LoadingCards } from 'src/views/CRUD/welcome/Welcome';
|
||||||
import ChartCard from 'src/views/CRUD/chart/ChartCard';
|
import ChartCard from 'src/views/CRUD/chart/ChartCard';
|
||||||
import Chart from 'src/types/Chart';
|
import Chart from 'src/types/Chart';
|
||||||
|
@ -65,8 +65,11 @@ function ChartTable({
|
||||||
examples,
|
examples,
|
||||||
}: ChartTableProps) {
|
}: ChartTableProps) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const filterStore = getFromLocalStorage(HOMEPAGE_CHART_FILTER, null);
|
const filterStore = getItem(
|
||||||
const initialFilter = filterStore || TableTabTypes.EXAMPLES;
|
LocalStorageKeys.homepage_chart_filter,
|
||||||
|
TableTabTypes.EXAMPLES,
|
||||||
|
);
|
||||||
|
const initialFilter = filterStore;
|
||||||
|
|
||||||
const filteredExamples = filter(examples, obj => 'viz_type' in obj);
|
const filteredExamples = filter(examples, obj => 'viz_type' in obj);
|
||||||
|
|
||||||
|
@ -162,7 +165,7 @@ function ChartTable({
|
||||||
label: t('Favorite'),
|
label: t('Favorite'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setChartFilter(TableTabTypes.FAVORITE);
|
setChartFilter(TableTabTypes.FAVORITE);
|
||||||
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.FAVORITE);
|
setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.FAVORITE);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -170,7 +173,7 @@ function ChartTable({
|
||||||
label: t('Mine'),
|
label: t('Mine'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setChartFilter(TableTabTypes.MINE);
|
setChartFilter(TableTabTypes.MINE);
|
||||||
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.MINE);
|
setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.MINE);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -180,7 +183,7 @@ function ChartTable({
|
||||||
label: t('Examples'),
|
label: t('Examples'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setChartFilter(TableTabTypes.EXAMPLES);
|
setChartFilter(TableTabTypes.EXAMPLES);
|
||||||
setInLocalStorage(HOMEPAGE_CHART_FILTER, TableTabTypes.EXAMPLES);
|
setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.EXAMPLES);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,9 @@ import {
|
||||||
import handleResourceExport from 'src/utils/export';
|
import handleResourceExport from 'src/utils/export';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
setItem,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import { LoadingCards } from 'src/views/CRUD/welcome/Welcome';
|
import { LoadingCards } from 'src/views/CRUD/welcome/Welcome';
|
||||||
import {
|
import {
|
||||||
|
@ -37,7 +38,6 @@ import {
|
||||||
createErrorHandler,
|
createErrorHandler,
|
||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
} from 'src/views/CRUD/utils';
|
} from 'src/views/CRUD/utils';
|
||||||
import { HOMEPAGE_DASHBOARD_FILTER } from 'src/views/CRUD/storageKeys';
|
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
||||||
|
@ -61,8 +61,11 @@ function DashboardTable({
|
||||||
examples,
|
examples,
|
||||||
}: DashboardTableProps) {
|
}: DashboardTableProps) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const filterStore = getFromLocalStorage(HOMEPAGE_DASHBOARD_FILTER, null);
|
const filterStore = getItem(
|
||||||
const defaultFilter = filterStore || TableTabTypes.EXAMPLES;
|
LocalStorageKeys.homepage_dashboard_filter,
|
||||||
|
TableTabTypes.EXAMPLES,
|
||||||
|
);
|
||||||
|
const defaultFilter = filterStore;
|
||||||
|
|
||||||
const filteredExamples = filter(examples, obj => !('viz_type' in obj));
|
const filteredExamples = filter(examples, obj => !('viz_type' in obj));
|
||||||
|
|
||||||
|
@ -159,7 +162,10 @@ function DashboardTable({
|
||||||
label: t('Favorite'),
|
label: t('Favorite'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setDashboardFilter(TableTabTypes.FAVORITE);
|
setDashboardFilter(TableTabTypes.FAVORITE);
|
||||||
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.FAVORITE);
|
setItem(
|
||||||
|
LocalStorageKeys.homepage_dashboard_filter,
|
||||||
|
TableTabTypes.FAVORITE,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -167,7 +173,7 @@ function DashboardTable({
|
||||||
label: t('Mine'),
|
label: t('Mine'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setDashboardFilter(TableTabTypes.MINE);
|
setDashboardFilter(TableTabTypes.MINE);
|
||||||
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.MINE);
|
setItem(LocalStorageKeys.homepage_dashboard_filter, TableTabTypes.MINE);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -178,7 +184,10 @@ function DashboardTable({
|
||||||
label: t('Examples'),
|
label: t('Examples'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setDashboardFilter(TableTabTypes.EXAMPLES);
|
setDashboardFilter(TableTabTypes.EXAMPLES);
|
||||||
setInLocalStorage(HOMEPAGE_DASHBOARD_FILTER, TableTabTypes.EXAMPLES);
|
setItem(
|
||||||
|
LocalStorageKeys.homepage_dashboard_filter,
|
||||||
|
TableTabTypes.EXAMPLES,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,11 @@ import Collapse from 'src/components/Collapse';
|
||||||
import { User } from 'src/types/bootstrapTypes';
|
import { User } from 'src/types/bootstrapTypes';
|
||||||
import { reject } from 'lodash';
|
import { reject } from 'lodash';
|
||||||
import {
|
import {
|
||||||
getFromLocalStorage,
|
getItem,
|
||||||
setInLocalStorage,
|
dangerouslyGetItemDoNotUse,
|
||||||
|
setItem,
|
||||||
|
dangerouslySetItemDoNotUse,
|
||||||
|
LocalStorageKeys,
|
||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import ListViewCard from 'src/components/ListViewCard';
|
import ListViewCard from 'src/components/ListViewCard';
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||||
|
@ -35,10 +38,6 @@ import {
|
||||||
getUserOwnedObjects,
|
getUserOwnedObjects,
|
||||||
loadingCardCount,
|
loadingCardCount,
|
||||||
} from 'src/views/CRUD/utils';
|
} from 'src/views/CRUD/utils';
|
||||||
import {
|
|
||||||
HOMEPAGE_ACTIVITY_FILTER,
|
|
||||||
HOMEPAGE_COLLAPSE_STATE,
|
|
||||||
} from 'src/views/CRUD/storageKeys';
|
|
||||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||||
import { Switch } from 'src/common/components';
|
import { Switch } from 'src/common/components';
|
||||||
|
|
||||||
|
@ -146,7 +145,7 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
||||||
const id = userid.toString();
|
const id = userid.toString();
|
||||||
const recent = `/superset/recent_activity/${user.userId}/?limit=6`;
|
const recent = `/superset/recent_activity/${user.userId}/?limit=6`;
|
||||||
const [activeChild, setActiveChild] = useState('Loading');
|
const [activeChild, setActiveChild] = useState('Loading');
|
||||||
const userKey = getFromLocalStorage(id, null);
|
const userKey = dangerouslyGetItemDoNotUse(id, null);
|
||||||
let defaultChecked = false;
|
let defaultChecked = false;
|
||||||
if (isFeatureEnabled(FeatureFlag.THUMBNAILS)) {
|
if (isFeatureEnabled(FeatureFlag.THUMBNAILS)) {
|
||||||
defaultChecked =
|
defaultChecked =
|
||||||
|
@ -161,17 +160,17 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
||||||
);
|
);
|
||||||
const [loadedCount, setLoadedCount] = useState(0);
|
const [loadedCount, setLoadedCount] = useState(0);
|
||||||
|
|
||||||
const collapseState = getFromLocalStorage(HOMEPAGE_COLLAPSE_STATE, null);
|
const collapseState = getItem(LocalStorageKeys.homepage_collapse_state, []);
|
||||||
const [activeState, setActiveState] = useState<Array<string>>(collapseState);
|
const [activeState, setActiveState] = useState<Array<string>>(collapseState);
|
||||||
|
|
||||||
const handleCollapse = (state: Array<string>) => {
|
const handleCollapse = (state: Array<string>) => {
|
||||||
setActiveState(state);
|
setActiveState(state);
|
||||||
setInLocalStorage(HOMEPAGE_COLLAPSE_STATE, state);
|
setItem(LocalStorageKeys.homepage_collapse_state, state);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const activeTab = getFromLocalStorage(HOMEPAGE_ACTIVITY_FILTER, null);
|
const activeTab = getItem(LocalStorageKeys.homepage_activity_filter, null);
|
||||||
setActiveState(collapseState || DEFAULT_TAB_ARR);
|
setActiveState(collapseState.length > 0 ? collapseState : DEFAULT_TAB_ARR);
|
||||||
getRecentAcitivtyObjs(user.userId, recent, addDangerToast)
|
getRecentAcitivtyObjs(user.userId, recent, addDangerToast)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data: ActivityData | null = {};
|
const data: ActivityData | null = {};
|
||||||
|
@ -183,7 +182,7 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
||||||
setActiveChild('Viewed');
|
setActiveChild('Viewed');
|
||||||
} else if (!activeTab && !data.Viewed) {
|
} else if (!activeTab && !data.Viewed) {
|
||||||
setActiveChild('Created');
|
setActiveChild('Created');
|
||||||
} else setActiveChild(activeTab);
|
} else setActiveChild(activeTab || 'Created');
|
||||||
} else if (!activeTab) setActiveChild('Created');
|
} else if (!activeTab) setActiveChild('Created');
|
||||||
else setActiveChild(activeTab);
|
else setActiveChild(activeTab);
|
||||||
setActivityData(activityData => ({ ...activityData, ...data }));
|
setActivityData(activityData => ({ ...activityData, ...data }));
|
||||||
|
@ -237,7 +236,7 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setChecked(!checked);
|
setChecked(!checked);
|
||||||
setInLocalStorage(id, { thumbnails: !checked });
|
dangerouslySetItemDoNotUse(id, { thumbnails: !checked });
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
Loading…
Reference in New Issue