chore: Refactor localstorage into typesafe version (#17832)

This commit is contained in:
Erik Ritter 2021-12-20 13:58:59 -08:00 committed by GitHub
parent e3b44f4825
commit 6edc183c5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 202 additions and 98 deletions

View File

@ -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> </>
), ),
}, },
}, },

View File

@ -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(),
}); });

View File

@ -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(() => {

View File

@ -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 => {

View File

@ -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"

View File

@ -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;

View File

@ -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);
});
});

View File

@ -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
} }
}; }

View File

@ -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={

View File

@ -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');

View File

@ -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);
}, },
}); });
} }

View File

@ -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);
}, },
}); });
} }

View File

@ -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,
);
}, },
}); });
} }

View File

@ -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(() => {