Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/b2c-vs-extension/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ src/**
!src/storefront-next-cartridge.html
!src/scapi-explorer.html
!src/ods-management.html
!src/cip-analytics/*.css
out/**
**/node_modules/**

Expand Down
4 changes: 2 additions & 2 deletions packages/b2c-vs-extension/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export default [
...tseslint.configs.recommended,
prettierPlugin,
{
files: ['**/*.ts'],
files: ['**/*.ts', '**/*.tsx'],
plugins: {
header: headerPlugin,
},
languageOptions: {
parserOptions: {ecmaVersion: 2022, sourceType: 'module'},
parserOptions: {ecmaVersion: 2022, sourceType: 'module', ecmaFeatures: {jsx: true}},
},
rules: {
'header/header': ['error', 'block', copyrightHeader],
Expand Down
177 changes: 176 additions & 1 deletion packages/b2c-vs-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
],
"type": "module",
"dependencies": {
"@salesforce/b2c-tooling-sdk": "workspace:*"
"@salesforce/b2c-tooling-sdk": "workspace:*",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"engines": {
"vscode": "^1.105.1"
Expand Down Expand Up @@ -102,6 +104,11 @@
"type": "boolean",
"default": true,
"description": "Send anonymous usage telemetry (extension lifecycle and broad feature-category events). Honors VS Code's telemetry.telemetryLevel — disabling that disables this regardless of this setting."
},
"b2c-dx.features.cipAnalytics": {
"type": "boolean",
"default": true,
"description": "Enable the B2C-DX Analytics (CIP) sidebar for browsing tables and running curated reports."
}
}
},
Expand All @@ -127,6 +134,11 @@
"id": "b2c-dx-sandboxes",
"title": "B2C-DX Sandboxes",
"icon": "$(server-environment)"
},
{
"id": "b2c-dx-analytics",
"title": "B2C-DX Analytics",
"icon": "$(graph)"
}
]
},
Expand All @@ -151,6 +163,14 @@
"contextualTitle": "B2C-DX"
}
],
"b2c-dx-analytics": [
{
"id": "b2cCipAnalytics",
"name": "CIP Analytics",
"icon": "$(graph)",
"contextualTitle": "B2C-DX Analytics"
}
],
"b2c-dx-scapi": [
{
"id": "b2cApiBrowser",
Expand Down Expand Up @@ -187,6 +207,10 @@
{
"view": "b2cCartridgeExplorer",
"contents": "No cartridges found.\n\nCartridges are identified by .project files in the workspace.\n\n[Refresh](command:b2c-dx.codeSync.refreshCartridges)"
},
{
"view": "b2cCipAnalytics",
"contents": "Explore Commerce Intelligence Platform (CIP) data — build SQL queries visually, browse tables, and run curated reports.\n\n[Open Query Builder](command:b2c-dx.cipAnalytics.queryBuilder)\n[Browse Tables](command:b2c-dx.cipAnalytics.browseTables)\n\nRequires OAuth credentials (clientId, clientSecret) in dw.json.\n\n[Refresh](command:b2c-dx.cipAnalytics.refresh)"
}
],
"debuggers": [
Expand Down Expand Up @@ -253,6 +277,71 @@
"title": "Open API Documentation",
"category": "B2C DX - API Browser"
},
{
"command": "b2c-dx.cipAnalytics.refresh",
"title": "Refresh",
"icon": "$(refresh)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.resetFromDwJson",
"title": "Reset from dw.json…",
"icon": "$(discard)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.openReport",
"title": "Open Report",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.browseTables",
"title": "Browse Tables",
"icon": "$(table)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.queryBuilder",
"title": "Open Query Builder",
"icon": "$(zap)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.configureConnection",
"title": "Configure Connection…",
"icon": "$(gear)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.testConnection",
"title": "Test Connection",
"icon": "$(debug-disconnect)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.switchRealm",
"title": "Switch Realm…",
"icon": "$(server)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.switchConnection",
"title": "Switch Connection…",
"icon": "$(plug)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.addRealm",
"title": "Add Realm…",
"icon": "$(add)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.cipAnalytics.removeRealm",
"title": "Remove Realm…",
"icon": "$(trash)",
"category": "B2C-DX Analytics"
},
{
"command": "b2c-dx.sandbox.refresh",
"title": "Refresh",
Expand Down Expand Up @@ -639,6 +728,26 @@
"when": "view == b2cCartridgeExplorer",
"group": "navigation"
},
{
"command": "b2c-dx.cipAnalytics.removeRealm",
"when": "view == b2cCipAnalytics",
"group": "navigation@0"
},
{
"command": "b2c-dx.cipAnalytics.addRealm",
"when": "view == b2cCipAnalytics",
"group": "navigation@0"
},
{
"command": "b2c-dx.cipAnalytics.refresh",
"when": "view == b2cCipAnalytics",
"group": "navigation@4"
},
{
"command": "b2c-dx.cipAnalytics.resetFromDwJson",
"when": "view == b2cCipAnalytics",
"group": "navigation@9"
},
{
"command": "b2c-dx.codeSync.deploy",
"when": "view == b2cCartridgeExplorer",
Expand All @@ -661,6 +770,26 @@
}
],
"view/item/context": [
{
"command": "b2c-dx.cipAnalytics.switchConnection",
"when": "view == b2cCipAnalytics && viewItem == cipRealm",
"group": "inline@0"
},
{
"command": "b2c-dx.cipAnalytics.removeRealm",
"when": "view == b2cCipAnalytics && viewItem == cipRealm",
"group": "2_realm@0"
},
{
"command": "b2c-dx.cipAnalytics.testConnection",
"when": "view == b2cCipAnalytics && viewItem == cipRealmInfo",
"group": "inline@0"
},
{
"command": "b2c-dx.cipAnalytics.configureConnection",
"when": "view == b2cCipAnalytics && viewItem == cipRealmInfo",
"group": "inline@1"
},
{
"command": "b2c-dx.webdav.addCatalog",
"when": "view == b2cWebdavExplorer && viewItem == virtual-root-catalogs",
Expand Down Expand Up @@ -869,6 +998,50 @@
}
],
"commandPalette": [
{
"command": "b2c-dx.cipAnalytics.refresh",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.resetFromDwJson",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.openReport",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.browseTables",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.queryBuilder",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.configureConnection",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.testConnection",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.switchRealm",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.switchConnection",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.addRealm",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.cipAnalytics.removeRealm",
"when": "config.b2c-dx.features.cipAnalytics"
},
{
"command": "b2c-dx.apiBrowser.openSwagger",
"when": "false"
Expand Down Expand Up @@ -1031,6 +1204,8 @@
"@eslint/compat": "catalog:",
"@types/mocha": "catalog:",
"@types/node": "catalog:",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
"@types/vscode": "^1.105.1",
"@vscode/test-cli": "^0.0.12",
"@vscode/test-electron": "^2.5.2",
Expand Down
55 changes: 55 additions & 0 deletions packages/b2c-vs-extension/scripts/esbuild-bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ function copySdkScaffolds() {
fs.cpSync(src, dest, {recursive: true});
}

function copyCipProtoFiles() {
const src = path.join(sdkRoot, 'data', 'cip-proto');
const dest = path.join(pkgRoot, 'dist', 'data', 'cip-proto');
if (!fs.existsSync(src)) return;
fs.mkdirSync(dest, {recursive: true});
fs.cpSync(src, dest, {recursive: true});
console.log('[cip-proto] Copied proto files to dist/data/cip-proto/');
}

function inlineSdkPackageJson() {
const outPath = path.join(pkgRoot, 'dist', 'extension.cjs');
let str = fs.readFileSync(outPath, 'utf8');
Expand Down Expand Up @@ -108,18 +117,64 @@ const buildOptions = {
logLevel: 'info',
};

// Webview UI bundles. Each entry compiles a React app for one webview panel
// (Query Builder, Tables Browser, Report Dashboard). Targets the browser since
// these run inside a VS Code webview, not the extension host.
const webviewUiSrc = path.join(pkgRoot, 'src', 'webview-ui');
const webviewBuildOptions = {
entryPoints: {
'query-builder': path.join(webviewUiSrc, 'query-builder', 'index.tsx'),
'tables-browser': path.join(webviewUiSrc, 'tables-browser', 'index.tsx'),
'report-dashboard': path.join(webviewUiSrc, 'report-dashboard', 'index.tsx'),
},
outdir: path.join(pkgRoot, 'dist', 'webview-ui'),
bundle: true,
platform: 'browser',
format: 'esm',
target: 'es2022',
sourcemap: true,
jsx: 'automatic',
loader: {'.css': 'text'},
define: {
'process.env.NODE_ENV': watchMode ? '"development"' : '"production"',
},
logLevel: 'info',
};

if (watchMode) {
copySdkScaffolds();
copyCipProtoFiles();
const ctx = await esbuild.context(buildOptions);
await ctx.watch();
console.log('[esbuild] watching for changes...');

// Watch webview-ui in parallel; failures inside the React bundles must not bring
// down the extension host build, so each runs in its own context.
if (fs.existsSync(webviewUiSrc)) {
const webviewCtx = await esbuild.context(webviewBuildOptions);
await webviewCtx.watch();
console.log('[esbuild] watching webview-ui for changes...');
}
} else {
const result = await esbuild.build(buildOptions);

inlineSdkPackageJson();
copySdkScaffolds();
copyCipProtoFiles();
copySwaggerUiAssets();

if (fs.existsSync(webviewUiSrc)) {
try {
await esbuild.build(webviewBuildOptions);
console.log('[webview-ui] Built webview UI bundles into dist/webview-ui/');
} catch (err) {
// Surface a clean error so CI logs a single recognisable line instead of
// letting esbuild's stack ride out as the top-level rejection.
console.error('[webview-ui] Build failed:', err instanceof Error ? err.message : err);
process.exit(1);
}
}

if (result.metafile && process.env.ANALYZE_BUNDLE) {
const metaPath = path.join(pkgRoot, 'dist', 'meta.json');
fs.writeFileSync(metaPath, JSON.stringify(result.metafile, null, 2), 'utf-8');
Expand Down
Loading
Loading