Skip to content

Commit

Permalink
feat: migrate from external settings api (#621)
Browse files Browse the repository at this point in the history
  • Loading branch information
artemmufazalov authored Dec 28, 2023
1 parent 992cfa8 commit ae2fbbe
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 150 deletions.
9 changes: 5 additions & 4 deletions src/containers/App/Content.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import ReduxTooltip from '../ReduxTooltip/ReduxTooltip';
import Header from '../Header/Header';
import AppIcons from '../AppIcons/AppIcons';

import {getParsedSettingValue} from '../../store/reducers/settings/settings';
import {THEME_KEY} from '../../utils/constants';
import {useSetting} from '../../utils/hooks';

import './App.scss';
import PropTypes from 'prop-types';
Expand Down Expand Up @@ -72,7 +72,10 @@ Content.propTypes = {
};

function ContentWrapper(props) {
const {theme, singleClusterMode, isAuthenticated} = props;
const {singleClusterMode, isAuthenticated} = props;

const [theme] = useSetting(THEME_KEY);

return (
<HistoryContext.Consumer>
{(history) => (
Expand All @@ -96,15 +99,13 @@ function ContentWrapper(props) {
}

ContentWrapper.propTypes = {
theme: PropTypes.string,
singleClusterMode: PropTypes.bool,
isAuthenticated: PropTypes.bool,
children: PropTypes.node,
};

function mapStateToProps(state) {
return {
theme: getParsedSettingValue(state, THEME_KEY),
isAuthenticated: state.authentication.isAuthenticated,
singleClusterMode: state.singleClusterMode,
};
Expand Down
39 changes: 12 additions & 27 deletions src/containers/AsideNavigation/AsideNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
import {connect} from 'react-redux';
import {useDispatch} from 'react-redux';
import {useLocation} from 'react-router';
import {useHistory} from 'react-router-dom';
import cn from 'bem-cn-lite';
Expand All @@ -19,7 +19,6 @@ import settingsIcon from '../../assets/icons/settings.svg';
import supportIcon from '../../assets/icons/support.svg';

import {logout} from '../../store/reducers/authentication/authentication';
import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
import {TENANT_PAGE, TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
import routes, {TENANT, createHref, parseQuery} from '../../routes';
import {useSetting, useTypedSelector} from '../../utils/hooks';
Expand Down Expand Up @@ -117,10 +116,6 @@ function YdbUserDropdown({isCompact, popupAnchor, ydbUser}: YdbUserDropdownProps

interface AsideNavigationProps {
children: React.ReactNode;
ydbUser: string;
compact: boolean;
logout: VoidFunction;
setSettingValue: (name: string, value: string) => void;
}

enum Panel {
Expand Down Expand Up @@ -189,15 +184,19 @@ export const useGetLeftNavigationItems = () => {

function AsideNavigation(props: AsideNavigationProps) {
const history = useHistory();
const dispatch = useDispatch();

const [visiblePanel, setVisiblePanel] = useState<Panel>();

const setIsCompact = (compact: boolean) => {
props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
};
const {user: ydbUser} = useTypedSelector((state) => state.authentication);
const [compact, setIsCompact] = useSetting<boolean>(ASIDE_HEADER_COMPACT_KEY);

const menuItems = useGetLeftNavigationItems();

const onLogout = () => {
dispatch(logout());
};

return (
<React.Fragment>
<AsideHeader
Expand All @@ -207,7 +206,7 @@ function AsideNavigation(props: AsideNavigationProps) {
onClick: () => history.push('/'),
}}
menuItems={menuItems}
compact={props.compact}
compact={compact}
onChangeCompact={setIsCompact}
className={b()}
renderContent={() => props.children}
Expand Down Expand Up @@ -248,8 +247,8 @@ function AsideNavigation(props: AsideNavigationProps) {
isCompact={compact}
popupAnchor={asideRef}
ydbUser={{
login: props.ydbUser,
logout: props.logout,
login: ydbUser,
logout: onLogout,
}}
/>
</React.Fragment>
Expand All @@ -269,18 +268,4 @@ function AsideNavigation(props: AsideNavigationProps) {
);
}

const mapStateToProps = (state: any) => {
const {user: ydbUser} = state.authentication;

return {
ydbUser,
compact: getParsedSettingValue(state, ASIDE_HEADER_COMPACT_KEY),
};
};

const mapDispatchToProps = {
logout,
setSettingValue,
};

export default connect(mapStateToProps, mapDispatchToProps)(AsideNavigation);
export default AsideNavigation;
5 changes: 1 addition & 4 deletions src/containers/Tenant/Diagnostics/Partitions/Partitions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ export const Partitions = ({path}: PartitionsProps) => {
error: nodesError,
} = useTypedSelector((state) => state.nodesList);

const [hiddenColumns, setHiddenColumns] = useSetting<string[]>(
PARTITIONS_HIDDEN_COLUMNS_KEY,
[],
);
const [hiddenColumns, setHiddenColumns] = useSetting<string[]>(PARTITIONS_HIDDEN_COLUMNS_KEY);

const [columns, columnsIdsForSelector] = useGetPartitionsColumns(selectedConsumer);

Expand Down
12 changes: 4 additions & 8 deletions src/containers/Tenant/Query/QueryEditor/QueryEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
setTenantPath,
} from '../../../../store/reducers/executeQuery';
import {getExplainQuery, getExplainQueryAst} from '../../../../store/reducers/explainQuery';
import {getParsedSettingValue, setSettingValue} from '../../../../store/reducers/settings/settings';
import {setShowPreview} from '../../../../store/reducers/schema/schema';
import {
DEFAULT_IS_QUERY_RESULT_COLLAPSED,
Expand Down Expand Up @@ -86,6 +85,7 @@ function QueryEditor(props) {
const [queryMode, setQueryMode] = useQueryModes();
const [useMultiSchema] = useSetting(QUERY_USE_MULTI_SCHEMA_KEY);
const [lastUsedQueryAction, setLastUsedQueryAction] = useSetting(LAST_USED_QUERY_ACTION_KEY);
const [savedQueries, setSavedQueries] = useSetting(SAVED_QUERIES_KEY);

useEffect(() => {
if (savedPath !== path) {
Expand Down Expand Up @@ -417,7 +417,7 @@ function QueryEditor(props) {

const storageEventHandler = (event) => {
if (event.key === SAVED_QUERIES_KEY) {
props.setSettingValue(SAVED_QUERIES_KEY, event.newValue);
setSavedQueries(event.newValue);
}
};

Expand All @@ -430,8 +430,6 @@ function QueryEditor(props) {
const onSaveQueryHandler = (queryName) => {
const {
executeQuery: {input},
savedQueries = [],
setSettingValue,
} = props;

const queryIndex = savedQueries.findIndex(
Expand All @@ -445,11 +443,11 @@ function QueryEditor(props) {
newSavedQueries.push(newQuery);
}

setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
setSavedQueries(newSavedQueries);
};

const renderControls = () => {
const {executeQuery, explainQuery, savedQueries} = props;
const {executeQuery, explainQuery} = props;

return (
<QueryEditorControls
Expand Down Expand Up @@ -511,7 +509,6 @@ const mapStateToProps = (state) => {
return {
executeQuery: state.executeQuery,
explainQuery: state.explainQuery,
savedQueries: getParsedSettingValue(state, SAVED_QUERIES_KEY),
showPreview: state.schema.showPreview,
currentSchema: state.schema.currentSchema,
monacoHotKey: state.executeQuery?.monacoHotKey,
Expand All @@ -525,7 +522,6 @@ const mapDispatchToProps = {
goToNextQuery,
getExplainQuery,
getExplainQueryAst,
setSettingValue,
setShowPreview,
setMonacoHotKey,
setTenantPath,
Expand Down
7 changes: 4 additions & 3 deletions src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import type {StorageApiRequestParams} from '../store/reducers/storage/types';

import {backend as BACKEND} from '../store';
import {prepareSortValue} from '../utils/filters';
import {settingsApi} from '../utils/settings';

const config = {withCredentials: !window.custom_backend};

Expand Down Expand Up @@ -378,10 +377,12 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
path_id: tenantId?.PathId,
});
}
postSetting(name: string, value: string) {

/** @deprecated use localStorage instead */
postSetting(settingsApi: string, name: string, value: string) {
return this.request({
method: 'PATCH',
url: settingsApi || '',
url: settingsApi,
data: {[name]: value},
});
}
Expand Down
113 changes: 113 additions & 0 deletions src/services/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {TENANT_PAGES_IDS} from '../store/reducers/tenant/constants';

import {
ASIDE_HEADER_COMPACT_KEY,
CLUSTER_INFO_HIDDEN_KEY,
INVERTED_DISKS_KEY,
LANGUAGE_KEY,
LAST_USED_QUERY_ACTION_KEY,
PARTITIONS_HIDDEN_COLUMNS_KEY,
QUERY_INITIAL_MODE_KEY,
QUERY_USE_MULTI_SCHEMA_KEY,
SAVED_QUERIES_KEY,
TENANT_INITIAL_PAGE_KEY,
THEME_KEY,
USE_BACKEND_PARAMS_FOR_TABLES_KEY,
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
} from '../utils/constants';
import {QUERY_ACTIONS, QUERY_MODES} from '../utils/query';
import {parseJson} from '../utils/utils';

export type SettingsObject = Record<string, unknown>;

const USE_LOCAL_STORAGE_FOR_SETTINGS_KEY = 'useLocalStorageForSettings';

/** User settings keys and their default values */
const DEFAULT_USER_SETTINGS: SettingsObject = {
[THEME_KEY]: 'system',
[LANGUAGE_KEY]: undefined,
[INVERTED_DISKS_KEY]: false,
[USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: false,
[QUERY_USE_MULTI_SCHEMA_KEY]: false,
[SAVED_QUERIES_KEY]: [],
[TENANT_INITIAL_PAGE_KEY]: TENANT_PAGES_IDS.query,
[QUERY_INITIAL_MODE_KEY]: QUERY_MODES.script,
[LAST_USED_QUERY_ACTION_KEY]: QUERY_ACTIONS.execute,
[ASIDE_HEADER_COMPACT_KEY]: true,
[PARTITIONS_HIDDEN_COLUMNS_KEY]: [],
[CLUSTER_INFO_HIDDEN_KEY]: true,
[USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
};

class SettingsManager {
constructor() {
// Migrate settings to LS if external API was used before
const settingsApi = window.web_version ? window.systemSettings?.settingsApi : undefined;

const useLocalStorage = this.readUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY);

if (settingsApi && !useLocalStorage) {
const externalUserSettings = window.userSettings;

if (externalUserSettings) {
Object.entries(externalUserSettings).forEach(([key, value]) =>
this.setUserSettingsValue(key, value),
);
}

this.setUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY, true);
}
}

/**
* User settings - settings stored in LS or external store
*/
getUserSettings() {
return this.extractSettingsFromLS();
}

/**
* Returns parsed settings value.
* If value cannot be parsed, returns initially stored string.
* If there is no value, return default value
*/
readUserSettingsValue(key: string, defaultValue?: unknown) {
return this.readValueFromLS(key) ?? defaultValue ?? DEFAULT_USER_SETTINGS[key];
}

/**
* Stringify value and set it to LS
*/
setUserSettingsValue(key: string, value: unknown) {
return this.setValueToLS(key, value);
}

private extractSettingsFromLS = () => {
return Object.entries(DEFAULT_USER_SETTINGS).reduce<SettingsObject>((acc, [key, value]) => {
acc[key] = this.readUserSettingsValue(key, value);
return acc;
}, {});
};

private readValueFromLS = (key: string): unknown => {
try {
const value = localStorage.getItem(key);

return parseJson(value);
} catch {
return undefined;
}
};

private setValueToLS = (key: string, value: unknown): void => {
try {
if (typeof value === 'string') {
localStorage.setItem(key, value);
} else {
localStorage.setItem(key, JSON.stringify(value));
}
} catch {}
};
}

export const settingsManager = new SettingsManager();
9 changes: 6 additions & 3 deletions src/store/reducers/executeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import type {
QueryInHistory,
} from '../../types/store/executeQuery';
import type {QueryRequestParams, QueryMode, QuerySyntax} from '../../types/store/query';
import {getValueFromLS, parseJson} from '../../utils/utils';
import {QUERIES_HISTORY_KEY} from '../../utils/constants';
import {QUERY_MODES, QUERY_SYNTAX, parseQueryAPIExecuteResponse} from '../../utils/query';
import {parseQueryError} from '../../utils/error';
import {settingsManager} from '../../services/settings';
import '../../services/api';

import {createRequestActionTypes, createApiRequest} from '../utils';
Expand All @@ -28,7 +28,10 @@ const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
const SET_MONACO_HOT_KEY = 'query/SET_MONACO_HOT_KEY';
const SET_TENANT_PATH = 'query/SET_TENANT_PATH';

const queriesHistoryInitial: string[] = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
const queriesHistoryInitial = settingsManager.readUserSettingsValue(
QUERIES_HISTORY_KEY,
[],
) as string[];

const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;

Expand Down Expand Up @@ -97,7 +100,7 @@ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
const newQueries = [...state.history.queries, {queryText, syntax}].slice(
state.history.queries.length >= MAXIMUM_QUERIES_IN_HISTORY ? 1 : 0,
);
window.localStorage.setItem(QUERIES_HISTORY_KEY, JSON.stringify(newQueries));
settingsManager.setUserSettingsValue(QUERIES_HISTORY_KEY, newQueries);
const currentIndex = newQueries.length - 1;

return {
Expand Down
Loading

0 comments on commit ae2fbbe

Please sign in to comment.