@forgeroute/ui 0.4.36 → 0.4.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42883,6 +42883,10 @@ const DEFAULT_TEXTS = {
42883
42883
  selectSource: "Select",
42884
42884
  connected: "Connected",
42885
42885
  importMore: "Import more",
42886
+ importRequired: "Import your data to continue, or skip this step.",
42887
+ importErrorsTitle: (errors) => `${errors} row${errors === 1 ? "" : "s"} could not be imported`,
42888
+ importErrorsText: (imported, errors) => `${imported} imported. Fix the ${errors === 1 ? "row" : "rows"} listed in the import window in your file and import ${errors === 1 ? "it" : "them"} again (only the ${errors === 1 ? "row" : "rows"} that failed, so nothing is imported twice) to continue.`,
42889
+ importAgain: "Import again",
42886
42890
  whatGetsImported: "WHAT GETS IMPORTED:",
42887
42891
  doneTitle: "You're All Set!",
42888
42892
  doneDescription: "Your account is configured and ready to go. Here's a quick summary:",
@@ -42911,6 +42915,18 @@ var SetupWizardComponent = class SetupWizardComponent {
42911
42915
  this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
42912
42916
  this.destroyRef = inject(DestroyRef);
42913
42917
  this.narrow = signal(false, ...ngDevMode ? [{ debugName: "narrow" }] : /* istanbul ignore next */ []);
42918
+ this.importBlocked = computed(() => {
42919
+ const st = this.current();
42920
+ return st.kind === "import" && !!st.requireImport && !this.completed().has(st.key);
42921
+ }, ...ngDevMode ? [{ debugName: "importBlocked" }] : /* istanbul ignore next */ []);
42922
+ this.splitTab = signal("extra", ...ngDevMode ? [{ debugName: "splitTab" }] : /* istanbul ignore next */ []);
42923
+ this.splitTabs = computed(() => [{
42924
+ key: "extra",
42925
+ label: this.current().extraTab || this.current().extraTitle || ""
42926
+ }, {
42927
+ key: "main",
42928
+ label: this.current().mainTab || this.current().cardTitle || ""
42929
+ }], ...ngDevMode ? [{ debugName: "splitTabs" }] : /* istanbul ignore next */ []);
42914
42930
  this.split = computed(() => this.current().kind !== "custom" && !!this.current().splitLayout && !!this.templateFor(this.current().key), ...ngDevMode ? [{ debugName: "split" }] : /* istanbul ignore next */ []);
42915
42931
  this.steps = input.required(...ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []);
42916
42932
  this.texts = input({}, ...ngDevMode ? [{ debugName: "texts" }] : /* istanbul ignore next */ []);
@@ -42930,6 +42946,7 @@ var SetupWizardComponent = class SetupWizardComponent {
42930
42946
  this.completed = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "completed" }] : /* istanbul ignore next */ []);
42931
42947
  this.skipped = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "skipped" }] : /* istanbul ignore next */ []);
42932
42948
  this.imports = signal({}, ...ngDevMode ? [{ debugName: "imports" }] : /* istanbul ignore next */ []);
42949
+ this.importErrors = signal({}, ...ngDevMode ? [{ debugName: "importErrors" }] : /* istanbul ignore next */ []);
42933
42950
  this.statuses = signal({}, ...ngDevMode ? [{ debugName: "statuses" }] : /* istanbul ignore next */ []);
42934
42951
  this.busy = signal(false, ...ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []);
