diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index d80c4535cd8b..f65873c10df0 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -43,7 +43,7 @@
"@rjsf/utils": "^5.24.3",
"@rjsf/validator-ajv8": "^5.24.13",
"@scarf/scarf": "^1.4.0",
- "@stacklet/ui": "^2.15.0",
+ "@stacklet/ui": "^2.16.0",
"@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls",
"@superset-ui/core": "file:./packages/superset-ui-core",
"@superset-ui/legacy-plugin-chart-calendar": "file:./plugins/legacy-plugin-chart-calendar",
@@ -10471,9 +10471,9 @@
}
},
"node_modules/@stacklet/ui": {
- "version": "2.15.0",
- "resolved": "https://stacklet-653993915282.d.codeartifact.us-east-1.amazonaws.com/npm/stacklet.client.ui/@stacklet/ui/-/ui-2.15.0.tgz",
- "integrity": "sha512-QMHi0UPl0X2K74g929xR6luaBrAM+Dfegljgx3rIrPBShBkPmV6keqXMTWpwJLBMUJY0T2ulN2USEiyB6VQ3Pw==",
+ "version": "2.16.0",
+ "resolved": "https://stacklet-653993915282.d.codeartifact.us-east-1.amazonaws.com/npm/stacklet.client.ui/@stacklet/ui/-/ui-2.16.0.tgz",
+ "integrity": "sha512-sGKpXtMKpIFXr6H1mrgeoxFOhMhZvq0hI08YQvaZbFoPUcJSg/NC45qJz23gE7lxdBJNjRJ7b6FsTsdCFT4OWg==",
"hasInstallScript": true,
"license": "UNLICENSED",
"dependencies": {
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 69e1616907ac..ee4032c8588f 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -125,6 +125,7 @@
"@rjsf/utils": "^5.24.3",
"@rjsf/validator-ajv8": "^5.24.13",
"@scarf/scarf": "^1.4.0",
+ "@stacklet/ui": "^2.16.0",
"@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls",
"@superset-ui/core": "file:./packages/superset-ui-core",
"@superset-ui/legacy-plugin-chart-calendar": "file:./plugins/legacy-plugin-chart-calendar",
@@ -146,7 +147,6 @@
"@superset-ui/plugin-chart-pivot-table": "file:./plugins/plugin-chart-pivot-table",
"@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table",
"@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud",
- "@stacklet/ui": "^2.15.0",
"@superset-ui/switchboard": "file:./packages/superset-ui-switchboard",
"@types/d3-format": "^3.0.1",
"@types/d3-selection": "^3.0.11",
diff --git a/superset-frontend/src/stacklet/StackletSidebar.tsx b/superset-frontend/src/stacklet/StackletSidebar.tsx
index 91ea1ed03ac4..6227ef52bbc4 100644
--- a/superset-frontend/src/stacklet/StackletSidebar.tsx
+++ b/superset-frontend/src/stacklet/StackletSidebar.tsx
@@ -35,13 +35,17 @@ import '@fontsource-variable/dm-sans';
import getBootstrapData from 'src/utils/getBootstrapData';
import type { MenuData } from 'src/types/bootstrapTypes';
-import { getAppSelectorOptions, SUPERSET_APP_NAME } from './appSelector';
+import { getAppSelectorOptions, getSupersetAppName } from './appSelector';
import { buildNavItems, resolveActiveNavToken } from './menuItems';
// The design system's stylesheet with every rule pre-scoped under
// `.stacklet-ui-scope` — the raw dist/ui.css would restyle all of Superset
// (Tailwind preflight + global html/body rules).
import '@stacklet/ui/dist/ui.scoped.css';
+// Superset-local layout/type tweaks so "AssetDB (Preview)" fits the sidebar;
+// must come after the scoped stylesheet to win the cascade.
+import './stackletSidebarOverrides.css';
+
/** Matches the sidebar widths baked into the V2Sidebar component. */
export const SIDEBAR_WIDTH = '13.625rem';
export const SIDEBAR_COLLAPSED_WIDTH = '4.5rem';
@@ -258,6 +262,7 @@ export default function StackletSidebar({
[data, user],
);
const appSelectorOptions = useMemo(() => getAppSelectorOptions(), []);
+ const supersetAppName = useMemo(() => getSupersetAppName(), []);
const signInMenu = useCurrentUserMenu(data, collapsed, themeControl);
// See resolveActiveNavToken: a virtual token stands in for the pathname so
// exactly one nav item is highlighted, query-aware for filtered presets.
@@ -266,8 +271,16 @@ export default function StackletSidebar({
[navItems, pathname, search],
);
+ // TEMPORARY — remove together with stackletSidebarOverrides.css once the
+ // Redash-backed AssetDB is retired: only the longer "AssetDB (Preview)"
+ // branding needs the sizing overrides that class scopes.
+ const scopeClassName =
+ supersetAppName === 'AssetDB (Preview)'
+ ? 'stacklet-ui-scope stacklet-preview-branding'
+ : 'stacklet-ui-scope';
+
return (
-
+
diff --git a/superset-frontend/src/stacklet/appSelector.test.ts b/superset-frontend/src/stacklet/appSelector.test.ts
index 3eb84b4b8368..c8480d312336 100644
--- a/superset-frontend/src/stacklet/appSelector.test.ts
+++ b/superset-frontend/src/stacklet/appSelector.test.ts
@@ -17,7 +17,7 @@
* under the License.
*/
import getBootstrapData from 'src/utils/getBootstrapData';
-import { getAppSelectorOptions, SUPERSET_APP_NAME } from './appSelector';
+import { getAppSelectorOptions, getSupersetAppName } from './appSelector';
jest.mock('src/utils/getBootstrapData', () => jest.fn());
@@ -26,18 +26,25 @@ const mockedBootstrap = getBootstrapData as jest.Mock;
const bootstrapWith = (common: object) =>
mockedBootstrap.mockReturnValue({ common });
-test('builds entries from the platform-injected stacklet.urls', () => {
+test('brands itself "AssetDB (Preview)" while the Redash-backed AssetDB exists', () => {
bootstrapWith({
stacklet: {
urls: {
console: 'https://console.acme.stacklet.io',
+ redash: 'https://redash.acme.stacklet.io',
sinistral: 'https://sinistral.acme.stacklet.io',
superset: 'https://superset.acme.stacklet.io',
},
},
});
+ expect(getSupersetAppName()).toBe('AssetDB (Preview)');
expect(getAppSelectorOptions()).toEqual([
- { label: SUPERSET_APP_NAME, href: '', isBeta: false },
+ { label: 'AssetDB (Preview)', href: '', isBeta: false },
+ {
+ label: 'AssetDB',
+ href: 'https://redash.acme.stacklet.io',
+ isBeta: false,
+ },
{
label: 'Console',
href: 'https://console.acme.stacklet.io',
@@ -47,20 +54,36 @@ test('builds entries from the platform-injected stacklet.urls', () => {
]);
});
-test('omits siblings whose URL is not configured', () => {
+test('brands itself plain "AssetDB" when Redash is not deployed', () => {
bootstrapWith({
- stacklet: { urls: { console: 'https://console.acme.stacklet.io' } },
+ stacklet: {
+ urls: {
+ console: 'https://console.acme.stacklet.io',
+ superset: 'https://superset.acme.stacklet.io',
+ },
+ },
});
- expect(getAppSelectorOptions().map(option => option.label)).toEqual([
- SUPERSET_APP_NAME,
- 'Console',
+ expect(getSupersetAppName()).toBe('AssetDB');
+ expect(getAppSelectorOptions()).toEqual([
+ { label: 'AssetDB', href: '', isBeta: false },
+ {
+ label: 'Console',
+ href: 'https://console.acme.stacklet.io',
+ isBeta: false,
+ },
]);
});
test('falls back to the dev platform when the payload has no stacklet.urls', () => {
bootstrapWith({});
+ // The dev fallback includes a Redash URL, so the Preview name applies
expect(getAppSelectorOptions()).toEqual([
- { label: SUPERSET_APP_NAME, href: '', isBeta: false },
+ { label: 'AssetDB (Preview)', href: '', isBeta: false },
+ {
+ label: 'AssetDB',
+ href: 'https://redash.dev.stacklet.dev',
+ isBeta: false,
+ },
{
label: 'Console',
href: 'https://console.dev.stacklet.dev',
diff --git a/superset-frontend/src/stacklet/appSelector.ts b/superset-frontend/src/stacklet/appSelector.ts
index 9923da89014d..b299d665e34c 100644
--- a/superset-frontend/src/stacklet/appSelector.ts
+++ b/superset-frontend/src/stacklet/appSelector.ts
@@ -18,13 +18,6 @@
*/
import getBootstrapData from 'src/utils/getBootstrapData';
-/**
- * How this Superset deployment is branded in the Stacklet platform's app
- * switcher (Design Kit v2, node 6820-6796). Also part of @stacklet/ui's
- * `V2AppName` union, so it can be passed to the Sidebar without casts.
- */
-export const SUPERSET_APP_NAME = 'AssetDB';
-
export interface StackletAppOption {
label: string;
href: string;
@@ -50,19 +43,40 @@ interface StackletBootstrapExtras {
*/
const DEV_FALLBACK_URLS: Partial> = {
console: 'https://console.dev.stacklet.dev',
+ redash: 'https://redash.dev.stacklet.dev',
sinistral: 'https://sinistral.dev.stacklet.dev',
};
+function getStackletUrls(): Partial> {
+ const common = getBootstrapData().common as StackletBootstrapExtras;
+ return common?.stacklet?.urls ?? DEV_FALLBACK_URLS;
+}
+
+/**
+ * How this Superset deployment is branded in the Stacklet platform's app
+ * switcher (Design Kit v2, node 6820-6796). Plain "AssetDB" once it is the
+ * only AssetDB in the environment; "(Preview)" while the Redash-backed
+ * AssetDB is still deployed alongside it. Both names are part of
+ * @stacklet/ui's `V2AppName` union, so the result can be passed to the
+ * Sidebar without casts.
+ */
+export function getSupersetAppName(): 'AssetDB' | 'AssetDB (Preview)' {
+ return getStackletUrls().redash ? 'AssetDB (Preview)' : 'AssetDB';
+}
+
/**
* Builds the app switcher entries for the Stacklet sidebar. Superset itself
- * (branded AssetDB) is always present and selected; siblings appear only
- * when their URL is configured.
+ * is always present and selected; siblings — including the Redash-backed
+ * "AssetDB" — appear only when their URL is configured. The Sidebar renders
+ * the selected app first regardless of this order.
*/
export function getAppSelectorOptions(): StackletAppOption[] {
- const common = getBootstrapData().common as StackletBootstrapExtras;
- const urls = common?.stacklet?.urls ?? DEV_FALLBACK_URLS;
+ const urls = getStackletUrls();
return [
- { label: SUPERSET_APP_NAME, href: '', isBeta: false },
+ { label: getSupersetAppName(), href: '', isBeta: false },
+ ...(urls.redash
+ ? [{ label: 'AssetDB', href: urls.redash, isBeta: false }]
+ : []),
...(urls.console
? [{ label: 'Console', href: urls.console, isBeta: false }]
: []),
diff --git a/superset-frontend/src/stacklet/stackletSidebarOverrides.css b/superset-frontend/src/stacklet/stackletSidebarOverrides.css
new file mode 100644
index 000000000000..151e3756ccf3
--- /dev/null
+++ b/superset-frontend/src/stacklet/stackletSidebarOverrides.css
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+/*
+ * TEMPORARY — delete this file (and its import plus the
+ * `stacklet-preview-branding` class in StackletSidebar.tsx) once the
+ * Redash-backed AssetDB is retired: the app is then branded plain "AssetDB",
+ * which fits the sidebar with the component defaults.
+ *
+ * Superset-local tweaks on top of @stacklet/ui's scoped stylesheet (imported
+ * right before this file in StackletSidebar.tsx), so the longer
+ * "AssetDB (Preview)" pill fits the sidebar without touching the shared
+ * component. `stacklet-preview-branding` is stamped on the scope wrapper only
+ * while the Redash URL is configured — the only case that gets the long name.
+ * Selectors anchor on the trigger's aria-label rather than the dist's utility
+ * class names, which are minified build artifacts.
+ */
+
+/* Header row holding the logo and the app selector: tighter padding and gap
+ than the component defaults, freeing width for the longer name. */
+.stacklet-ui-scope.stacklet-preview-branding
+ div:has(> div > button[aria-label^='App selector']) {
+ padding: 16px;
+ column-gap: 6px;
+}
+
+/* Slightly smaller logo, matching the reduced type next to it. */
+.stacklet-ui-scope.stacklet-preview-branding
+ div:has(> div > button[aria-label^='App selector'])
+ > a
+ > svg {
+ width: 24px;
+ height: auto;
+}
+
+/* The trigger lays out label and tile icon on the text baseline; with the
+ smaller type below the icon rides too high, so center-align instead. */
+.stacklet-ui-scope.stacklet-preview-branding
+ button[aria-label^='App selector'] {
+ align-items: center;
+}
+
+/* Smaller label type so the full name fits the expanded sidebar width. */
+.stacklet-ui-scope.stacklet-preview-branding
+ button[aria-label^='App selector']
+ .whitespace-nowrap {
+ font-size: 12px;
+}