Skip to content

Commit 9534f21

Browse files
committed
refactored to make the ux resuable
1 parent 10f30dd commit 9534f21

40 files changed

Lines changed: 660 additions & 221 deletions

packages/b2c-tooling-sdk/src/operations/cip/reports.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
6868
description: 'Track daily sales performance with AOV and AOS metrics',
6969
category: 'Sales Analytics',
7070
parameters: [
71-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
71+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
7272
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
7373
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
7474
],
@@ -86,7 +86,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
8686
parameters: [
8787
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
8888
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
89-
{name: 'siteId', description: 'Optional site ID', type: 'string'},
89+
{name: 'siteId', description: 'Optional natural site id', type: 'string'},
9090
],
9191
buildSql(params) {
9292
const from = getDateLiteral(params, 'from');
@@ -101,7 +101,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
101101
description: 'Analyze OCAPI request volume and response latency',
102102
category: 'Technical Analytics',
103103
parameters: [
104-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
104+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
105105
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
106106
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
107107
],
@@ -117,7 +117,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
117117
description: 'Identify top selling products across channels',
118118
category: 'Product Analytics',
119119
parameters: [
120-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
120+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
121121
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
122122
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
123123
],
@@ -133,7 +133,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
133133
description: 'Analyze frequently co-purchased products',
134134
category: 'Product Analytics',
135135
parameters: [
136-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
136+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
137137
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
138138
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
139139
],
@@ -163,7 +163,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
163163
description: 'Identify search terms driving revenue and conversion',
164164
category: 'Search Analytics',
165165
parameters: [
166-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
166+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
167167
{name: 'hasResults', description: 'Filter successful/unsuccessful searches', type: 'boolean', required: true},
168168
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
169169
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
@@ -181,7 +181,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
181181
description: 'Track payment method adoption and transaction metrics',
182182
category: 'Payment Analytics',
183183
parameters: [
184-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
184+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
185185
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
186186
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
187187
],
@@ -197,7 +197,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
197197
description: 'Track customer registration trends by date and device',
198198
category: 'Customer Analytics',
199199
parameters: [
200-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
200+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
201201
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
202202
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
203203
],
@@ -213,7 +213,7 @@ export const CIP_REPORTS: CipReportDefinition[] = [
213213
description: 'Identify top traffic referrers and visit share',
214214
category: 'Traffic Analytics',
215215
parameters: [
216-
{name: 'siteId', description: 'Site ID', type: 'string', required: true},
216+
{name: 'siteId', description: 'Natural site id', type: 'string', required: true},
217217
{name: 'from', description: 'Inclusive start date (YYYY-MM-DD)', type: 'date', required: true},
218218
{name: 'to', description: 'Inclusive end date (YYYY-MM-DD)', type: 'date', required: true},
219219
{name: 'limit', description: 'Max rows (1-500)', type: 'number', min: 1, max: 500},
Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
// Place your settings in this file to overwrite default and user settings.
22
{
3-
"files.exclude": {
4-
"out": false // set this to true to hide the "out" folder with the compiled JS files
5-
},
6-
"search.exclude": {
7-
"out": true // set this to false to include "out" folder in search results
8-
},
9-
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10-
"typescript.tsc.autoDetect": "off",
11-
"workbench.colorCustomizations": {
12-
"list.deemphasizedForeground": "#9a9a9a",
13-
"list.descriptionForeground": "#9a9a9a"
14-
}
3+
"files.exclude": {
4+
"out": false // set this to true to hide the "out" folder with the compiled JS files
5+
},
6+
"search.exclude": {
7+
"out": true // set this to false to include "out" folder in search results
8+
},
9+
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10+
"typescript.tsc.autoDetect": "off"
1511
}

packages/b2c-vs-extension/eslint.config.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export default [
2222
...tseslint.configs.recommended,
2323
prettierPlugin,
2424
{
25-
files: ['**/*.ts'],
25+
files: ['**/*.ts', '**/*.tsx'],
2626
plugins: {
2727
header: headerPlugin,
2828
},
2929
languageOptions: {
30-
parserOptions: {ecmaVersion: 2022, sourceType: 'module'},
30+
parserOptions: {ecmaVersion: 2022, sourceType: 'module', ecmaFeatures: {jsx: true}},
3131
},
3232
rules: {
3333
'header/header': ['error', 'block', copyrightHeader],

packages/b2c-vs-extension/package.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,50 @@
997997
}
998998
],
999999
"commandPalette": [
1000+
{
1001+
"command": "b2c-dx.cipAnalytics.refresh",
1002+
"when": "config.b2c-dx.features.cipAnalytics"
1003+
},
1004+
{
1005+
"command": "b2c-dx.cipAnalytics.resetFromDwJson",
1006+
"when": "config.b2c-dx.features.cipAnalytics"
1007+
},
1008+
{
1009+
"command": "b2c-dx.cipAnalytics.openReport",
1010+
"when": "config.b2c-dx.features.cipAnalytics"
1011+
},
1012+
{
1013+
"command": "b2c-dx.cipAnalytics.browseTables",
1014+
"when": "config.b2c-dx.features.cipAnalytics"
1015+
},
1016+
{
1017+
"command": "b2c-dx.cipAnalytics.queryBuilder",
1018+
"when": "config.b2c-dx.features.cipAnalytics"
1019+
},
1020+
{
1021+
"command": "b2c-dx.cipAnalytics.configureConnection",
1022+
"when": "config.b2c-dx.features.cipAnalytics"
1023+
},
1024+
{
1025+
"command": "b2c-dx.cipAnalytics.testConnection",
1026+
"when": "config.b2c-dx.features.cipAnalytics"
1027+
},
1028+
{
1029+
"command": "b2c-dx.cipAnalytics.switchRealm",
1030+
"when": "config.b2c-dx.features.cipAnalytics"
1031+
},
1032+
{
1033+
"command": "b2c-dx.cipAnalytics.switchConnection",
1034+
"when": "config.b2c-dx.features.cipAnalytics"
1035+
},
1036+
{
1037+
"command": "b2c-dx.cipAnalytics.addRealm",
1038+
"when": "config.b2c-dx.features.cipAnalytics"
1039+
},
1040+
{
1041+
"command": "b2c-dx.cipAnalytics.removeRealm",
1042+
"when": "config.b2c-dx.features.cipAnalytics"
1043+
},
10001044
{
10011045
"command": "b2c-dx.apiBrowser.openSwagger",
10021046
"when": "false"

packages/b2c-vs-extension/scripts/esbuild-bundle.mjs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,15 @@ if (watchMode) {
164164
copySwaggerUiAssets();
165165

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

171178
if (result.metafile && process.env.ANALYZE_BUNDLE) {

packages/b2c-vs-extension/src/cip-analytics/cip-connection-service.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
import {createCipClient, DEFAULT_CIP_HOST, DEFAULT_CIP_STAGING_HOST} from '@salesforce/b2c-tooling-sdk/clients';
77
import {listCipTables} from '@salesforce/b2c-tooling-sdk/operations/cip';
8+
import {randomUUID} from 'node:crypto';
89
import * as vscode from 'vscode';
910
import type {B2CExtensionConfig} from '../config-provider.js';
1011

@@ -244,7 +245,10 @@ export class CipConnectionService implements vscode.Disposable {
244245

245246
/** Remove a saved realm by id. If it was active, falls back to the first remaining realm. */
246247
async removeRealm(id: string): Promise<void> {
248+
const before = this.realms.length;
247249
this.realms = this.realms.filter((r) => r.id !== id);
250+
if (this.realms.length === before) return;
251+
this.realmStatusMap.delete(id);
248252
await this.persistRealms();
249253
if (this.connection.id === id) {
250254
const fallback = this.realms[0];
@@ -254,6 +258,11 @@ export class CipConnectionService implements vscode.Disposable {
254258
this.connection = makeBlankConnection();
255259
this._onDidChange.fire(this.get());
256260
}
261+
} else {
262+
// Always notify subscribers (tree, status bar) even when the active realm
263+
// didn't change — a non-active realm went away and the sidebar needs to
264+
// re-render to reflect it.
265+
this._onDidChange.fire(this.get());
257266
}
258267
}
259268

@@ -317,9 +326,14 @@ export class CipConnectionService implements vscode.Disposable {
317326
this.setStatus('testing', `Connecting to CIP host ${host}`);
318327

319328
const TIMEOUT_MS = 15_000;
320-
const timeoutPromise = new Promise<never>((_, reject) =>
321-
setTimeout(() => reject(new Error(`Connection timed out after ${TIMEOUT_MS / 1000}s`)), TIMEOUT_MS),
322-
);
329+
// Track the timer so we can clear it once the handshake settles. Without
330+
// the clear, a fast-returning request still keeps the timer pending and
331+
// its rejection runs later as a no-op against an already-resolved race —
332+
// not user-visible, but pollutes the event loop.
333+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
334+
const timeoutPromise = new Promise<never>((_, reject) => {
335+
timeoutId = setTimeout(() => reject(new Error(`Connection timed out after ${TIMEOUT_MS / 1000}s`)), TIMEOUT_MS);
336+
});
323337

324338
try {
325339
const config = this.configProvider.getConfig();
@@ -334,6 +348,8 @@ export class CipConnectionService implements vscode.Disposable {
334348
const message = err instanceof Error ? err.message : String(err);
335349
this.log.appendLine(`[CIP Connection] FAILED · ${message}`);
336350
this.setStatus('disconnected', message);
351+
} finally {
352+
if (timeoutId !== undefined) clearTimeout(timeoutId);
337353
}
338354
return this.get();
339355
}
@@ -445,7 +461,7 @@ function realmFrom(conn: CipConnection): CipRealm {
445461
}
446462

447463
function generateId(): string {
448-
return Math.random().toString(36).slice(2, 10);
464+
return randomUUID();
449465
}
450466

451467
/** Derive a short friendly label from a tenant ID by stripping common env suffixes.

0 commit comments

Comments
 (0)