diff --git a/superset-frontend/packages/superset-ui-core/src/index.ts b/superset-frontend/packages/superset-ui-core/src/index.ts index 23d972fc9a05..2a53112f6fe2 100644 --- a/superset-frontend/packages/superset-ui-core/src/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/index.ts @@ -35,3 +35,4 @@ export * from './chart'; export * from './chart-composition'; export * from './components'; export * from './math-expression'; +export * from './ui-overrides'; diff --git a/superset-frontend/packages/superset-ui-core/src/models/Registry.ts b/superset-frontend/packages/superset-ui-core/src/models/Registry.ts index 7bf7f175cb8c..90a8065e29ac 100644 --- a/superset-frontend/packages/superset-ui-core/src/models/Registry.ts +++ b/superset-frontend/packages/superset-ui-core/src/models/Registry.ts @@ -59,6 +59,10 @@ export interface RegistryConfig { /** * Registry class * + * !!!!!!!! + * IF YOU ARE ADDING A NEW REGISTRY TO SUPERSET, CONSIDER USING TypedRegistry + * !!!!!!!! + * * Can use generic to specify type of item in the registry * @type V Type of value * @type W Type of value returned from loader function when using registerLoader(). diff --git a/superset-frontend/packages/superset-ui-core/src/models/TypedRegistry.ts b/superset-frontend/packages/superset-ui-core/src/models/TypedRegistry.ts new file mode 100644 index 000000000000..80e32167f560 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/models/TypedRegistry.ts @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A Registry which serves as a typed key:value store for Superset and for Plugins. + * + * Differences from the older Registry class: + * + * 1. The keys and values stored in this class are individually typed by TYPEMAP parameter. + * In the old Registry, all values are of the same type and keys are not enumerated. + * Though you can also use indexed or mapped types in a TYPEMAP. + * + * 2. This class does not have a separate async get and set methods or use loaders. + * Instead, TYPEMAP should specify async values and loaders explicitly when needed. + * The value can be anything! A string, a class, a function, an async function... anything! + * + * 3. This class does not implement Policies, that is a separate concern to be handled elsewhere. + * + * + * Removing or altering types in a type map could be a potential breaking change, be careful! + * + * Listener methods have not been added because there isn't a use case yet. + */ +class TypedRegistry { + name = 'TypedRegistry'; + + private records: TYPEMAP; + + constructor(initialRecords: TYPEMAP) { + this.records = initialRecords; + } + + get(key: K): TYPEMAP[K] { + // The type construction above means that when you call this function, + // you get a really specific type back. + return this.records[key]; + } + + set(key: K, value: TYPEMAP[K]) { + this.records[key] = value; + } +} + +export default TypedRegistry; diff --git a/superset-frontend/packages/superset-ui-core/src/models/index.ts b/superset-frontend/packages/superset-ui-core/src/models/index.ts index 10d46c2a7e5a..365ed391d331 100644 --- a/superset-frontend/packages/superset-ui-core/src/models/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/models/index.ts @@ -21,3 +21,4 @@ export { default as Plugin } from './Plugin'; export { default as Preset } from './Preset'; export { default as Registry, OverwritePolicy } from './Registry'; export { default as RegistryWithDefaultKey } from './RegistryWithDefaultKey'; +export { default as TypedRegistry } from './TypedRegistry'; diff --git a/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts b/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts new file mode 100644 index 000000000000..fb74ae1ece49 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { TypedRegistry } from '../models'; +import { makeSingleton } from '../utils'; + +/** A function (or component) which returns text (or marked-up text) */ +type UiGeneratorText

= (props: P) => string | React.ReactElement; + +/** + * This type defines all the UI override options which replace elements of Superset's default UI. + * Idea with the keys here is generally to namespace following the form of 'domain.functonality.item' + * + * When defining a new option here, take care to keep any parameters to functions (or components) minimal. + * Any removal or alteration to a parameter will be considered a breaking change. + */ +export type UiOverrides = Partial<{ + 'embedded.documentation.description': UiGeneratorText; + 'embedded.documentation.url': string; +}>; + +/** + * A registry containing UI customizations to replace elements of Superset's default UI. + */ +class UiOverrideRegistry extends TypedRegistry { + name = 'UiOverrideRegistry'; +} + +export const getUiOverrideRegistry = makeSingleton(UiOverrideRegistry, {}); diff --git a/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx b/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx new file mode 100644 index 000000000000..d59afc216fb8 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx @@ -0,0 +1,20 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './UiOverrideRegistry'; diff --git a/superset-frontend/packages/superset-ui-core/test/models/TypedRegistry.test.ts b/superset-frontend/packages/superset-ui-core/test/models/TypedRegistry.test.ts new file mode 100644 index 000000000000..7eb0d88f9d7e --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/models/TypedRegistry.test.ts @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { TypedRegistry } from '@superset-ui/core'; + +describe('TypedRegistry', () => { + it('gets a value', () => { + const reg = new TypedRegistry({ foo: 'bar' }); + expect(reg.get('foo')).toBe('bar'); + }); + + it('sets a value', () => { + const reg = new TypedRegistry({ foo: 'bar' }); + reg.set('foo', 'blah'); + expect(reg.get('foo')).toBe('blah'); + }); +}); diff --git a/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx b/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx index d20cc2460090..a2c44f490243 100644 --- a/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx +++ b/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx @@ -17,7 +17,13 @@ * under the License. */ import React, { useCallback, useEffect, useState } from 'react'; -import { makeApi, styled, SupersetApiError, t } from '@superset-ui/core'; +import { + makeApi, + styled, + SupersetApiError, + t, + getUiOverrideRegistry, +} from '@superset-ui/core'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import Modal from 'src/components/Modal'; import Loading from 'src/components/Loading'; @@ -27,6 +33,8 @@ import { useToasts } from 'src/components/MessageToasts/withToasts'; import { FormItem } from 'src/components/Form'; import { EmbeddedDashboard } from '../types'; +const uiOverrideRegistry = getUiOverrideRegistry(); + type Props = { dashboardId: string; show: boolean; @@ -140,6 +148,13 @@ export const DashboardEmbedControls = ({ dashboardId, onHide }: Props) => { return ; } + const docsDescription = uiOverrideRegistry.get( + 'embedded.documentation.description', + ); + const docsUrl = + uiOverrideRegistry.get('embedded.documentation.url') ?? + 'https://www.npmjs.com/package/@superset-ui/embedded-sdk'; + return ( <>

@@ -159,12 +174,10 @@ export const DashboardEmbedControls = ({ dashboardId, onHide }: Props) => {

{t('For further instructions, consult the')}{' '} - - {t('Superset Embedded SDK documentation.')} + + {docsDescription + ? docsDescription() + : t('Superset Embedded SDK documentation.')}

Settings