42935
42952
  this.api = {
@@ -43001,6 +43018,7 @@ var SetupWizardComponent = class SetupWizardComponent {
43001
43018
  this.error.set("");
43002
43019
  this.areaCodeOpen.set("");
43003
43020
  this.areaCode.set("");
43021
+ this.splitTab.set("extra");
43004
43022
  this.currentKey.set(key);
43005
43023
  const step = this.allSteps().find((s) => s.key === key);
43006
43024
  if (step.kind === "integrations") this.loadStatuses(step.integrations ?? []);
@@ -43072,23 +43090,37 @@ var SetupWizardComponent = class SetupWizardComponent {
43072
43090
  this.importers()[0]?.openImport();
43073
43091
  }
43074
43092
  onImported(key) {
43075
- const imported = this.importers()[0]?.importResult?.imported ?? 0;
43093
+ const result = this.importers()[0]?.importResult;
43094
+ const imported = result?.imported ?? 0;
43095
+ const errors = result?.errors?.length ?? 0;
43076
43096
  this.imports.update((m) => ({
43077
43097
  ...m,
43078
43098
  [key]: imported
43079
43099
  }));
43080
- this.markCompleted(key);
43100
+ this.importErrors.update((m) => ({
43101
+ ...m,
43102
+ [key]: errors
43103
+ }));
43104
+ if (imported > 0 && errors === 0) this.markCompleted(key);
43081
43105
  }
43082
43106
  importResult(key) {
43083
43107
  const n = this.imports()[key];
43084
43108
  return n === void 0 ? null : n;
43085
43109
  }
43110
+ importErrorCount(key) {
43111
+ return this.importErrors()[key] ?? 0;
43112
+ }
43086
43113
  clearImport(key) {
43087
43114
  this.imports.update((m) => {
43088
43115
  const n = { ...m };
43089
43116
  delete n[key];
43090
43117
  return n;
43091
43118
  });
43119
+ this.importErrors.update((m) => {
43120
+ const n = { ...m };
43121
+ delete n[key];
43122
+ return n;
43123
+ });
43092
43124
  }
43093
43125
  importTitle(key) {
43094
43126
  const imp = this.steps().find((s) => s.key === key)?.import;
@@ -43266,16 +43298,41 @@ var SetupWizardComponent = class SetupWizardComponent {
43266
43298
  <ui-button variant="primary" size="sm" data-testid="wizard-finish" (click)="finished.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('check')" /></svg> {{ t().finish }}</ui-button>
43267
43299
  </div>
43268
43300
  } @else {
43269
- <div class="sw-step-content" [class.sw-wide]="split()" [attr.aria-busy]="busy()" [attr.data-step]="current().key">
43301
+ <div class="sw-step-content" [attr.aria-busy]="busy()" [attr.data-step]="current().key">
43270
43302
  @if (intro(); as i) { <ui-section-header class="sw-intro" data-testid="wizard-step-intro" size="lg" background="#eaf3ff" [title]="i.title" [description]="i.text"><span section-header-icon class="sw-step-number" data-testid="wizard-step-number">{{ index() + 1 }}</span></ui-section-header> }
43271
43303
 
43272
- <div class="sw-body" [class.sw-split]="split()" data-testid="wizard-body">
43273
- @if (split() && templateFor(current().key); as left) {
43304
+ <ng-template #actions>
43305
+ @if (index() > 0) { <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
43306
+ <div class="sw-actions-right">
43307
+ @if (current().skippable !== false) {
43308
+ <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
43309
+ }
43310
+ @if (current().kind === 'custom') {
43311
+ @if (!current().ownActions) {
43312
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
43313
+ {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
43314
+ </ui-button>
43315
+ }
43316
+ } @else if (current().kind === 'integrations') {
43317
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43318
+ } @else if (current().kind === 'import') {
43319
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-continue" [disabled]="importBlocked()" [ariaDescribedBy]="importBlocked() ? 'sw-continue-hint' : ''" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43320
+ }
43321
+ </div>
43322
+ </ng-template>
43323
+ @if (split()) {
43324
+ <ui-pill-tabs class="sw-split-tabs" [tabs]="splitTabs()" [activeKey]="splitTab()" [ariaLabel]="current().label" (tabChange)="splitTab.set($event === 'main' ? 'main' : 'extra')" data-testid="wizard-split-tabs" />
43325
+ }
43326
+ @if (split() && splitTab() === 'extra' && templateFor(current().key); as left) {
43274
43327
  <ui-detail-card class="sw-card sw-extra-card" [title]="current().extraTitle ?? ''" [showHeader]="!!current().extraTitle" [headingLevel]="3" [collapsible]="false"
43275
- [ariaLabel]="current().extraTitle || current().label" headerBackground="rgb(248, 250, 252)" data-testid="wizard-extra-card">
43328
+ [ariaLabel]="current().extraTitle || current().label" headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)" data-testid="wizard-extra-card">
43276
43329
  <ng-container [ngTemplateOutlet]="left" [ngTemplateOutletContext]="{ $implicit: api }" />
43330
+ <p class="sw-extra-status" role="status" data-testid="wizard-extra-status">{{ current().extraFooter?.() }}</p>
43331
+ @if (importBlocked()) { <p class="sw-hint sw-continue-hint" id="sw-continue-hint" data-testid="wizard-continue-hint">{{ t().importRequired }}</p> }
43332
+ <div card-footer class="sw-step-actions"><ng-container [ngTemplateOutlet]="actions" /></div>
43277
43333
  </ui-detail-card>
43278
43334
  }
43335
+ @if (!split() || splitTab() === 'main') {
43279
43336
  <ui-detail-card class="sw-card" [showHeader]="!!current().cardTitle || !!headerTemplateFor(current().key)" [title]="current().cardTitle ?? ''" [headingLevel]="3" [collapsible]="false"
43280
43337
  [ariaLabel]="current().label" headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)" data-testid="wizard-step-card">
43281
43338
  @if (headerTemplateFor(current().key); as ht) {
@@ -43296,7 +43353,12 @@ var SetupWizardComponent = class SetupWizardComponent {
43296
43353
  @for (tag of imp.tags; track tag) { <ui-badge [label]="tag" variant="slate" /> }
43297
43354
  </div>
43298
43355
  }
43299
- @if (importResult(current().key); as res) {
43356
+ @if (importErrorCount(current().key) > 0) {
43357
+ <ui-alert variant="warning" [title]="t().importErrorsTitle(importErrorCount(current().key))" [attr.data-testid]="'import-errors-' + current().key">
43358
+ {{ t().importErrorsText(importResult(current().key) ?? 0, importErrorCount(current().key)) }}
43359
+ <ui-button variant="link" size="sm" data-testid="import-again" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importAgain }}</ui-button>
43360
+ </ui-alert>
43361
+ } @else if (importResult(current().key); as res) {
43300
43362
  <ui-alert variant="success" [title]="importTitle(current().key)" [attr.data-testid]="'import-result-' + current().key">
43301
43363
  {{ imp.resultText }}
43302
43364
  <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importMore }}</ui-button>
@@ -43330,36 +43392,20 @@ var SetupWizardComponent = class SetupWizardComponent {
43330
43392
  }
43331
43393
  }
43332
43394
 
43395
+ @if (importBlocked()) { <p class="sw-hint sw-continue-hint" id="sw-continue-hint" data-testid="wizard-continue-hint">{{ t().importRequired }}</p> }
43396
+
43333
43397
  @if (error()) { <ui-alert variant="danger" data-testid="wizard-save-error">{{ error() }}</ui-alert> }
43334
43398
 
43335
- <div card-footer class="sw-step-actions">
43336
- @if (index() > 0) { <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
43337
- <div class="sw-actions-right">
43338
- @if (current().skippable !== false) {
43339
- <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
43340
- }
43341
- @if (current().kind === 'custom') {
43342
- @if (!current().ownActions) {
43343
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
43344
- {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
43345
- </ui-button>
43346
- }
43347
- } @else if (current().kind === 'integrations') {
43348
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43349
- } @else if (current().kind === 'import') {
43350
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43351
- }
43352
- </div>
43353
- </div>
43399
+ <div card-footer class="sw-step-actions"><ng-container [ngTemplateOutlet]="actions" /></div>
43354
43400
  </ui-detail-card>
43355
- </div>
43401
+ }
43356
43402
  </div>
43357
43403
  }
43358
43404
  </main>
43359
43405
  </div>
43360
43406
  `,
43361
43407
  isInline: true,
43362
- styles: [".sw-page{display:flex;min-height:100vh;min-height:100dvh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}@media(min-width:1100px){.sw-step-content.sw-wide{max-width:1400px}}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-body{display:block}.sw-body.sw-split{display:grid;grid-template-columns:1fr;gap:24px}@media(min-width:1100px){.sw-body.sw-split{grid-template-columns:1fr 1fr;align-items:start}}.sw-body>.sw-card{min-width:0}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-step-actions,.sw-actions-right{flex-direction:column-reverse;align-items:stretch;gap:10px}.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
43408
+ styles: [".sw-page{display:flex;min-height:100vh;min-height:100dvh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-split-tabs{display:block;margin-bottom:16px}.sw-hint.sw-continue-hint{margin:14px 0 0}.sw-extra-status{font-size:.8125rem;color:#64748b;margin:12px 0 0}.sw-extra-status:empty{display:none}.sw-hint{font-size:.8125rem;line-height:1.5;color:#64748b;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px;margin-left:auto}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-step-actions{flex-direction:column-reverse;align-items:stretch;gap:10px}.sw-actions-right{flex-direction:column-reverse;align-items:stretch;gap:10px;margin-left:0}.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
43363
43409
  dependencies: [
43364
43410
  {
43365
43411
  kind: "directive",
@@ -43530,6 +43576,18 @@ var SetupWizardComponent = class SetupWizardComponent {
43530
43576
  ],
43531
43577
  outputs: ["action"]
43532
43578
  },
43579
+ {
43580
+ kind: "component",
43581
+ type: PillTabsComponent,
43582
+ selector: "ui-pill-tabs",
43583
+ inputs: [
43584
+ "tabs",
43585
+ "activeKey",
43586
+ "ariaLabel",
43587
+ "name"
43588
+ ],
43589
+ outputs: ["tabChange"]
43590
+ },
43533
43591
  {
43534
43592
  kind: "component",
43535
43593
  type: PanelInfoListComponent,
@@ -43669,6 +43727,7 @@ i0.ɵɵngDeclareClassMetadata({
43669
43727
  DetailCardComponent,
43670
43728
  ImportSourceGridComponent,
43671
43729
  OptionCardComponent,
43730
+ PillTabsComponent,
43672
43731
  PanelInfoListComponent,
43673
43732
  ProgressBarComponent,
43674
43733
  SectionHeaderComponent,
@@ -43706,16 +43765,41 @@ i0.ɵɵngDeclareClassMetadata({
43706
43765
  <ui-button variant="primary" size="sm" data-testid="wizard-finish" (click)="finished.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('check')" /></svg> {{ t().finish }}</ui-button>
43707
43766
  </div>
43708
43767
  } @else {
43709
- <div class="sw-step-content" [class.sw-wide]="split()" [attr.aria-busy]="busy()" [attr.data-step]="current().key">
43768
+ <div class="sw-step-content" [attr.aria-busy]="busy()" [attr.data-step]="current().key">
43710
43769
  @if (intro(); as i) { <ui-section-header class="sw-intro" data-testid="wizard-step-intro" size="lg" background="#eaf3ff" [title]="i.title" [description]="i.text"><span section-header-icon class="sw-step-number" data-testid="wizard-step-number">{{ index() + 1 }}</span></ui-section-header> }
43711
43770
 
43712
- <div class="sw-body" [class.sw-split]="split()" data-testid="wizard-body">
43713
- @if (split() && templateFor(current().key); as left) {
43771
+ <ng-template #actions>
43772
+ @if (index() > 0) { <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
43773
+ <div class="sw-actions-right">
43774
+ @if (current().skippable !== false) {
43775
+ <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
43776
+ }
43777
+ @if (current().kind === 'custom') {
43778
+ @if (!current().ownActions) {
43779
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
43780
+ {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
43781
+ </ui-button>
43782
+ }
43783
+ } @else if (current().kind === 'integrations') {
43784
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43785
+ } @else if (current().kind === 'import') {
43786
+ <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-continue" [disabled]="importBlocked()" [ariaDescribedBy]="importBlocked() ? 'sw-continue-hint' : ''" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43787
+ }
43788
+ </div>
43789
+ </ng-template>
43790
+ @if (split()) {
43791
+ <ui-pill-tabs class="sw-split-tabs" [tabs]="splitTabs()" [activeKey]="splitTab()" [ariaLabel]="current().label" (tabChange)="splitTab.set($event === 'main' ? 'main' : 'extra')" data-testid="wizard-split-tabs" />
43792
+ }
43793
+ @if (split() && splitTab() === 'extra' && templateFor(current().key); as left) {
43714
43794
  <ui-detail-card class="sw-card sw-extra-card" [title]="current().extraTitle ?? ''" [showHeader]="!!current().extraTitle" [headingLevel]="3" [collapsible]="false"
43715
- [ariaLabel]="current().extraTitle || current().label" headerBackground="rgb(248, 250, 252)" data-testid="wizard-extra-card">
43795
+ [ariaLabel]="current().extraTitle || current().label" headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)" data-testid="wizard-extra-card">
43716
43796
  <ng-container [ngTemplateOutlet]="left" [ngTemplateOutletContext]="{ $implicit: api }" />
43797
+ <p class="sw-extra-status" role="status" data-testid="wizard-extra-status">{{ current().extraFooter?.() }}</p>
43798
+ @if (importBlocked()) { <p class="sw-hint sw-continue-hint" id="sw-continue-hint" data-testid="wizard-continue-hint">{{ t().importRequired }}</p> }
43799
+ <div card-footer class="sw-step-actions"><ng-container [ngTemplateOutlet]="actions" /></div>
43717
43800
  </ui-detail-card>
43718
43801
  }
43802
+ @if (!split() || splitTab() === 'main') {
43719
43803
  <ui-detail-card class="sw-card" [showHeader]="!!current().cardTitle || !!headerTemplateFor(current().key)" [title]="current().cardTitle ?? ''" [headingLevel]="3" [collapsible]="false"
43720
43804
  [ariaLabel]="current().label" headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)" data-testid="wizard-step-card">
43721
43805
  @if (headerTemplateFor(current().key); as ht) {
@@ -43736,7 +43820,12 @@ i0.ɵɵngDeclareClassMetadata({
43736
43820
  @for (tag of imp.tags; track tag) { <ui-badge [label]="tag" variant="slate" /> }
43737
43821
  </div>
43738
43822
  }
43739
- @if (importResult(current().key); as res) {
43823
+ @if (importErrorCount(current().key) > 0) {
43824
+ <ui-alert variant="warning" [title]="t().importErrorsTitle(importErrorCount(current().key))" [attr.data-testid]="'import-errors-' + current().key">
43825
+ {{ t().importErrorsText(importResult(current().key) ?? 0, importErrorCount(current().key)) }}
43826
+ <ui-button variant="link" size="sm" data-testid="import-again" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importAgain }}</ui-button>
43827
+ </ui-alert>
43828
+ } @else if (importResult(current().key); as res) {
43740
43829
  <ui-alert variant="success" [title]="importTitle(current().key)" [attr.data-testid]="'import-result-' + current().key">
43741
43830
  {{ imp.resultText }}
43742
43831
  <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importMore }}</ui-button>
@@ -43770,35 +43859,19 @@ i0.ɵɵngDeclareClassMetadata({
43770
43859
  }
43771
43860
  }
43772
43861
 
43862
+ @if (importBlocked()) { <p class="sw-hint sw-continue-hint" id="sw-continue-hint" data-testid="wizard-continue-hint">{{ t().importRequired }}</p> }
43863
+
43773
43864
  @if (error()) { <ui-alert variant="danger" data-testid="wizard-save-error">{{ error() }}</ui-alert> }
43774
43865
 
43775
- <div card-footer class="sw-step-actions">
43776
- @if (index() > 0) { <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
43777
- <div class="sw-actions-right">
43778
- @if (current().skippable !== false) {
43779
- <ui-button variant="secondary" size="sm" [fullWidth]="narrow()" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
43780
- }
43781
- @if (current().kind === 'custom') {
43782
- @if (!current().ownActions) {
43783
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
43784
- {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
43785
- </ui-button>
43786
- }
43787
- } @else if (current().kind === 'integrations') {
43788
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43789
- } @else if (current().kind === 'import') {
43790
- <ui-button variant="primary" size="sm" [fullWidth]="narrow()" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
43791
- }
43792
- </div>
43793
- </div>
43866
+ <div card-footer class="sw-step-actions"><ng-container [ngTemplateOutlet]="actions" /></div>
43794
43867
  </ui-detail-card>
43795
- </div>
43868
+ }
43796
43869
  </div>
43797
43870
  }
43798
43871
  </main>
43799
43872
  </div>
43800
43873
  `,
43801
- styles: [".sw-page{display:flex;min-height:100vh;min-height:100dvh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}@media(min-width:1100px){.sw-step-content.sw-wide{max-width:1400px}}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-body{display:block}.sw-body.sw-split{display:grid;grid-template-columns:1fr;gap:24px}@media(min-width:1100px){.sw-body.sw-split{grid-template-columns:1fr 1fr;align-items:start}}.sw-body>.sw-card{min-width:0}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-step-actions,.sw-actions-right{flex-direction:column-reverse;align-items:stretch;gap:10px}.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
43874
+ styles: [".sw-page{display:flex;min-height:100vh;min-height:100dvh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-split-tabs{display:block;margin-bottom:16px}.sw-hint.sw-continue-hint{margin:14px 0 0}.sw-extra-status{font-size:.8125rem;color:#64748b;margin:12px 0 0}.sw-extra-status:empty{display:none}.sw-hint{font-size:.8125rem;line-height:1.5;color:#64748b;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px;margin-left:auto}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-step-actions{flex-direction:column-reverse;align-items:stretch;gap:10px}.sw-actions-right{flex-direction:column-reverse;align-items:stretch;gap:10px;margin-left:0}.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
43802
43875
  }]
43803
43876
  }],
43804
43877
  ctorParameters: () => [],
@@ -45430,7 +45503,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
45430
45503
  @for (v of group.variables; track v.key) {
45431
45504
  <button type="button" class="variable-item" (mousedown)="saveSelection()" (click)="insertVariable(v)">
45432
45505
  <span class="var-tag">{{ '{{' + v.key + '}}' }}</span>
45433
- <span class="var-example">{{ v.example }}</span>
45506
+ <span class="var-example">Example: {{ v.example }}</span>
45434
45507
  <!-- A very short explanation of what the variable is: the host's description, else its label. -->
45435
45508
  <span class="var-description">{{ v.description || v.label }}</span>
45436
45509
  </button>
@@ -46213,7 +46286,7 @@ i0.ɵɵngDeclareClassMetadata({
46213
46286
  @for (v of group.variables; track v.key) {
46214
46287
  <button type="button" class="variable-item" (mousedown)="saveSelection()" (click)="insertVariable(v)">
46215
46288
  <span class="var-tag">{{ '{{' + v.key + '}}' }}</span>
46216
- <span class="var-example">{{ v.example }}</span>
46289
+ <span class="var-example">Example: {{ v.example }}</span>
46217
46290
  <!-- A very short explanation of what the variable is: the host's description, else its label. -->
46218
46291
  <span class="var-description">{{ v.description || v.label }}</span>
46219
46292
  </button>