@memberjunction/ng-artifacts 5.28.0 → 5.29.0

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.
Files changed (65) hide show
  1. package/dist/lib/__tests__/artifact-snapshots.test.d.ts +2 -0
  2. package/dist/lib/__tests__/artifact-snapshots.test.d.ts.map +1 -0
  3. package/dist/lib/__tests__/artifact-snapshots.test.js +155 -0
  4. package/dist/lib/__tests__/artifact-snapshots.test.js.map +1 -0
  5. package/dist/lib/components/artifact-viewer-panel.component.d.ts +16 -2
  6. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  7. package/dist/lib/components/artifact-viewer-panel.component.js +128 -98
  8. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  9. package/dist/lib/components/base-artifact-viewer.component.d.ts +24 -0
  10. package/dist/lib/components/base-artifact-viewer.component.d.ts.map +1 -1
  11. package/dist/lib/components/base-artifact-viewer.component.js +15 -1
  12. package/dist/lib/components/base-artifact-viewer.component.js.map +1 -1
  13. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts +2 -0
  14. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts.map +1 -1
  15. package/dist/lib/components/plugins/code-artifact-viewer.component.js +5 -1
  16. package/dist/lib/components/plugins/code-artifact-viewer.component.js.map +1 -1
  17. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +2 -1
  18. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
  19. package/dist/lib/components/plugins/component-artifact-viewer.component.js +29 -0
  20. package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
  21. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts +50 -43
  22. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts.map +1 -1
  23. package/dist/lib/components/plugins/data-artifact-viewer.component.js +336 -137
  24. package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
  25. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts +2 -0
  26. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts.map +1 -1
  27. package/dist/lib/components/plugins/docx-artifact-viewer.component.js +21 -6
  28. package/dist/lib/components/plugins/docx-artifact-viewer.component.js.map +1 -1
  29. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts +2 -0
  30. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts.map +1 -1
  31. package/dist/lib/components/plugins/html-artifact-viewer.component.js +11 -1
  32. package/dist/lib/components/plugins/html-artifact-viewer.component.js.map +1 -1
  33. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts +2 -0
  34. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
  35. package/dist/lib/components/plugins/json-artifact-viewer.component.js +5 -1
  36. package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
  37. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts +2 -0
  38. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts.map +1 -1
  39. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js +5 -1
  40. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js.map +1 -1
  41. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts +2 -0
  42. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts.map +1 -1
  43. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js +29 -10
  44. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js.map +1 -1
  45. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts +2 -0
  46. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts.map +1 -1
  47. package/dist/lib/components/plugins/svg-artifact-viewer.component.js +11 -1
  48. package/dist/lib/components/plugins/svg-artifact-viewer.component.js.map +1 -1
  49. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts +2 -0
  50. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts.map +1 -1
  51. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js +39 -13
  52. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js.map +1 -1
  53. package/dist/lib/services/analyze-artifact.service.d.ts +77 -0
  54. package/dist/lib/services/analyze-artifact.service.d.ts.map +1 -0
  55. package/dist/lib/services/analyze-artifact.service.js +120 -0
  56. package/dist/lib/services/analyze-artifact.service.js.map +1 -0
  57. package/dist/lib/snapshot-helpers.d.ts +48 -0
  58. package/dist/lib/snapshot-helpers.d.ts.map +1 -0
  59. package/dist/lib/snapshot-helpers.js +79 -0
  60. package/dist/lib/snapshot-helpers.js.map +1 -0
  61. package/dist/public-api.d.ts +2 -0
  62. package/dist/public-api.d.ts.map +1 -1
  63. package/dist/public-api.js +3 -0
  64. package/dist/public-api.js.map +1 -1
  65. package/package.json +16 -16
