Web console: make it possible to namespace local storage, auto flatten spec generator should deal better with bad data (#12238)

* improve computeFlattenExprsForData

* allow local storage namespacing

* add test
This commit is contained in:
Vadim Ogievetsky 2022-02-07 18:52:41 -08:00 committed by GitHub
parent ced1389d4c
commit 090c429c8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 15 deletions

View File

@ -49,6 +49,7 @@ describe('spec-utils', () => {
], ],
value: 2, value: 2,
}, },
'Curveball' as any,
]; ];
it('works for path, ignore-arrays', () => { it('works for path, ignore-arrays', () => {

View File

@ -82,13 +82,15 @@ export function computeFlattenExprsForData(
data: Record<string, any>[], data: Record<string, any>[],
exprType: ExprType, exprType: ExprType,
arrayHandling: ArrayHandling, arrayHandling: ArrayHandling,
includeTopLevel = false,
): string[] { ): string[] {
const seenPaths: Record<string, boolean> = {}; const seenPaths: Record<string, boolean> = {};
for (const datum of data) { for (const datum of data) {
if (!datum || typeof datum !== 'object') continue;
const datumKeys = Object.keys(datum); const datumKeys = Object.keys(datum);
for (const datumKey of datumKeys) { for (const datumKey of datumKeys) {
const datumValue = datum[datumKey]; const datumValue = datum[datumKey];
if (isNested(datumValue)) { if (includeTopLevel || isNested(datumValue)) {
addPath( addPath(
seenPaths, seenPaths,
exprType === 'path' ? `$.${datumKey}` : `.${datumKey}`, exprType === 'path' ? `$.${datumKey}` : `.${datumKey}`,

View File

@ -29,6 +29,7 @@ import { bootstrapReactTable } from './bootstrap/react-table-defaults';
import { ConsoleApplication } from './console-application'; import { ConsoleApplication } from './console-application';
import { Links, setLinkOverrides } from './links'; import { Links, setLinkOverrides } from './links';
import { Api, UrlBaser } from './singletons'; import { Api, UrlBaser } from './singletons';
import { setLocalStorageNamespace } from './utils';
import './entry.scss'; import './entry.scss';
@ -63,6 +64,9 @@ interface ConsoleConfig {
// Allow for link overriding to different docs // Allow for link overriding to different docs
linkOverrides?: Links; linkOverrides?: Links;
// Allow for namespacing the local storage in case multiple clusters share a URL due to proxying
localStorageNamespace?: string;
} }
const consoleConfig: ConsoleConfig = (window as any).consoleConfig; const consoleConfig: ConsoleConfig = (window as any).consoleConfig;
@ -89,6 +93,10 @@ if (consoleConfig.linkOverrides) {
setLinkOverrides(consoleConfig.linkOverrides); setLinkOverrides(consoleConfig.linkOverrides);
} }
if (consoleConfig.localStorageNamespace) {
setLocalStorageNamespace(consoleConfig.localStorageNamespace);
}
QueryRunner.defaultQueryExecutor = (payload, isSql, cancelToken) => { QueryRunner.defaultQueryExecutor = (payload, isSql, cancelToken) => {
return Api.instance.post(`/druid/v2${isSql ? '/sql' : ''}`, payload, { cancelToken }); return Api.instance.post(`/druid/v2${isSql ? '/sql' : ''}`, payload, { cancelToken });
}; };

View File

@ -16,28 +16,22 @@
* limitations under the License. * limitations under the License.
*/ */
import * as JSONBig from 'json-bigint-native';
import { Dispatch, SetStateAction, useState } from 'react'; import { Dispatch, SetStateAction, useState } from 'react';
import { localStorageGetJson, LocalStorageKeys, localStorageSetJson } from '../utils';
export function useLocalStorageState<T>( export function useLocalStorageState<T>(
key: string, key: LocalStorageKeys,
initialValue?: T, initialValue?: T,
): [T, Dispatch<SetStateAction<T>>] { ): [T, Dispatch<SetStateAction<T>>] {
const [state, setState] = useState(() => { const [state, setState] = useState(() => {
try { return localStorageGetJson(key) || initialValue;
const item = window.localStorage.getItem(key);
return item ? JSONBig.parse(item) : initialValue;
} catch {
return initialValue;
}
}); });
const setValue: Dispatch<SetStateAction<T>> = (value: T | ((prevState: T) => T)) => { const setValue: Dispatch<SetStateAction<T>> = (value: T | ((prevState: T) => T)) => {
const valueToStore = value instanceof Function ? value(state) : value; const valueToStore = value instanceof Function ? value(state) : value;
setState(valueToStore); setState(valueToStore);
try { localStorageSetJson(key, valueToStore);
window.localStorage.setItem(key, JSONBig.stringify(valueToStore));
} catch {}
}; };
return [state, setValue]; return [state, setValue];
} }

View File

@ -44,10 +44,20 @@ export type LocalStorageKeys = typeof LocalStorageKeys[keyof typeof LocalStorage
// ---------------------------- // ----------------------------
let localStorageNamespace: string | undefined;
export function setLocalStorageNamespace(namespace: string) {
localStorageNamespace = namespace;
}
function prependNamespace(key: string): string {
return localStorageNamespace ? `${localStorageNamespace}:${key}` : key;
}
export function localStorageSet(key: LocalStorageKeys, value: string): void { export function localStorageSet(key: LocalStorageKeys, value: string): void {
if (typeof localStorage === 'undefined') return; if (typeof localStorage === 'undefined') return;
try { try {
localStorage.setItem(key, value); localStorage.setItem(prependNamespace(key), value);
} catch (e) { } catch (e) {
console.error('Issue setting local storage key', e); console.error('Issue setting local storage key', e);
} }
@ -60,7 +70,7 @@ export function localStorageSetJson(key: LocalStorageKeys, value: any): void {
export function localStorageGet(key: LocalStorageKeys): string | undefined { export function localStorageGet(key: LocalStorageKeys): string | undefined {
if (typeof localStorage === 'undefined') return; if (typeof localStorage === 'undefined') return;
try { try {
return localStorage.getItem(key) || undefined; return localStorage.getItem(prependNamespace(key)) || localStorage.getItem(key) || undefined;
} catch (e) { } catch (e) {
console.error('Issue getting local storage key', e); console.error('Issue getting local storage key', e);
return; return;
@ -80,7 +90,7 @@ export function localStorageGetJson(key: LocalStorageKeys): any {
export function localStorageRemove(key: LocalStorageKeys): void { export function localStorageRemove(key: LocalStorageKeys): void {
if (typeof localStorage === 'undefined') return; if (typeof localStorage === 'undefined') return;
try { try {
localStorage.removeItem(key); localStorage.removeItem(prependNamespace(key));
} catch (e) { } catch (e) {
console.error('Issue removing local storage key', e); console.error('Issue removing local storage key', e);
} }