@@ -1 +1 @@
1
- {"version":3,"file":"svg-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/svg-artifact-viewer.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;;;;;;IAyB5E,8BAAyB;IACvB,0BAA4D;IAC9D,iBAAM;;;IADqB,cAA4B;IAA5B,oEAA4B;;;;IAGvD,0CAIqC;IAHnC,gUAAwB;IAI1B,iBAAiB;;;IAJf,iDAAwB;IAExB,AADA,gCAAkB,6BACG;;AA9BjC;;GAEG;AAuGI,IAAM,0BAA0B,GAAhC,MAAM,0BAA2B,SAAQ,iCAAiC;IAY3D;IAXb,UAAU,GAAG,EAAE,CAAC;IAChB,cAAc,GAAa,EAAE,CAAC;IAC9B,QAAQ,GAAyB,SAAS,CAAC;IAElD;;OAEG;IACH,IAAoB,iBAAiB;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAoB,SAAuB;QACzC,KAAK,EAAE,CAAC;QADU,cAAS,GAAT,SAAS,CAAc;IAE3C,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,iFAAiF;QACjF,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBACvD,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YAC3C,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;oHA9BU,0BAA0B;6DAA1B,0BAA0B;YAhG/B,AADF,AADF,8BAAsD,aAC3B,gBAEgC;YAA/B,sHAAoB,SAAS,IAAC;YACpD,uBAA0B;YAAC,yBAC7B;YAAA,iBAAS;YACT,iCACqD;YAA9B,sHAAoB,QAAQ,IAAC;YAClD,uBAA2B;YAAC,wBAC9B;YAAA,iBAAS;YACT,iCAA6D;YAAnB,uGAAS,YAAQ,IAAC;YAC1D,uBAA2B;YAAC,uBAC9B;YACF,AADE,iBAAS,EACL;YACN,+BAAmC;YAK/B,AAJF,8FAA8B,oFAIrB;YASb,AADE,iBAAM,EACF;;YA5B2B,sCAAoB;YAExB,eAAuC;YAAvC,oDAAuC;YAIvC,eAAsC;YAAtC,mDAAsC;YAS/D,eAWC;YAXD,sDAWC;;;AAwEI,0BAA0B;IADtC,aAAa,CAAC,iCAAiC,EAAE,yBAAyB,CAAC;GAC/D,0BAA0B,CA+BtC;;iFA/BY,0BAA0B;cAtGtC,SAAS;6BACI,KAAK,YACP,wBAAwB,YACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BT;;kFAqEU,0BAA0B","sourcesContent":["import { Component } from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\n\n/**\n * Viewer component for SVG artifacts\n */\n@Component({\n standalone: false,\n selector: 'mj-svg-artifact-viewer',\n template: `\n <div class=\"svg-artifact-viewer\" [ngClass]=\"cssClass\">\n <div class=\"svg-toolbar\">\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'preview'\"\n title=\"Preview\" (click)=\"viewMode = 'preview'\">\n <i class=\"fas fa-eye\"></i> Preview\n </button>\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'source'\"\n title=\"Source\" (click)=\"viewMode = 'source'\">\n <i class=\"fas fa-code\"></i> Source\n </button>\n <button class=\"btn-icon\" title=\"Copy SVG\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"svg-content-container\">\n @if (viewMode === 'preview') {\n <div class=\"svg-preview\">\n <div class=\"svg-wrapper\" [innerHTML]=\"safeSvgContent\"></div>\n </div>\n } @else {\n <mj-code-editor\n [(ngModel)]=\"svgContent\"\n [language]=\"'xml'\"\n [readonly]=\"readonly\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n }\n </div>\n </div>\n `,\n styles: [`\n .svg-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .svg-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .svg-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .svg-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .svg-wrapper {\n max-width: 100%;\n max-height: 100%;\n }\n\n .svg-wrapper ::ng-deep svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'SvgArtifactViewerPlugin')\nexport class SvgArtifactViewerComponent extends BaseArtifactViewerPluginComponent {\n public svgContent = '';\n public safeSvgContent: SafeHtml = '';\n public viewMode: 'preview' | 'source' = 'preview';\n\n /**\n * SVG artifacts always have content to display\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n constructor(private sanitizer: DomSanitizer) {\n super();\n }\n\n ngOnInit(): void {\n this.svgContent = this.getContent();\n // For SVG, we use sanitize with SecurityContext.HTML (1) to allow safe rendering\n this.safeSvgContent = this.sanitizer.sanitize(1, this.svgContent) || '';\n }\n\n onCopy(): void {\n if (this.svgContent) {\n navigator.clipboard.writeText(this.svgContent).then(() => {\n console.log('✅ Copied SVG to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"svg-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/svg-artifact-viewer.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;;;;;;IAyB5E,8BAAyB;IACvB,0BAA4D;IAC9D,iBAAM;;;IADqB,cAA4B;IAA5B,oEAA4B;;;;IAGvD,0CAIqC;IAHnC,gUAAwB;IAI1B,iBAAiB;;;IAJf,iDAAwB;IAExB,AADA,gCAAkB,6BACG;;AA9BjC;;GAEG;AAuGI,IAAM,0BAA0B,GAAhC,MAAM,0BAA2B,SAAQ,iCAAiC;IAY3D;IAXb,UAAU,GAAG,EAAE,CAAC;IAChB,cAAc,GAAa,EAAE,CAAC;IAC9B,QAAQ,GAAyB,SAAS,CAAC;IAElD;;OAEG;IACH,IAAoB,iBAAiB;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAoB,SAAuB;QACzC,KAAK,EAAE,CAAC;QADU,cAAS,GAAT,SAAS,CAAc;IAE3C,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,iFAAiF;QACjF,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAC1E,CAAC;IAEe,uBAAuB;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,SAAS,CAAC;QACjD,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBACvD,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YAC3C,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;oHAvCU,0BAA0B;6DAA1B,0BAA0B;YAhG/B,AADF,AADF,8BAAsD,aAC3B,gBAEgC;YAA/B,sHAAoB,SAAS,IAAC;YACpD,uBAA0B;YAAC,yBAC7B;YAAA,iBAAS;YACT,iCACqD;YAA9B,sHAAoB,QAAQ,IAAC;YAClD,uBAA2B;YAAC,wBAC9B;YAAA,iBAAS;YACT,iCAA6D;YAAnB,uGAAS,YAAQ,IAAC;YAC1D,uBAA2B;YAAC,uBAC9B;YACF,AADE,iBAAS,EACL;YACN,+BAAmC;YAK/B,AAJF,8FAA8B,oFAIrB;YASb,AADE,iBAAM,EACF;;YA5B2B,sCAAoB;YAExB,eAAuC;YAAvC,oDAAuC;YAIvC,eAAsC;YAAtC,mDAAsC;YAS/D,eAWC;YAXD,sDAWC;;;AAwEI,0BAA0B;IADtC,aAAa,CAAC,iCAAiC,EAAE,yBAAyB,CAAC;GAC/D,0BAA0B,CAwCtC;;iFAxCY,0BAA0B;cAtGtC,SAAS;6BACI,KAAK,YACP,wBAAwB,YACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BT;;kFAqEU,0BAA0B","sourcesContent":["import { Component } from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\n\n/**\n * Viewer component for SVG artifacts\n */\n@Component({\n standalone: false,\n selector: 'mj-svg-artifact-viewer',\n template: `\n <div class=\"svg-artifact-viewer\" [ngClass]=\"cssClass\">\n <div class=\"svg-toolbar\">\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'preview'\"\n title=\"Preview\" (click)=\"viewMode = 'preview'\">\n <i class=\"fas fa-eye\"></i> Preview\n </button>\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'source'\"\n title=\"Source\" (click)=\"viewMode = 'source'\">\n <i class=\"fas fa-code\"></i> Source\n </button>\n <button class=\"btn-icon\" title=\"Copy SVG\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"svg-content-container\">\n @if (viewMode === 'preview') {\n <div class=\"svg-preview\">\n <div class=\"svg-wrapper\" [innerHTML]=\"safeSvgContent\"></div>\n </div>\n } @else {\n <mj-code-editor\n [(ngModel)]=\"svgContent\"\n [language]=\"'xml'\"\n [readonly]=\"readonly\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n }\n </div>\n </div>\n `,\n styles: [`\n .svg-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .svg-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .svg-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .svg-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .svg-wrapper {\n max-width: 100%;\n max-height: 100%;\n }\n\n .svg-wrapper ::ng-deep svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'SvgArtifactViewerPlugin')\nexport class SvgArtifactViewerComponent extends BaseArtifactViewerPluginComponent {\n public svgContent = '';\n public safeSvgContent: SafeHtml = '';\n public viewMode: 'preview' | 'source' = 'preview';\n\n /**\n * SVG artifacts always have content to display\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n constructor(private sanitizer: DomSanitizer) {\n super();\n }\n\n ngOnInit(): void {\n this.svgContent = this.getContent();\n // For SVG, we use sanitize with SecurityContext.HTML (1) to allow safe rendering\n this.safeSvgContent = this.sanitizer.sanitize(1, this.svgContent) || '';\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n const content = this.getRawContent();\n if (!content) return null;\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.custom = { content };\n return snap;\n }\n\n onCopy(): void {\n if (this.svgContent) {\n navigator.clipboard.writeText(this.svgContent).then(() => {\n console.log('✅ Copied SVG to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { OnInit, ChangeDetectorRef } from '@angular/core';
2
+ import { DataSnapshot } from '@memberjunction/core';
2
3
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
3
4
  import { ArtifactFileService } from '../../services/artifact-file.service';
4
5
  import { ColDef, GridReadyEvent } from 'ag-grid-community';
@@ -37,6 +38,7 @@ export declare class XlsxArtifactViewerComponent extends BaseArtifactViewerPlugi
37
38
  private parseWorkbook;
38
39
  private fetchAsArrayBuffer;
39
40
  private showError;
41
+ GetCurrentStateSnapshot(): DataSnapshot | null;
40
42
  static ɵfac: i0.ɵɵFactoryDeclaration<XlsxArtifactViewerComponent, never>;
41
43
  static ɵcmp: i0.ɵɵComponentDeclaration<XlsxArtifactViewerComponent, "mj-xlsx-artifact-viewer", never, {}, {}, never, never, false, never>;
42
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"xlsx-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/xlsx-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,cAAc,EAAW,MAAM,mBAAmB,CAAC;;AAEpE,mDAAmD;AACnD,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;IAC5D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBA0Ia,2BAA4B,SAAQ,iCAAkC,YAAW,MAAM;IAahG,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,GAAG;IAZN,SAAS,UAAQ;IACjB,aAAa,UAAS;IACtB,YAAY,SAAM;IAClB,MAAM,EAAE,SAAS,EAAE,CAAM;IACzB,gBAAgB,SAAK;IACrB,aAAa,EAAE,MAAM,CAAmE;IAE/F,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,WAAW,CAAM;gBAGf,WAAW,EAAE,mBAAmB,EAChC,GAAG,EAAE,iBAAiB;IAKhC,IAAoB,iBAAiB,IAAI,OAAO,CAAiB;IAEjE,IAAW,WAAW,IAAI,SAAS,GAAG,IAAI,CAEzC;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAKxC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAO1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAmB1B,YAAY;IAsC1B,OAAO,CAAC,aAAa;YAmBP,kBAAkB;IAQhC,OAAO,CAAC,SAAS;yCA7HN,2BAA2B;2CAA3B,2BAA2B;CAmIvC"}
1
+ {"version":3,"file":"xlsx-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/xlsx-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,YAAY,EAAiC,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,cAAc,EAAW,MAAM,mBAAmB,CAAC;;AAEpE,mDAAmD;AACnD,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;IAC5D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBA6Ia,2BAA4B,SAAQ,iCAAkC,YAAW,MAAM;IAYhG,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,GAAG;IAZN,SAAS,UAAQ;IACjB,aAAa,UAAS;IACtB,YAAY,SAAM;IAClB,MAAM,EAAE,SAAS,EAAE,CAAM;IACzB,gBAAgB,SAAK;IACrB,aAAa,EAAE,MAAM,CAAmE;IAE/F,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,WAAW,CAAM;gBAGf,WAAW,EAAE,mBAAmB,EAChC,GAAG,EAAE,iBAAiB;IAKhC,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;IAED,IAAW,WAAW,IAAI,SAAS,GAAG,IAAI,CAEzC;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAKxC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAO1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAgB1B,YAAY;IAsC1B,OAAO,CAAC,aAAa;YAmBP,kBAAkB;IAQhC,OAAO,CAAC,SAAS;IAMD,uBAAuB,IAAI,YAAY,GAAG,IAAI;yCAjInD,2BAA2B;2CAA3B,2BAA2B;CA0JvC"}
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { Component } from '@angular/core';
8
8
  import { RegisterClass } from '@memberjunction/global';
9
+ import { DataSnapshot, DataTable, MJColumnDescriptor } from '@memberjunction/core';
9
10
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
10
11
  import * as i0 from "@angular/core";
11
12
  import * as i1 from "../../services/artifact-file.service";
@@ -88,7 +89,9 @@ let XlsxArtifactViewerComponent = class XlsxArtifactViewerComponent extends Base
88
89
  this.fileService = fileService;
89
90
  this.cdr = cdr;
90
91
  }
91
- get hasDisplayContent() { return true; }
92
+ get hasDisplayContent() {
93
+ return true;
94
+ }
92
95
  get activeSheet() {
93
96
  return this.sheets[this.activeSheetIndex] ?? null;
94
97
  }
@@ -143,7 +146,7 @@ let XlsxArtifactViewerComponent = class XlsxArtifactViewerComponent extends Base
143
146
  // Create an object URL for download support
144
147
  this.downloadUrl = this.fileService.dataUrlToObjectUrl(content, this.artifactVersion.MimeType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
145
148
  }
146
- const XLSX = await import('xlsx');
149
+ const XLSX = (await import('xlsx'));
147
150
  const workbook = XLSX.read(arrayBuffer, { type: 'array' });
148
151
  this.sheets = this.parseWorkbook(workbook, XLSX);
149
152
  this.isLoading = false;
@@ -154,14 +157,14 @@ let XlsxArtifactViewerComponent = class XlsxArtifactViewerComponent extends Base
154
157
  }
155
158
  }
156
159
  parseWorkbook(workbook, XLSX) {
157
- return workbook.SheetNames.map(name => {
160
+ return workbook.SheetNames.map((name) => {
158
161
  const sheet = workbook.Sheets[name];
159
162
  const rows = XLSX.utils.sheet_to_json(sheet, {
160
163
  defval: null,
161
164
  raw: false, // Format dates/numbers as strings so AG Grid can display them
162
165
  });
163
166
  const headers = rows.length > 0 ? Object.keys(rows[0]) : [];
164
- const columnDefs = headers.map(h => ({
167
+ const columnDefs = headers.map((h) => ({
165
168
  field: h,
166
169
  headerName: h,
167
170
  tooltipField: h,
@@ -181,6 +184,30 @@ let XlsxArtifactViewerComponent = class XlsxArtifactViewerComponent extends Base
181
184
  this.errorMessage = message;
182
185
  this.cdr.markForCheck();
183
186
  }
187
+ GetCurrentStateSnapshot() {
188
+ if (this.sheets.length === 0)
189
+ return null;
190
+ // Convert parsed sheets into DataTables for structured snapshot
191
+ const tables = this.sheets.map((sheet) => {
192
+ const table = new DataTable();
193
+ table.name = sheet.name;
194
+ table.source = 'static';
195
+ table.columns = sheet.columnDefs
196
+ .filter((col) => col.field)
197
+ .map((col) => {
198
+ const desc = new MJColumnDescriptor(col.field);
199
+ desc.displayName = col.headerName ?? col.field;
200
+ desc.sqlBaseType = 'nvarchar';
201
+ return desc;
202
+ });
203
+ table.rows = sheet.rowData;
204
+ table.metadata = { rowCount: sheet.rowData.length };
205
+ return table;
206
+ });
207
+ const snap = DataSnapshot.FromTables(tables, this.getDisplayTitle() ?? undefined);
208
+ snap.activeTab = this.sheets[this.activeSheetIndex]?.name;
209
+ return snap;
210
+ }
184
211
  static ɵfac = function XlsxArtifactViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || XlsxArtifactViewerComponent)(i0.ɵɵdirectiveInject(i1.ArtifactFileService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
185
212
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: XlsxArtifactViewerComponent, selectors: [["mj-xlsx-artifact-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 4, consts: [[1, "xlsx-viewer"], [3, "download", "fileName", "isDownloading", "showPrint"], [1, "xlsx-viewer__state"], [1, "xlsx-viewer__state", "xlsx-viewer__state--error"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-exclamation-triangle"], [1, "xlsx-viewer__tabs"], [1, "xlsx-viewer__grid"], [1, "ag-theme-quartz", 3, "gridReady", "rowData", "columnDefs", "defaultColDef", "animateRows", "suppressMovableColumns", "enableCellTextSelection"], [1, "xlsx-viewer__tab", 3, "xlsx-viewer__tab--active"], [1, "xlsx-viewer__tab", 3, "click"], [1, "fas", "fa-table"]], template: function XlsxArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
186
213
  i0.ɵɵelementStart(0, "div", 0)(1, "mj-file-artifact-toolbar", 1);
@@ -193,7 +220,7 @@ let XlsxArtifactViewerComponent = class XlsxArtifactViewerComponent extends Base
193
220
  i0.ɵɵproperty("fileName", (ctx.artifactVersion == null ? null : ctx.artifactVersion.FileName) || "workbook.xlsx")("isDownloading", ctx.isDownloading)("showPrint", false);
194
221
  i0.ɵɵadvance();
195
222
  i0.ɵɵconditional(ctx.isLoading ? 2 : ctx.errorMessage ? 3 : 4);
196
- } }, dependencies: [i2.AgGridAngular, i3.FileArtifactToolbarComponent], styles: [".xlsx-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition: background 0.1s, color 0.1s;\n }\n\n .xlsx-viewer__tab[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid[_ngcontent-%COMP%] ag-grid-angular[_ngcontent-%COMP%] {\n height: 100%;\n width: 100%;\n display: block;\n }"] });
223
+ } }, dependencies: [i2.AgGridAngular, i3.FileArtifactToolbarComponent], styles: [".xlsx-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition:\n background 0.1s,\n color 0.1s;\n }\n\n .xlsx-viewer__tab[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid[_ngcontent-%COMP%] ag-grid-angular[_ngcontent-%COMP%] {\n height: 100%;\n width: 100%;\n display: block;\n }"] });
197
224
  };
198
225
  XlsxArtifactViewerComponent = __decorate([
199
226
  RegisterClass(BaseArtifactViewerPluginComponent, 'XlsxArtifactViewerPlugin')
@@ -207,7 +234,8 @@ export { XlsxArtifactViewerComponent };
207
234
  [fileName]="artifactVersion?.FileName || 'workbook.xlsx'"
208
235
  [isDownloading]="isDownloading"
209
236
  [showPrint]="false"
210
- (download)="onDownload()">
237
+ (download)="onDownload()"
238
+ >
211
239
  </mj-file-artifact-toolbar>
212
240
 
213
241
  @if (isLoading) {
@@ -224,10 +252,7 @@ export { XlsxArtifactViewerComponent };
224
252
  @if (sheets.length > 1) {
225
253
  <div class="xlsx-viewer__tabs">
226
254
  @for (sheet of sheets; track sheet.name; let i = $index) {
227
- <button
228
- class="xlsx-viewer__tab"
229
- [class.xlsx-viewer__tab--active]="i === activeSheetIndex"
230
- (click)="selectSheet(i)">
255
+ <button class="xlsx-viewer__tab" [class.xlsx-viewer__tab--active]="i === activeSheetIndex" (click)="selectSheet(i)">
231
256
  <i class="fas fa-table"></i>
232
257
  {{ sheet.name }}
233
258
  </button>
@@ -244,12 +269,13 @@ export { XlsxArtifactViewerComponent };
244
269
  [animateRows]="false"
245
270
  [suppressMovableColumns]="false"
246
271
  [enableCellTextSelection]="true"
247
- (gridReady)="onGridReady($event)">
272
+ (gridReady)="onGridReady($event)"
273
+ >
248
274
  </ag-grid-angular>
249
275
  </div>
250
276
  }
251
277
  </div>
252
- `, styles: ["\n .xlsx-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition: background 0.1s, color 0.1s;\n }\n\n .xlsx-viewer__tab:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid ag-grid-angular {\n height: 100%;\n width: 100%;\n display: block;\n }\n "] }]
278
+ `, styles: ["\n .xlsx-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition:\n background 0.1s,\n color 0.1s;\n }\n\n .xlsx-viewer__tab:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid ag-grid-angular {\n height: 100%;\n width: 100%;\n display: block;\n }\n "] }]
253
279
  }], () => [{ type: i1.ArtifactFileService }, { type: i0.ChangeDetectorRef }], null); })();
254
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(XlsxArtifactViewerComponent, { className: "XlsxArtifactViewerComponent", filePath: "src/lib/components/plugins/xlsx-artifact-viewer.component.ts", lineNumber: 158 }); })();
280
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(XlsxArtifactViewerComponent, { className: "XlsxArtifactViewerComponent", filePath: "src/lib/components/plugins/xlsx-artifact-viewer.component.ts", lineNumber: 162 }); })();
255
281
  //# sourceMappingURL=xlsx-artifact-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xlsx-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/xlsx-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { ColDef, GridReadyEvent, GridApi } from 'ag-grid-community';\n\n/** A parsed sheet ready for display in AG Grid. */\ninterface SheetData {\n name: string;\n rowData: Record<string, string | number | boolean | null>[];\n columnDefs: ColDef[];\n}\n\n/**\n * Viewer plugin for Excel (XLSX/XLS) artifact versions stored in MJStorage.\n *\n * Downloads the file, parses all sheets with SheetJS, then renders the active\n * sheet in an AG Grid. Sheet tabs let the user switch between sheets.\n */\n@Component({\n standalone: false,\n selector: 'mj-xlsx-artifact-viewer',\n template: `\n <div class=\"xlsx-viewer\">\n <mj-file-artifact-toolbar\n [fileName]=\"artifactVersion?.FileName || 'workbook.xlsx'\"\n [isDownloading]=\"isDownloading\"\n [showPrint]=\"false\"\n (download)=\"onDownload()\">\n </mj-file-artifact-toolbar>\n\n @if (isLoading) {\n <div class=\"xlsx-viewer__state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading workbook…</span>\n </div>\n } @else if (errorMessage) {\n <div class=\"xlsx-viewer__state xlsx-viewer__state--error\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else {\n @if (sheets.length > 1) {\n <div class=\"xlsx-viewer__tabs\">\n @for (sheet of sheets; track sheet.name; let i = $index) {\n <button\n class=\"xlsx-viewer__tab\"\n [class.xlsx-viewer__tab--active]=\"i === activeSheetIndex\"\n (click)=\"selectSheet(i)\">\n <i class=\"fas fa-table\"></i>\n {{ sheet.name }}\n </button>\n }\n </div>\n }\n\n <div class=\"xlsx-viewer__grid\">\n <ag-grid-angular\n class=\"ag-theme-quartz\"\n [rowData]=\"activeSheet?.rowData\"\n [columnDefs]=\"activeSheet?.columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [animateRows]=\"false\"\n [suppressMovableColumns]=\"false\"\n [enableCellTextSelection]=\"true\"\n (gridReady)=\"onGridReady($event)\">\n </ag-grid-angular>\n </div>\n }\n </div>\n `,\n styles: [`\n .xlsx-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition: background 0.1s, color 0.1s;\n }\n\n .xlsx-viewer__tab:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid ag-grid-angular {\n height: 100%;\n width: 100%;\n display: block;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'XlsxArtifactViewerPlugin')\nexport class XlsxArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n\n public isLoading = true;\n public isDownloading = false;\n public errorMessage = '';\n public sheets: SheetData[] = [];\n public activeSheetIndex = 0;\n public defaultColDef: ColDef = { resizable: true, sortable: true, filter: true, minWidth: 80 };\n\n private gridApi: GridApi | null = null;\n private downloadUrl = '';\n\n constructor(\n private fileService: ArtifactFileService,\n private cdr: ChangeDetectorRef,\n ) {\n super();\n }\n\n public override get hasDisplayContent(): boolean { return true; }\n\n public get activeSheet(): SheetData | null {\n return this.sheets[this.activeSheetIndex] ?? null;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadWorkbook();\n }\n\n public onGridReady(event: GridReadyEvent): void {\n this.gridApi = event.api;\n this.gridApi.sizeColumnsToFit();\n }\n\n public selectSheet(index: number): void {\n this.activeSheetIndex = index;\n this.cdr.markForCheck();\n // Let Angular render the new rowData/columnDefs before re-sizing\n setTimeout(() => this.gridApi?.sizeColumnsToFit(), 0);\n }\n\n public async onDownload(): Promise<void> {\n if (!this.downloadUrl || this.isDownloading) {\n return;\n }\n this.isDownloading = true;\n this.cdr.markForCheck();\n try {\n await this.triggerBrowserDownload(\n this.downloadUrl,\n this.artifactVersion?.FileName || 'workbook.xlsx',\n );\n } finally {\n this.isDownloading = false;\n this.cdr.markForCheck();\n }\n }\n\n // ─── Private helpers ────────────────────────────────────────────────────────\n\n private async loadWorkbook(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n this.showError('No artifact version provided.');\n return;\n }\n\n try {\n let arrayBuffer: ArrayBuffer;\n\n if (this.artifactVersion.ContentMode === 'File') {\n // File-backed: download from storage via pre-auth URL\n this.downloadUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n arrayBuffer = await this.fetchAsArrayBuffer(this.downloadUrl);\n } else {\n // Inline: content is a base64 data URL stored in the artifact version\n const content = this.artifactVersion.Content;\n if (!content) {\n this.showError('Artifact has no content.');\n return;\n }\n arrayBuffer = this.fileService.dataUrlToArrayBuffer(content);\n // Create an object URL for download support\n this.downloadUrl = this.fileService.dataUrlToObjectUrl(\n content,\n this.artifactVersion.MimeType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n );\n }\n\n const XLSX = await import('xlsx') as unknown as XlsxModuleShim;\n const workbook = XLSX.read(arrayBuffer, { type: 'array' });\n this.sheets = this.parseWorkbook(workbook, XLSX);\n this.isLoading = false;\n this.cdr.markForCheck();\n } catch (err) {\n this.showError(`Could not load workbook: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n private parseWorkbook(workbook: WorkbookType, XLSX: XlsxModuleShim): SheetData[] {\n return workbook.SheetNames.map(name => {\n const sheet = workbook.Sheets[name];\n const rows = XLSX.utils.sheet_to_json<Record<string, string | number | boolean | null>>(sheet, {\n defval: null,\n raw: false, // Format dates/numbers as strings so AG Grid can display them\n });\n\n const headers = rows.length > 0 ? Object.keys(rows[0]) : [];\n const columnDefs: ColDef[] = headers.map(h => ({\n field: h,\n headerName: h,\n tooltipField: h,\n }));\n\n return { name, rowData: rows, columnDefs };\n });\n }\n\n private async fetchAsArrayBuffer(url: string): Promise<ArrayBuffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching file`);\n }\n return response.arrayBuffer();\n }\n\n private showError(message: string): void {\n this.isLoading = false;\n this.errorMessage = message;\n this.cdr.markForCheck();\n }\n\n}\n\n\n// ─── Minimal type shims for xlsx dynamic import ────────────────────────────────\n\ninterface WorkbookType {\n SheetNames: string[];\n Sheets: Record<string, unknown>;\n}\n\ninterface XlsxModuleShim {\n read(data: ArrayBuffer, opts: { type: 'array' | 'buffer' | 'binary' | 'base64' | 'string' }): WorkbookType;\n utils: {\n sheet_to_json<T>(sheet: unknown, opts: { defval: null; raw: boolean }): T[];\n };\n}\n"]}
1
+ {"version":3,"file":"xlsx-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/xlsx-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { DataSnapshot, DataTable, MJColumnDescriptor } from '@memberjunction/core';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { ColDef, GridReadyEvent, GridApi } from 'ag-grid-community';\n\n/** A parsed sheet ready for display in AG Grid. */\ninterface SheetData {\n name: string;\n rowData: Record<string, string | number | boolean | null>[];\n columnDefs: ColDef[];\n}\n\n/**\n * Viewer plugin for Excel (XLSX/XLS) artifact versions stored in MJStorage.\n *\n * Downloads the file, parses all sheets with SheetJS, then renders the active\n * sheet in an AG Grid. Sheet tabs let the user switch between sheets.\n */\n@Component({\n standalone: false,\n selector: 'mj-xlsx-artifact-viewer',\n template: `\n <div class=\"xlsx-viewer\">\n <mj-file-artifact-toolbar\n [fileName]=\"artifactVersion?.FileName || 'workbook.xlsx'\"\n [isDownloading]=\"isDownloading\"\n [showPrint]=\"false\"\n (download)=\"onDownload()\"\n >\n </mj-file-artifact-toolbar>\n\n @if (isLoading) {\n <div class=\"xlsx-viewer__state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading workbook…</span>\n </div>\n } @else if (errorMessage) {\n <div class=\"xlsx-viewer__state xlsx-viewer__state--error\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else {\n @if (sheets.length > 1) {\n <div class=\"xlsx-viewer__tabs\">\n @for (sheet of sheets; track sheet.name; let i = $index) {\n <button class=\"xlsx-viewer__tab\" [class.xlsx-viewer__tab--active]=\"i === activeSheetIndex\" (click)=\"selectSheet(i)\">\n <i class=\"fas fa-table\"></i>\n {{ sheet.name }}\n </button>\n }\n </div>\n }\n\n <div class=\"xlsx-viewer__grid\">\n <ag-grid-angular\n class=\"ag-theme-quartz\"\n [rowData]=\"activeSheet?.rowData\"\n [columnDefs]=\"activeSheet?.columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [animateRows]=\"false\"\n [suppressMovableColumns]=\"false\"\n [enableCellTextSelection]=\"true\"\n (gridReady)=\"onGridReady($event)\"\n >\n </ag-grid-angular>\n </div>\n }\n </div>\n `,\n styles: [\n `\n .xlsx-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .xlsx-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .xlsx-viewer__tabs {\n display: flex;\n gap: 2px;\n padding: 4px 8px 0;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n overflow-x: auto;\n flex-shrink: 0;\n }\n\n .xlsx-viewer__tab {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-bottom: none;\n border-radius: 4px 4px 0 0;\n color: var(--mj-text-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition:\n background 0.1s,\n color 0.1s;\n }\n\n .xlsx-viewer__tab:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .xlsx-viewer__tab--active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-border-default);\n font-weight: 600;\n position: relative;\n }\n\n .xlsx-viewer__tab--active::after {\n content: '';\n position: absolute;\n bottom: -1px;\n left: 0;\n right: 0;\n height: 1px;\n background: var(--mj-bg-surface);\n }\n\n .xlsx-viewer__grid {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n .xlsx-viewer__grid ag-grid-angular {\n height: 100%;\n width: 100%;\n display: block;\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'XlsxArtifactViewerPlugin')\nexport class XlsxArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n public isLoading = true;\n public isDownloading = false;\n public errorMessage = '';\n public sheets: SheetData[] = [];\n public activeSheetIndex = 0;\n public defaultColDef: ColDef = { resizable: true, sortable: true, filter: true, minWidth: 80 };\n\n private gridApi: GridApi | null = null;\n private downloadUrl = '';\n\n constructor(\n private fileService: ArtifactFileService,\n private cdr: ChangeDetectorRef,\n ) {\n super();\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n public get activeSheet(): SheetData | null {\n return this.sheets[this.activeSheetIndex] ?? null;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadWorkbook();\n }\n\n public onGridReady(event: GridReadyEvent): void {\n this.gridApi = event.api;\n this.gridApi.sizeColumnsToFit();\n }\n\n public selectSheet(index: number): void {\n this.activeSheetIndex = index;\n this.cdr.markForCheck();\n // Let Angular render the new rowData/columnDefs before re-sizing\n setTimeout(() => this.gridApi?.sizeColumnsToFit(), 0);\n }\n\n public async onDownload(): Promise<void> {\n if (!this.downloadUrl || this.isDownloading) {\n return;\n }\n this.isDownloading = true;\n this.cdr.markForCheck();\n try {\n await this.triggerBrowserDownload(this.downloadUrl, this.artifactVersion?.FileName || 'workbook.xlsx');\n } finally {\n this.isDownloading = false;\n this.cdr.markForCheck();\n }\n }\n\n // ─── Private helpers ────────────────────────────────────────────────────────\n\n private async loadWorkbook(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n this.showError('No artifact version provided.');\n return;\n }\n\n try {\n let arrayBuffer: ArrayBuffer;\n\n if (this.artifactVersion.ContentMode === 'File') {\n // File-backed: download from storage via pre-auth URL\n this.downloadUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n arrayBuffer = await this.fetchAsArrayBuffer(this.downloadUrl);\n } else {\n // Inline: content is a base64 data URL stored in the artifact version\n const content = this.artifactVersion.Content;\n if (!content) {\n this.showError('Artifact has no content.');\n return;\n }\n arrayBuffer = this.fileService.dataUrlToArrayBuffer(content);\n // Create an object URL for download support\n this.downloadUrl = this.fileService.dataUrlToObjectUrl(\n content,\n this.artifactVersion.MimeType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n );\n }\n\n const XLSX = (await import('xlsx')) as unknown as XlsxModuleShim;\n const workbook = XLSX.read(arrayBuffer, { type: 'array' });\n this.sheets = this.parseWorkbook(workbook, XLSX);\n this.isLoading = false;\n this.cdr.markForCheck();\n } catch (err) {\n this.showError(`Could not load workbook: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n private parseWorkbook(workbook: WorkbookType, XLSX: XlsxModuleShim): SheetData[] {\n return workbook.SheetNames.map((name) => {\n const sheet = workbook.Sheets[name];\n const rows = XLSX.utils.sheet_to_json<Record<string, string | number | boolean | null>>(sheet, {\n defval: null,\n raw: false, // Format dates/numbers as strings so AG Grid can display them\n });\n\n const headers = rows.length > 0 ? Object.keys(rows[0]) : [];\n const columnDefs: ColDef[] = headers.map((h) => ({\n field: h,\n headerName: h,\n tooltipField: h,\n }));\n\n return { name, rowData: rows, columnDefs };\n });\n }\n\n private async fetchAsArrayBuffer(url: string): Promise<ArrayBuffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching file`);\n }\n return response.arrayBuffer();\n }\n\n private showError(message: string): void {\n this.isLoading = false;\n this.errorMessage = message;\n this.cdr.markForCheck();\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n if (this.sheets.length === 0) return null;\n\n // Convert parsed sheets into DataTables for structured snapshot\n const tables: DataTable[] = this.sheets.map((sheet) => {\n const table = new DataTable();\n table.name = sheet.name;\n table.source = 'static';\n table.columns = sheet.columnDefs\n .filter((col) => col.field)\n .map((col) => {\n const desc = new MJColumnDescriptor(col.field as string);\n desc.displayName = (col.headerName as string | undefined) ?? (col.field as string);\n desc.sqlBaseType = 'nvarchar';\n return desc;\n });\n table.rows = sheet.rowData;\n table.metadata = { rowCount: sheet.rowData.length };\n return table;\n });\n\n const snap = DataSnapshot.FromTables(tables, this.getDisplayTitle() ?? undefined);\n snap.activeTab = this.sheets[this.activeSheetIndex]?.name;\n return snap;\n }\n}\n\n// ─── Minimal type shims for xlsx dynamic import ────────────────────────────────\n\ninterface WorkbookType {\n SheetNames: string[];\n Sheets: Record<string, unknown>;\n}\n\ninterface XlsxModuleShim {\n read(data: ArrayBuffer, opts: { type: 'array' | 'buffer' | 'binary' | 'base64' | 'string' }): WorkbookType;\n utils: {\n sheet_to_json<T>(sheet: unknown, opts: { defval: null; raw: boolean }): T[];\n };\n}\n"]}
@@ -0,0 +1,77 @@
1
+ import { DataSnapshot, UserInfo } from '@memberjunction/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Arguments for {@link AnalyzeArtifactService.StartAnalysisConversation}.
5
+ */
6
+ export interface StartAnalysisConversationArgs {
7
+ /** The DataSnapshot captured from the source artifact's GetCurrentStateSnapshot(). */
8
+ snapshot: DataSnapshot;
9
+ /** Context user for all entity saves. */
10
+ currentUser: UserInfo;
11
+ /** Environment the new conversation and artifact belong to. */
12
+ environmentId: string;
13
+ /** Optional title override. Defaults to snapshot.title or 'Untitled Snapshot'. */
14
+ title?: string;
15
+ /** Optional initial user message text. Defaults to 'Analyze "<title>"'. */
16
+ initialMessage?: string;
17
+ }
18
+ /**
19
+ * Arguments for {@link AnalyzeArtifactService.CreateSnapshotArtifact}.
20
+ * Creates just the Artifact + ArtifactVersion — no conversation, no junction.
21
+ * Used by callers who already have a conversation and just want to persist
22
+ * the snapshot and link it to a specific user message themselves.
23
+ */
24
+ export interface CreateSnapshotArtifactArgs {
25
+ snapshot: DataSnapshot;
26
+ currentUser: UserInfo;
27
+ environmentId: string;
28
+ title?: string;
29
+ }
30
+ /**
31
+ * Result of {@link AnalyzeArtifactService.CreateSnapshotArtifact}.
32
+ */
33
+ export interface CreateSnapshotArtifactResult {
34
+ artifactId: string;
35
+ artifactVersionId: string;
36
+ title: string;
37
+ }
38
+ /**
39
+ * Result of {@link AnalyzeArtifactService.StartAnalysisConversation}.
40
+ */
41
+ export interface AnalyzeArtifactResult {
42
+ conversationId: string;
43
+ conversationDetailId: string;
44
+ artifactId: string;
45
+ artifactVersionId: string;
46
+ }
47
+ /**
48
+ * Plumbing for the standalone "Analyze" flow (unified data layer plan §8.8).
49
+ *
50
+ * Given a captured {@link DataSnapshot} from any artifact viewer, creates a
51
+ * fresh "Data Snapshot" artifact containing the snapshot JSON, a new
52
+ * conversation, an initial user message, and a junction linking the artifact
53
+ * version as `Direction='Input'` on that message. Agent kickoff and navigation
54
+ * are the caller's responsibility.
55
+ *
56
+ * Consumers subscribe to `(analyzeRequested)` on `<mj-artifact-viewer-panel>`,
57
+ * call `StartAnalysisConversation`, then route the user to the returned
58
+ * `conversationId`.
59
+ */
60
+ export declare class AnalyzeArtifactService {
61
+ /**
62
+ * Creates ONLY the Artifact + ArtifactVersion for a captured snapshot.
63
+ * Does not create a conversation or any junctions. Used by callers who
64
+ * already have a conversation and want to attach the snapshot to a
65
+ * message they're about to send (e.g., in-conversation Analyze flow).
66
+ */
67
+ CreateSnapshotArtifact(args: CreateSnapshotArtifactArgs): Promise<CreateSnapshotArtifactResult>;
68
+ /**
69
+ * Create a new analysis conversation seeded with the captured snapshot.
70
+ * Performs six sequential saves; throws with the underlying entity error
71
+ * message on any failure.
72
+ */
73
+ StartAnalysisConversation(args: StartAnalysisConversationArgs): Promise<AnalyzeArtifactResult>;
74
+ static ɵfac: i0.ɵɵFactoryDeclaration<AnalyzeArtifactService, never>;
75
+ static ɵprov: i0.ɵɵInjectableDeclaration<AnalyzeArtifactService>;
76
+ }
77
+ //# sourceMappingURL=analyze-artifact.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-artifact.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/analyze-artifact.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAuB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;;AAUnF;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,sFAAsF;IACtF,QAAQ,EAAE,YAAY,CAAC;IACvB,yCAAyC;IACzC,WAAW,EAAE,QAAQ,CAAC;IACtB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,QAAQ,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,qBACa,sBAAsB;IACjC;;;;;OAKG;IACG,sBAAsB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,4BAA4B,CAAC;IA+CrG;;;;OAIG;IACG,yBAAyB,CAAC,IAAI,EAAE,6BAA6B,GAAG,OAAO,CAAC,qBAAqB,CAAC;yCA3DzF,sBAAsB;6CAAtB,sBAAsB;CAgHlC"}
@@ -0,0 +1,120 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { LogStatus, Metadata } from '@memberjunction/core';
3
+ import { ArtifactMetadataEngine, } from '@memberjunction/core-entities';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Plumbing for the standalone "Analyze" flow (unified data layer plan §8.8).
7
+ *
8
+ * Given a captured {@link DataSnapshot} from any artifact viewer, creates a
9
+ * fresh "Data Snapshot" artifact containing the snapshot JSON, a new
10
+ * conversation, an initial user message, and a junction linking the artifact
11
+ * version as `Direction='Input'` on that message. Agent kickoff and navigation
12
+ * are the caller's responsibility.
13
+ *
14
+ * Consumers subscribe to `(analyzeRequested)` on `<mj-artifact-viewer-panel>`,
15
+ * call `StartAnalysisConversation`, then route the user to the returned
16
+ * `conversationId`.
17
+ */
18
+ export class AnalyzeArtifactService {
19
+ /**
20
+ * Creates ONLY the Artifact + ArtifactVersion for a captured snapshot.
21
+ * Does not create a conversation or any junctions. Used by callers who
22
+ * already have a conversation and want to attach the snapshot to a
23
+ * message they're about to send (e.g., in-conversation Analyze flow).
24
+ */
25
+ async CreateSnapshotArtifact(args) {
26
+ const { snapshot, currentUser, environmentId } = args;
27
+ const title = args.title || snapshot.title || 'Untitled Snapshot';
28
+ // Resolve the "Data Snapshot" artifact type.
29
+ const engine = ArtifactMetadataEngine.Instance;
30
+ await engine.Config(false, currentUser);
31
+ let snapshotType = engine.FindArtifactType('Data Snapshot');
32
+ if (!snapshotType) {
33
+ await engine.Config(true, currentUser);
34
+ snapshotType = engine.FindArtifactType('Data Snapshot');
35
+ }
36
+ if (!snapshotType) {
37
+ throw new Error('AnalyzeArtifactService: "Data Snapshot" artifact type not found. Ensure metadata has been pushed.');
38
+ }
39
+ const md = new Metadata();
40
+ const artifact = await md.GetEntityObject('MJ: Artifacts', currentUser);
41
+ artifact.Name = title;
42
+ artifact.Description = `Snapshot captured for analysis at ${new Date().toISOString()}`;
43
+ artifact.TypeID = snapshotType.ID;
44
+ artifact.UserID = currentUser.ID;
45
+ artifact.EnvironmentID = environmentId;
46
+ if (!(await artifact.Save())) {
47
+ throw new Error(`Failed to save artifact: ${artifact.LatestResult?.CompleteMessage ?? 'unknown error'}`);
48
+ }
49
+ const version = await md.GetEntityObject('MJ: Artifact Versions', currentUser);
50
+ version.ArtifactID = artifact.ID;
51
+ version.VersionNumber = 1;
52
+ version.Content = JSON.stringify(snapshot);
53
+ version.UserID = currentUser.ID;
54
+ version.Name = title;
55
+ if (!(await version.Save())) {
56
+ throw new Error(`Failed to save artifact version: ${version.LatestResult?.CompleteMessage ?? 'unknown error'}`);
57
+ }
58
+ return {
59
+ artifactId: artifact.ID,
60
+ artifactVersionId: version.ID,
61
+ title,
62
+ };
63
+ }
64
+ /**
65
+ * Create a new analysis conversation seeded with the captured snapshot.
66
+ * Performs six sequential saves; throws with the underlying entity error
67
+ * message on any failure.
68
+ */
69
+ async StartAnalysisConversation(args) {
70
+ const { snapshot, currentUser, environmentId } = args;
71
+ const title = args.title || snapshot.title || 'Untitled Snapshot';
72
+ const initialMessage = args.initialMessage || `Analyze "${title}"`;
73
+ // Steps 1-3: Create the Data Snapshot artifact + version (shared with CreateSnapshotArtifact)
74
+ const { artifactId, artifactVersionId } = await this.CreateSnapshotArtifact({
75
+ snapshot,
76
+ currentUser,
77
+ environmentId,
78
+ title,
79
+ });
80
+ const md = new Metadata();
81
+ // 4. Create the conversation
82
+ const conversation = await md.GetEntityObject('MJ: Conversations', currentUser);
83
+ conversation.Name = `Analyze: ${title}`;
84
+ conversation.UserID = currentUser.ID;
85
+ conversation.EnvironmentID = environmentId;
86
+ if (!(await conversation.Save())) {
87
+ throw new Error(`Failed to save conversation: ${conversation.LatestResult?.CompleteMessage ?? 'unknown error'}`);
88
+ }
89
+ // 5. Seed the initial user message
90
+ const detail = await md.GetEntityObject('MJ: Conversation Details', currentUser);
91
+ detail.ConversationID = conversation.ID;
92
+ detail.Role = 'User';
93
+ detail.Message = initialMessage;
94
+ if (!(await detail.Save())) {
95
+ throw new Error(`Failed to save conversation detail: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`);
96
+ }
97
+ // 6. Link the snapshot as an input artifact on that message
98
+ const junction = await md.GetEntityObject('MJ: Conversation Detail Artifacts', currentUser);
99
+ junction.ConversationDetailID = detail.ID;
100
+ junction.ArtifactVersionID = artifactVersionId;
101
+ junction.Direction = 'Input';
102
+ if (!(await junction.Save())) {
103
+ throw new Error(`Failed to link artifact to conversation: ${junction.LatestResult?.CompleteMessage ?? 'unknown error'}`);
104
+ }
105
+ LogStatus(`[AnalyzeArtifactService] Created conversation ${conversation.ID} with input artifact ${artifactId} v1`);
106
+ return {
107
+ conversationId: conversation.ID,
108
+ conversationDetailId: detail.ID,
109
+ artifactId,
110
+ artifactVersionId,
111
+ };
112
+ }
113
+ static ɵfac = function AnalyzeArtifactService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnalyzeArtifactService)(); };
114
+ static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: AnalyzeArtifactService, factory: AnalyzeArtifactService.ɵfac, providedIn: 'root' });
115
+ }
116
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AnalyzeArtifactService, [{
117
+ type: Injectable,
118
+ args: [{ providedIn: 'root' }]
119
+ }], null, null); })();
120
+ //# sourceMappingURL=analyze-artifact.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-artifact.service.js","sourceRoot":"","sources":["../../../src/lib/services/analyze-artifact.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { DataSnapshot, LogStatus, Metadata, UserInfo } from '@memberjunction/core';\nimport {\n ArtifactMetadataEngine,\n MJArtifactEntity,\n MJArtifactVersionEntity,\n MJConversationEntity,\n MJConversationDetailEntity,\n MJConversationDetailArtifactEntity,\n} from '@memberjunction/core-entities';\n\n/**\n * Arguments for {@link AnalyzeArtifactService.StartAnalysisConversation}.\n */\nexport interface StartAnalysisConversationArgs {\n /** The DataSnapshot captured from the source artifact's GetCurrentStateSnapshot(). */\n snapshot: DataSnapshot;\n /** Context user for all entity saves. */\n currentUser: UserInfo;\n /** Environment the new conversation and artifact belong to. */\n environmentId: string;\n /** Optional title override. Defaults to snapshot.title or 'Untitled Snapshot'. */\n title?: string;\n /** Optional initial user message text. Defaults to 'Analyze \"<title>\"'. */\n initialMessage?: string;\n}\n\n/**\n * Arguments for {@link AnalyzeArtifactService.CreateSnapshotArtifact}.\n * Creates just the Artifact + ArtifactVersion — no conversation, no junction.\n * Used by callers who already have a conversation and just want to persist\n * the snapshot and link it to a specific user message themselves.\n */\nexport interface CreateSnapshotArtifactArgs {\n snapshot: DataSnapshot;\n currentUser: UserInfo;\n environmentId: string;\n title?: string;\n}\n\n/**\n * Result of {@link AnalyzeArtifactService.CreateSnapshotArtifact}.\n */\nexport interface CreateSnapshotArtifactResult {\n artifactId: string;\n artifactVersionId: string;\n title: string;\n}\n\n/**\n * Result of {@link AnalyzeArtifactService.StartAnalysisConversation}.\n */\nexport interface AnalyzeArtifactResult {\n conversationId: string;\n conversationDetailId: string;\n artifactId: string;\n artifactVersionId: string;\n}\n\n/**\n * Plumbing for the standalone \"Analyze\" flow (unified data layer plan §8.8).\n *\n * Given a captured {@link DataSnapshot} from any artifact viewer, creates a\n * fresh \"Data Snapshot\" artifact containing the snapshot JSON, a new\n * conversation, an initial user message, and a junction linking the artifact\n * version as `Direction='Input'` on that message. Agent kickoff and navigation\n * are the caller's responsibility.\n *\n * Consumers subscribe to `(analyzeRequested)` on `<mj-artifact-viewer-panel>`,\n * call `StartAnalysisConversation`, then route the user to the returned\n * `conversationId`.\n */\n@Injectable({ providedIn: 'root' })\nexport class AnalyzeArtifactService {\n /**\n * Creates ONLY the Artifact + ArtifactVersion for a captured snapshot.\n * Does not create a conversation or any junctions. Used by callers who\n * already have a conversation and want to attach the snapshot to a\n * message they're about to send (e.g., in-conversation Analyze flow).\n */\n async CreateSnapshotArtifact(args: CreateSnapshotArtifactArgs): Promise<CreateSnapshotArtifactResult> {\n const { snapshot, currentUser, environmentId } = args;\n const title = args.title || snapshot.title || 'Untitled Snapshot';\n\n // Resolve the \"Data Snapshot\" artifact type.\n const engine = ArtifactMetadataEngine.Instance;\n await engine.Config(false, currentUser);\n let snapshotType = engine.FindArtifactType('Data Snapshot');\n if (!snapshotType) {\n await engine.Config(true, currentUser);\n snapshotType = engine.FindArtifactType('Data Snapshot');\n }\n if (!snapshotType) {\n throw new Error(\n 'AnalyzeArtifactService: \"Data Snapshot\" artifact type not found. Ensure metadata has been pushed.',\n );\n }\n\n const md = new Metadata();\n\n const artifact = await md.GetEntityObject<MJArtifactEntity>('MJ: Artifacts', currentUser);\n artifact.Name = title;\n artifact.Description = `Snapshot captured for analysis at ${new Date().toISOString()}`;\n artifact.TypeID = snapshotType.ID;\n artifact.UserID = currentUser.ID;\n artifact.EnvironmentID = environmentId;\n if (!(await artifact.Save())) {\n throw new Error(`Failed to save artifact: ${artifact.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n\n const version = await md.GetEntityObject<MJArtifactVersionEntity>('MJ: Artifact Versions', currentUser);\n version.ArtifactID = artifact.ID;\n version.VersionNumber = 1;\n version.Content = JSON.stringify(snapshot);\n version.UserID = currentUser.ID;\n version.Name = title;\n if (!(await version.Save())) {\n throw new Error(`Failed to save artifact version: ${version.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n\n return {\n artifactId: artifact.ID,\n artifactVersionId: version.ID,\n title,\n };\n }\n\n /**\n * Create a new analysis conversation seeded with the captured snapshot.\n * Performs six sequential saves; throws with the underlying entity error\n * message on any failure.\n */\n async StartAnalysisConversation(args: StartAnalysisConversationArgs): Promise<AnalyzeArtifactResult> {\n const { snapshot, currentUser, environmentId } = args;\n const title = args.title || snapshot.title || 'Untitled Snapshot';\n const initialMessage = args.initialMessage || `Analyze \"${title}\"`;\n\n // Steps 1-3: Create the Data Snapshot artifact + version (shared with CreateSnapshotArtifact)\n const { artifactId, artifactVersionId } = await this.CreateSnapshotArtifact({\n snapshot,\n currentUser,\n environmentId,\n title,\n });\n\n const md = new Metadata();\n\n // 4. Create the conversation\n const conversation = await md.GetEntityObject<MJConversationEntity>('MJ: Conversations', currentUser);\n conversation.Name = `Analyze: ${title}`;\n conversation.UserID = currentUser.ID;\n conversation.EnvironmentID = environmentId;\n if (!(await conversation.Save())) {\n throw new Error(`Failed to save conversation: ${conversation.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n\n // 5. Seed the initial user message\n const detail = await md.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', currentUser);\n detail.ConversationID = conversation.ID;\n detail.Role = 'User';\n detail.Message = initialMessage;\n if (!(await detail.Save())) {\n throw new Error(`Failed to save conversation detail: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n\n // 6. Link the snapshot as an input artifact on that message\n const junction = await md.GetEntityObject<MJConversationDetailArtifactEntity>('MJ: Conversation Detail Artifacts', currentUser);\n junction.ConversationDetailID = detail.ID;\n junction.ArtifactVersionID = artifactVersionId;\n junction.Direction = 'Input';\n if (!(await junction.Save())) {\n throw new Error(`Failed to link artifact to conversation: ${junction.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n\n LogStatus(\n `[AnalyzeArtifactService] Created conversation ${conversation.ID} with input artifact ${artifactId} v1`,\n );\n\n return {\n conversationId: conversation.ID,\n conversationDetailId: detail.ID,\n artifactId,\n artifactVersionId,\n };\n }\n}\n"]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pure helper functions for creating DataSnapshots from artifact content.
3
+ *
4
+ * These are extracted from Angular viewer components so the logic can be
5
+ * unit-tested without Angular TestBed. Each viewer plugin delegates to
6
+ * the corresponding function here.
7
+ */
8
+ import { DataSnapshot, DataTable } from '@memberjunction/core';
9
+ /**
10
+ * Shape of a DataArtifactSpec that the data viewer works with.
11
+ * Only the fields relevant to snapshot creation are required.
12
+ */
13
+ interface DataArtifactSpecLike {
14
+ title?: string;
15
+ columns?: {
16
+ field: string;
17
+ headerName?: string;
18
+ sqlBaseType?: string;
19
+ }[];
20
+ rows?: Record<string, unknown>[];
21
+ }
22
+ /**
23
+ * Create a DataSnapshot from JSON artifact content.
24
+ * Parses the JSON, counts top-level keys, and stores the parsed value in custom.
25
+ */
26
+ export declare function createJsonSnapshot(content: string | null, title: string | null): DataSnapshot | null;
27
+ /**
28
+ * Create a DataSnapshot from code artifact content.
29
+ * Counts lines and stores content plus lineCount in custom.
30
+ */
31
+ export declare function createCodeSnapshot(content: string | null, title: string | null): DataSnapshot | null;
32
+ /**
33
+ * Create a DataSnapshot from markdown artifact content.
34
+ * Stores the raw content in custom.
35
+ */
36
+ export declare function createMarkdownSnapshot(content: string | null, title: string | null): DataSnapshot | null;
37
+ /**
38
+ * Create a DataSnapshot from a DataArtifactSpec (data viewer).
39
+ * Uses NormalizeToTables to convert the spec into a tabular snapshot.
40
+ */
41
+ /**
42
+ * Build a combined SQL string from multiple tables, each with a header comment.
43
+ * Returns null if no tables have SQL.
44
+ */
45
+ export declare function buildMultiTableSql(tables: DataTable[]): string | null;
46
+ export declare function createDataSnapshot(spec: DataArtifactSpecLike | null): DataSnapshot | null;
47
+ export {};
48
+ //# sourceMappingURL=snapshot-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/snapshot-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAqB,MAAM,sBAAsB,CAAC;AAElF;;;GAGG;AACH,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAcpG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAQpG;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAMxG;AAED;;;GAGG;AACH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CAMrE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAKzF"}