@memberjunction/ng-artifacts 2.112.0 → 2.113.1
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.
- package/dist/lib/components/artifact-message-card.component.d.ts +1 -1
- package/dist/lib/components/artifact-message-card.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-message-card.component.js +6 -22
- package/dist/lib/components/artifact-message-card.component.js.map +1 -1
- package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-type-plugin-viewer.component.js +5 -4
- package/dist/lib/components/artifact-type-plugin-viewer.component.js.map +1 -1
- package/dist/lib/components/artifact-version-history.component.d.ts +1 -1
- package/dist/lib/components/artifact-version-history.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-version-history.component.js +4 -4
- package/dist/lib/components/artifact-version-history.component.js.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.d.ts +19 -1
- package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.js +197 -111
- package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
- package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/json-artifact-viewer.component.js +9 -12
- package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
- package/package.json +8 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, ViewChild, SecurityContext
|
|
2
|
-
import { Metadata, RunView, LogError } from '@memberjunction/
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewChild, SecurityContext } from '@angular/core';
|
|
2
|
+
import { Metadata, RunView, LogError } from '@memberjunction/core';
|
|
3
3
|
import { ParseJSONRecursive } from '@memberjunction/global';
|
|
4
|
-
import { ArtifactMetadataEngine
|
|
4
|
+
import { ArtifactMetadataEngine } from '@memberjunction/core-entities';
|
|
5
5
|
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
6
6
|
import { Subject } from 'rxjs';
|
|
7
7
|
import { takeUntil } from 'rxjs/operators';
|
|
@@ -78,7 +78,7 @@ function ArtifactViewerPanelComponent_Conditional_14_Template(rf, ctx) { if (rf
|
|
|
78
78
|
} if (rf & 2) {
|
|
79
79
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
80
80
|
i0.ɵɵclassProp("in-collection", ctx_r0.isInCollection);
|
|
81
|
-
i0.ɵɵproperty("title", ctx_r0.isInCollection ? "
|
|
81
|
+
i0.ɵɵproperty("title", ctx_r0.isInCollection ? "Current version saved to " + ctx_r0.currentVersionCollections.length + " collection(s)" : "Save to Collection");
|
|
82
82
|
i0.ɵɵadvance();
|
|
83
83
|
i0.ɵɵclassMap(ctx_r0.isInCollection ? "fas fa-bookmark" : "far fa-bookmark");
|
|
84
84
|
} }
|
|
@@ -246,40 +246,41 @@ function ArtifactViewerPanelComponent_Conditional_21_Conditional_33_Template(rf,
|
|
|
246
246
|
i0.ɵɵrepeater(ctx_r0.filteredAttributes);
|
|
247
247
|
} }
|
|
248
248
|
function ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
249
|
-
i0.ɵɵelement(0, "i",
|
|
249
|
+
i0.ɵɵelement(0, "i", 62);
|
|
250
250
|
} }
|
|
251
251
|
function ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
252
|
-
i0.ɵɵelement(0, "i",
|
|
252
|
+
i0.ɵɵelement(0, "i", 63);
|
|
253
253
|
} }
|
|
254
254
|
function ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
255
255
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
256
|
-
i0.ɵɵelementStart(0, "div",
|
|
257
|
-
i0.ɵɵ
|
|
256
|
+
i0.ɵɵelementStart(0, "div", 60);
|
|
257
|
+
i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Template_div_click_0_listener() { const link_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(link_r12.hasAccess ? ctx_r0.onNavigateToLink(link_r12) : null); });
|
|
258
|
+
i0.ɵɵelementStart(1, "div", 61);
|
|
259
|
+
i0.ɵɵtemplate(2, ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Conditional_2_Template, 1, 0, "i", 62)(3, ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Conditional_3_Template, 1, 0, "i", 63);
|
|
258
260
|
i0.ɵɵelementEnd();
|
|
259
|
-
i0.ɵɵelementStart(4, "div",
|
|
261
|
+
i0.ɵɵelementStart(4, "div", 64)(5, "div", 65);
|
|
260
262
|
i0.ɵɵtext(6);
|
|
261
263
|
i0.ɵɵelementEnd();
|
|
262
|
-
i0.ɵɵelementStart(7, "div",
|
|
264
|
+
i0.ɵɵelementStart(7, "div", 66);
|
|
263
265
|
i0.ɵɵtext(8);
|
|
264
266
|
i0.ɵɵelementEnd()();
|
|
265
|
-
i0.ɵɵelementStart(9, "div",
|
|
266
|
-
i0.ɵɵ
|
|
267
|
-
i0.ɵɵ
|
|
268
|
-
i0.ɵɵelementEnd()()();
|
|
267
|
+
i0.ɵɵelementStart(9, "div", 67);
|
|
268
|
+
i0.ɵɵelement(10, "i", 68);
|
|
269
|
+
i0.ɵɵelementEnd()();
|
|
269
270
|
} if (rf & 2) {
|
|
270
271
|
const link_r12 = ctx.$implicit;
|
|
272
|
+
i0.ɵɵclassProp("disabled", !link_r12.hasAccess)("clickable", link_r12.hasAccess);
|
|
273
|
+
i0.ɵɵproperty("title", link_r12.hasAccess ? "Click to open" : "No access");
|
|
271
274
|
i0.ɵɵadvance(2);
|
|
272
275
|
i0.ɵɵconditional(link_r12.type === "conversation" ? 2 : 3);
|
|
273
276
|
i0.ɵɵadvance(4);
|
|
274
277
|
i0.ɵɵtextInterpolate(link_r12.name);
|
|
275
278
|
i0.ɵɵadvance(2);
|
|
276
279
|
i0.ɵɵtextInterpolate(link_r12.type === "conversation" ? "Conversation" : "Collection");
|
|
277
|
-
i0.ɵɵadvance(2);
|
|
278
|
-
i0.ɵɵproperty("disabled", !link_r12.hasAccess)("title", link_r12.hasAccess ? "Open" : "No access");
|
|
279
280
|
} }
|
|
280
281
|
function ArtifactViewerPanelComponent_Conditional_21_Conditional_35_Template(rf, ctx) { if (rf & 1) {
|
|
281
282
|
i0.ɵɵelementStart(0, "div", 42);
|
|
282
|
-
i0.ɵɵrepeaterCreate(1, ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Template,
|
|
283
|
+
i0.ɵɵrepeaterCreate(1, ArtifactViewerPanelComponent_Conditional_21_Conditional_35_For_2_Template, 11, 8, "div", 59, _forTrack1);
|
|
283
284
|
i0.ɵɵelementEnd();
|
|
284
285
|
} if (rf & 2) {
|
|
285
286
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -460,7 +461,8 @@ export class ArtifactViewerPanelComponent {
|
|
|
460
461
|
error = null;
|
|
461
462
|
jsonContent = '';
|
|
462
463
|
showVersionDropdown = false;
|
|
463
|
-
artifactCollections = [];
|
|
464
|
+
artifactCollections = []; // All collections for ALL versions
|
|
465
|
+
currentVersionCollections = []; // Collections containing CURRENT version only
|
|
464
466
|
primaryCollection = null;
|
|
465
467
|
// Tabbed interface
|
|
466
468
|
activeTab = 'display'; // Changed to string to support dynamic tabs
|
|
@@ -472,6 +474,7 @@ export class ArtifactViewerPanelComponent {
|
|
|
472
474
|
originConversation = null;
|
|
473
475
|
allCollections = [];
|
|
474
476
|
hasAccessToOriginConversation = false;
|
|
477
|
+
originConversationVersionId = null; // Version ID that came from origin conversation
|
|
475
478
|
// Dynamic tabs from plugin
|
|
476
479
|
get allTabs() {
|
|
477
480
|
// Start with Display tab (cannot be removed)
|
|
@@ -484,7 +487,7 @@ export class ArtifactViewerPanelComponent {
|
|
|
484
487
|
}
|
|
485
488
|
// Get tabs to remove from plugin (case-insensitive)
|
|
486
489
|
const removals = this.pluginViewer?.pluginInstance?.GetStandardTabRemovals?.() || [];
|
|
487
|
-
const removalsLower = removals.map(
|
|
490
|
+
const removalsLower = removals.map(r => r.toLowerCase());
|
|
488
491
|
// Add standard tabs (unless plugin removed them)
|
|
489
492
|
if (!removalsLower.includes('json')) {
|
|
490
493
|
tabs.push('JSON');
|
|
@@ -492,8 +495,8 @@ export class ArtifactViewerPanelComponent {
|
|
|
492
495
|
if (!removalsLower.includes('details')) {
|
|
493
496
|
tabs.push('Details');
|
|
494
497
|
}
|
|
495
|
-
//
|
|
496
|
-
if (!removalsLower.includes('links')) {
|
|
498
|
+
// Only add Links tab if there are links to show (unless plugin explicitly removes it)
|
|
499
|
+
if (!removalsLower.includes('links') && this.linksToShow.length > 0) {
|
|
497
500
|
tabs.push('Links');
|
|
498
501
|
}
|
|
499
502
|
return tabs;
|
|
@@ -504,11 +507,13 @@ export class ArtifactViewerPanelComponent {
|
|
|
504
507
|
const pluginTabs = this.pluginViewer.pluginInstance.GetAdditionalTabs();
|
|
505
508
|
const pluginTab = pluginTabs.find((t) => t.label.toLowerCase() === tabName.toLowerCase());
|
|
506
509
|
if (pluginTab) {
|
|
507
|
-
const content = typeof pluginTab.content === 'function'
|
|
510
|
+
const content = typeof pluginTab.content === 'function'
|
|
511
|
+
? pluginTab.content()
|
|
512
|
+
: pluginTab.content;
|
|
508
513
|
return {
|
|
509
514
|
type: pluginTab.contentType,
|
|
510
515
|
content: content,
|
|
511
|
-
language: pluginTab.language
|
|
516
|
+
language: pluginTab.language
|
|
512
517
|
};
|
|
513
518
|
}
|
|
514
519
|
}
|
|
@@ -531,7 +536,6 @@ export class ArtifactViewerPanelComponent {
|
|
|
531
536
|
if (this.refreshTrigger) {
|
|
532
537
|
this.refreshTrigger.pipe(takeUntil(this.destroy$)).subscribe(async (data) => {
|
|
533
538
|
if (data.artifactId === this.artifactId) {
|
|
534
|
-
console.log(`📦 Refreshing artifact viewer to version ${data.versionNumber}`);
|
|
535
539
|
// Reload all versions to get any new ones
|
|
536
540
|
await this.loadArtifact(data.versionNumber);
|
|
537
541
|
}
|
|
@@ -539,6 +543,10 @@ export class ArtifactViewerPanelComponent {
|
|
|
539
543
|
}
|
|
540
544
|
// Load artifact with specified version if provided
|
|
541
545
|
await this.loadArtifact(this.versionNumber);
|
|
546
|
+
// Track that user viewed this artifact
|
|
547
|
+
if (this.artifactVersion?.ID && this.currentUser) {
|
|
548
|
+
this.trackArtifactUsage('Viewed');
|
|
549
|
+
}
|
|
542
550
|
}
|
|
543
551
|
async ngOnChanges(changes) {
|
|
544
552
|
// Reload artifact when artifactId changes
|
|
@@ -549,17 +557,19 @@ export class ArtifactViewerPanelComponent {
|
|
|
549
557
|
if (changes['versionNumber'] && !changes['versionNumber'].firstChange) {
|
|
550
558
|
const newVersionNumber = changes['versionNumber'].currentValue;
|
|
551
559
|
if (newVersionNumber != null) {
|
|
552
|
-
console.log(`📦 Version number changed to ${newVersionNumber}, switching version`);
|
|
553
560
|
// Check if we already have this version loaded (avoid reload if possible)
|
|
554
|
-
const targetVersion = this.allVersions.find(
|
|
561
|
+
const targetVersion = this.allVersions.find(v => v.VersionNumber === newVersionNumber);
|
|
555
562
|
if (targetVersion) {
|
|
556
563
|
// Just switch to the version we already have
|
|
557
564
|
this.artifactVersion = targetVersion;
|
|
558
565
|
this.selectedVersionNumber = targetVersion.VersionNumber || 1;
|
|
559
566
|
this.jsonContent = this.FormatJSON(targetVersion.Content || '{}');
|
|
560
|
-
console.log(`📦 Switched to cached version ${this.selectedVersionNumber}`);
|
|
561
567
|
// Load version attributes
|
|
562
568
|
await this.loadVersionAttributes();
|
|
569
|
+
// Reload collection associations for this version
|
|
570
|
+
await this.loadCollectionAssociations();
|
|
571
|
+
// Reload links data
|
|
572
|
+
await this.loadLinksData();
|
|
563
573
|
}
|
|
564
574
|
else {
|
|
565
575
|
// Need to reload to get this version (shouldn't normally happen)
|
|
@@ -576,6 +586,8 @@ export class ArtifactViewerPanelComponent {
|
|
|
576
586
|
try {
|
|
577
587
|
this.isLoading = true;
|
|
578
588
|
this.error = null;
|
|
589
|
+
// Clear links data from previous artifact to prevent stale Links tab
|
|
590
|
+
this.clearLinksData();
|
|
579
591
|
const md = new Metadata();
|
|
580
592
|
// Load artifact
|
|
581
593
|
this.artifact = await md.GetEntityObject('MJ: Artifacts', this.currentUser);
|
|
@@ -592,21 +604,19 @@ export class ArtifactViewerPanelComponent {
|
|
|
592
604
|
EntityName: 'MJ: Artifact Versions',
|
|
593
605
|
ExtraFilter: `ArtifactID='${this.artifactId}'`,
|
|
594
606
|
OrderBy: 'VersionNumber DESC',
|
|
595
|
-
ResultType: 'entity_object'
|
|
607
|
+
ResultType: 'entity_object'
|
|
596
608
|
}, this.currentUser);
|
|
597
609
|
if (result.Success && result.Results && result.Results.length > 0) {
|
|
598
610
|
this.allVersions = result.Results;
|
|
599
611
|
// If target version specified, try to load it
|
|
600
612
|
if (targetVersionNumber) {
|
|
601
|
-
const targetVersion = this.allVersions.find(
|
|
613
|
+
const targetVersion = this.allVersions.find(v => v.VersionNumber === targetVersionNumber);
|
|
602
614
|
if (targetVersion) {
|
|
603
|
-
console.log(`📦 Loading specified version ${targetVersionNumber}`);
|
|
604
615
|
this.artifactVersion = targetVersion;
|
|
605
616
|
this.selectedVersionNumber = targetVersion.VersionNumber || 1;
|
|
606
617
|
this.jsonContent = this.FormatJSON(targetVersion.Content || '{}');
|
|
607
618
|
}
|
|
608
619
|
else {
|
|
609
|
-
console.warn(`📦 Version ${targetVersionNumber} not found, defaulting to latest`);
|
|
610
620
|
// Target version not found, default to latest
|
|
611
621
|
this.artifactVersion = result.Results[0];
|
|
612
622
|
this.selectedVersionNumber = this.artifactVersion.VersionNumber || 1;
|
|
@@ -625,7 +635,6 @@ export class ArtifactViewerPanelComponent {
|
|
|
625
635
|
await this.loadCollectionAssociations();
|
|
626
636
|
// Load links data
|
|
627
637
|
await this.loadLinksData();
|
|
628
|
-
console.log(`📦 Loaded ${this.allVersions.length} versions for artifact ${this.artifactId}, showing v${this.selectedVersionNumber}`);
|
|
629
638
|
}
|
|
630
639
|
else {
|
|
631
640
|
this.error = 'No artifact version found';
|
|
@@ -639,6 +648,15 @@ export class ArtifactViewerPanelComponent {
|
|
|
639
648
|
this.isLoading = false;
|
|
640
649
|
}
|
|
641
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* Clear all links-related data to prevent stale data when switching artifacts
|
|
653
|
+
*/
|
|
654
|
+
clearLinksData() {
|
|
655
|
+
this.allCollections = [];
|
|
656
|
+
this.originConversation = null;
|
|
657
|
+
this.hasAccessToOriginConversation = false;
|
|
658
|
+
this.originConversationVersionId = null;
|
|
659
|
+
}
|
|
642
660
|
async loadArtifactType() {
|
|
643
661
|
if (!this.artifact?.Type) {
|
|
644
662
|
return;
|
|
@@ -649,7 +667,6 @@ export class ArtifactViewerPanelComponent {
|
|
|
649
667
|
if (artifactType) {
|
|
650
668
|
// Resolve DriverClass by traversing parent hierarchy if needed
|
|
651
669
|
this.artifactTypeDriverClass = await this.resolveDriverClassForType(artifactType);
|
|
652
|
-
console.log(`📦 Loaded artifact type "${this.artifact.Type}", DriverClass: ${this.artifactTypeDriverClass || 'none'}`);
|
|
653
670
|
}
|
|
654
671
|
}
|
|
655
672
|
catch (err) {
|
|
@@ -665,13 +682,13 @@ export class ArtifactViewerPanelComponent {
|
|
|
665
682
|
const result = await rv.RunView({
|
|
666
683
|
EntityName: 'MJ: Artifact Version Attributes',
|
|
667
684
|
ExtraFilter: `ArtifactVersionID='${this.artifactVersion.ID}'`,
|
|
668
|
-
ResultType: 'entity_object'
|
|
685
|
+
ResultType: 'entity_object'
|
|
669
686
|
}, this.currentUser);
|
|
670
687
|
if (result.Success && result.Results) {
|
|
671
688
|
this.versionAttributes = result.Results;
|
|
672
689
|
// Check for displayMarkdown or displayHtml attributes
|
|
673
|
-
const displayMarkdownAttr = this.versionAttributes.find(
|
|
674
|
-
const displayHtmlAttr = this.versionAttributes.find(
|
|
690
|
+
const displayMarkdownAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displaymarkdown');
|
|
691
|
+
const displayHtmlAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displayhtml');
|
|
675
692
|
// Parse values - they might be JSON-encoded strings
|
|
676
693
|
this.displayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);
|
|
677
694
|
this.displayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);
|
|
@@ -690,7 +707,6 @@ export class ArtifactViewerPanelComponent {
|
|
|
690
707
|
else {
|
|
691
708
|
this.activeTab = 'details';
|
|
692
709
|
}
|
|
693
|
-
console.log(`📦 Loaded ${this.versionAttributes.length} attributes, displayMarkdown=${!!this.displayMarkdown}, displayHtml=${!!this.displayHtml}, hasDisplayTab=${this.hasDisplayTab}, activeTab=${this.activeTab}`);
|
|
694
710
|
}
|
|
695
711
|
}
|
|
696
712
|
catch (err) {
|
|
@@ -730,12 +746,12 @@ export class ArtifactViewerPanelComponent {
|
|
|
730
746
|
}
|
|
731
747
|
get contentType() {
|
|
732
748
|
// Try to get content type from artifact type or attributes
|
|
733
|
-
const contentTypeAttr = this.versionAttributes.find(
|
|
749
|
+
const contentTypeAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'contenttype');
|
|
734
750
|
return contentTypeAttr?.Value || undefined;
|
|
735
751
|
}
|
|
736
752
|
get filteredAttributes() {
|
|
737
753
|
// Filter out displayMarkdown and displayHtml as they're shown in the Display tab
|
|
738
|
-
return this.versionAttributes.filter(
|
|
754
|
+
return this.versionAttributes.filter(attr => {
|
|
739
755
|
const name = attr.Name?.toLowerCase();
|
|
740
756
|
return name !== 'displaymarkdown' && name !== 'displayhtml';
|
|
741
757
|
});
|
|
@@ -779,20 +795,35 @@ export class ArtifactViewerPanelComponent {
|
|
|
779
795
|
return;
|
|
780
796
|
try {
|
|
781
797
|
const rv = new RunView();
|
|
798
|
+
// Load ALL collection associations for ALL versions of this artifact
|
|
782
799
|
const result = await rv.RunView({
|
|
783
800
|
EntityName: 'MJ: Collection Artifacts',
|
|
784
|
-
ExtraFilter: `
|
|
785
|
-
|
|
801
|
+
ExtraFilter: `ArtifactVersionID IN (
|
|
802
|
+
SELECT ID FROM [__mj].[vwArtifactVersions] WHERE ArtifactID='${this.artifactId}'
|
|
803
|
+
)`,
|
|
804
|
+
ResultType: 'entity_object'
|
|
786
805
|
}, this.currentUser);
|
|
787
806
|
if (result.Success && result.Results) {
|
|
788
807
|
this.artifactCollections = result.Results;
|
|
808
|
+
// Filter to get only collections containing the CURRENT version
|
|
809
|
+
const currentVersionId = this.artifactVersion?.ID;
|
|
810
|
+
if (currentVersionId) {
|
|
811
|
+
// Type-safe comparison: ensure both IDs are strings and match exactly
|
|
812
|
+
const currentIdStr = String(currentVersionId).toLowerCase();
|
|
813
|
+
this.currentVersionCollections = result.Results.filter(ca => {
|
|
814
|
+
const versionIdStr = String(ca.ArtifactVersionID || '').toLowerCase();
|
|
815
|
+
return versionIdStr && currentIdStr && versionIdStr === currentIdStr;
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
this.currentVersionCollections = [];
|
|
820
|
+
}
|
|
789
821
|
// Load the primary collection details if exists
|
|
790
822
|
if (this.artifactCollections.length > 0) {
|
|
791
823
|
const collectionId = this.artifactCollections[0].CollectionID;
|
|
792
824
|
const md = new Metadata();
|
|
793
825
|
this.primaryCollection = await md.GetEntityObject('MJ: Collections', this.currentUser);
|
|
794
826
|
await this.primaryCollection.Load(collectionId);
|
|
795
|
-
console.log(`📦 Artifact is in ${this.artifactCollections.length} collection(s)`);
|
|
796
827
|
}
|
|
797
828
|
else {
|
|
798
829
|
this.primaryCollection = null;
|
|
@@ -804,7 +835,14 @@ export class ArtifactViewerPanelComponent {
|
|
|
804
835
|
}
|
|
805
836
|
}
|
|
806
837
|
get isInCollection() {
|
|
807
|
-
return this.
|
|
838
|
+
return this.currentVersionCollections.length > 0;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Get collection IDs that already contain the current version
|
|
842
|
+
* Used to exclude them from the save picker
|
|
843
|
+
*/
|
|
844
|
+
get currentVersionCollectionIds() {
|
|
845
|
+
return this.currentVersionCollections.map(ca => ca.CollectionID);
|
|
808
846
|
}
|
|
809
847
|
onCopyToClipboard() {
|
|
810
848
|
// Get content from the currently active tab instead of always copying jsonContent
|
|
@@ -820,12 +858,7 @@ export class ArtifactViewerPanelComponent {
|
|
|
820
858
|
onCopyDisplayContent() {
|
|
821
859
|
const content = this.displayHtml || this.displayMarkdown;
|
|
822
860
|
if (content) {
|
|
823
|
-
navigator.clipboard
|
|
824
|
-
.writeText(content)
|
|
825
|
-
.then(() => {
|
|
826
|
-
console.log('✅ Copied display content to clipboard');
|
|
827
|
-
})
|
|
828
|
-
.catch((err) => {
|
|
861
|
+
navigator.clipboard.writeText(content).catch(err => {
|
|
829
862
|
console.error('Failed to copy to clipboard:', err);
|
|
830
863
|
});
|
|
831
864
|
}
|
|
@@ -886,18 +919,27 @@ export class ArtifactViewerPanelComponent {
|
|
|
886
919
|
this.showVersionDropdown = false;
|
|
887
920
|
// Load attributes for the selected version
|
|
888
921
|
await this.loadVersionAttributes();
|
|
922
|
+
// CRITICAL FIX: Reload collection associations for this version
|
|
923
|
+
// This ensures bookmark button and Links tab reflect the correct state
|
|
924
|
+
await this.loadCollectionAssociations();
|
|
925
|
+
// Also reload links data to update conversation/collection links
|
|
926
|
+
await this.loadLinksData();
|
|
889
927
|
}
|
|
890
928
|
async onSaveToLibrary() {
|
|
891
929
|
// Always show the collection picker modal
|
|
892
930
|
// Artifacts can be saved to multiple collections
|
|
893
931
|
this.saveToCollectionRequested.emit({
|
|
894
932
|
artifactId: this.artifactId,
|
|
895
|
-
excludedCollectionIds: this.excludedCollectionIds
|
|
933
|
+
excludedCollectionIds: this.excludedCollectionIds
|
|
896
934
|
});
|
|
897
935
|
}
|
|
898
936
|
get excludedCollectionIds() {
|
|
899
|
-
// Return IDs of collections that already contain
|
|
900
|
-
|
|
937
|
+
// Return IDs of collections that already contain the CURRENT VERSION
|
|
938
|
+
// This allows saving different versions to the same collection
|
|
939
|
+
const excluded = this.currentVersionCollections
|
|
940
|
+
.filter(ca => ca.CollectionID)
|
|
941
|
+
.map(ca => String(ca.CollectionID));
|
|
942
|
+
return excluded;
|
|
901
943
|
}
|
|
902
944
|
/**
|
|
903
945
|
* Called by parent component after user selects collections in the picker.
|
|
@@ -910,34 +952,39 @@ export class ArtifactViewerPanelComponent {
|
|
|
910
952
|
try {
|
|
911
953
|
const md = new Metadata();
|
|
912
954
|
let successCount = 0;
|
|
913
|
-
//
|
|
955
|
+
// Get current version ID - save the version being viewed
|
|
956
|
+
const currentVersionId = this.artifactVersion?.ID;
|
|
957
|
+
if (!currentVersionId) {
|
|
958
|
+
console.error('No current version ID available');
|
|
959
|
+
MJNotificationService.Instance.CreateSimpleNotification('Cannot save: no version selected', 'error');
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
// Save artifact version to each selected collection
|
|
914
963
|
for (const collectionId of collectionIds) {
|
|
915
|
-
// Double check
|
|
964
|
+
// Double check this exact version doesn't already exist in the collection
|
|
916
965
|
const rv = new RunView();
|
|
917
966
|
const existingResult = await rv.RunView({
|
|
918
967
|
EntityName: 'MJ: Collection Artifacts',
|
|
919
|
-
ExtraFilter: `CollectionID='${collectionId}' AND
|
|
920
|
-
ResultType: 'entity_object'
|
|
968
|
+
ExtraFilter: `CollectionID='${collectionId}' AND ArtifactVersionID='${currentVersionId}'`,
|
|
969
|
+
ResultType: 'entity_object'
|
|
921
970
|
}, this.currentUser);
|
|
922
971
|
if (existingResult.Success && existingResult.Results && existingResult.Results.length > 0) {
|
|
923
|
-
console.log(`Artifact already in collection ${collectionId}, skipping`);
|
|
924
972
|
continue;
|
|
925
973
|
}
|
|
926
|
-
// Create junction record
|
|
974
|
+
// Create junction record with version ID
|
|
927
975
|
const collectionArtifact = await md.GetEntityObject('MJ: Collection Artifacts', this.currentUser);
|
|
928
976
|
collectionArtifact.CollectionID = collectionId;
|
|
929
|
-
collectionArtifact.
|
|
977
|
+
collectionArtifact.ArtifactVersionID = currentVersionId;
|
|
930
978
|
collectionArtifact.Sequence = 0;
|
|
931
979
|
const saved = await collectionArtifact.Save();
|
|
932
980
|
if (saved) {
|
|
933
981
|
successCount++;
|
|
934
982
|
}
|
|
935
983
|
else {
|
|
936
|
-
console.error(`Failed to save artifact to collection ${collectionId}`);
|
|
984
|
+
console.error(`Failed to save artifact version to collection ${collectionId}`);
|
|
937
985
|
}
|
|
938
986
|
}
|
|
939
987
|
if (successCount > 0) {
|
|
940
|
-
console.log(`✅ Saved artifact to ${successCount} collection(s)`);
|
|
941
988
|
MJNotificationService.Instance.CreateSimpleNotification(`Artifact saved to ${successCount} collection(s) successfully!`, 'success', 3000);
|
|
942
989
|
// Reload collection associations to update the bookmark icon state
|
|
943
990
|
await this.loadCollectionAssociations();
|
|
@@ -961,24 +1008,28 @@ export class ArtifactViewerPanelComponent {
|
|
|
961
1008
|
async loadLinksData() {
|
|
962
1009
|
if (!this.artifactId)
|
|
963
1010
|
return;
|
|
1011
|
+
// Clear old links data first to prevent stale data from previous artifact
|
|
1012
|
+
this.clearLinksData();
|
|
964
1013
|
try {
|
|
965
1014
|
const md = new Metadata();
|
|
966
1015
|
const rv = new RunView();
|
|
967
|
-
// Load all collections containing this artifact
|
|
1016
|
+
// Load all collections containing any version of this artifact
|
|
968
1017
|
const collArtifactsResult = await rv.RunView({
|
|
969
1018
|
EntityName: 'MJ: Collection Artifacts',
|
|
970
|
-
ExtraFilter: `
|
|
971
|
-
|
|
1019
|
+
ExtraFilter: `ArtifactVersionID IN (
|
|
1020
|
+
SELECT ID FROM [__mj].[vwArtifactVersions] WHERE ArtifactID='${this.artifactId}'
|
|
1021
|
+
)`,
|
|
1022
|
+
ResultType: 'entity_object'
|
|
972
1023
|
}, this.currentUser);
|
|
973
1024
|
if (collArtifactsResult.Success && collArtifactsResult.Results) {
|
|
974
1025
|
// Get unique collection IDs
|
|
975
|
-
const collectionIds = [...new Set(collArtifactsResult.Results.map(
|
|
1026
|
+
const collectionIds = [...new Set(collArtifactsResult.Results.map(ca => ca.CollectionID))];
|
|
976
1027
|
if (collectionIds.length > 0) {
|
|
977
|
-
const collectionsFilter = collectionIds.map(
|
|
1028
|
+
const collectionsFilter = collectionIds.map(id => `ID='${id}'`).join(' OR ');
|
|
978
1029
|
const collectionsResult = await rv.RunView({
|
|
979
1030
|
EntityName: 'MJ: Collections',
|
|
980
1031
|
ExtraFilter: collectionsFilter,
|
|
981
|
-
ResultType: 'entity_object'
|
|
1032
|
+
ResultType: 'entity_object'
|
|
982
1033
|
}, this.currentUser);
|
|
983
1034
|
if (collectionsResult.Success && collectionsResult.Results) {
|
|
984
1035
|
this.allCollections = collectionsResult.Results;
|
|
@@ -988,17 +1039,20 @@ export class ArtifactViewerPanelComponent {
|
|
|
988
1039
|
// Load origin conversation (if artifact came from conversation)
|
|
989
1040
|
// Artifacts are linked to conversations via ConversationDetailArtifact -> ConversationDetail -> Conversation
|
|
990
1041
|
// Get all version IDs for this artifact
|
|
991
|
-
const versionIds = this.allVersions.map(
|
|
1042
|
+
const versionIds = this.allVersions.map(v => v.ID);
|
|
992
1043
|
if (versionIds.length > 0) {
|
|
993
|
-
const versionFilter = versionIds.map(
|
|
1044
|
+
const versionFilter = versionIds.map(id => `ArtifactVersionID='${id}'`).join(' OR ');
|
|
994
1045
|
const convDetailArtifactsResult = await rv.RunView({
|
|
995
1046
|
EntityName: 'MJ: Conversation Detail Artifacts',
|
|
996
1047
|
ExtraFilter: versionFilter,
|
|
997
1048
|
MaxRows: 1,
|
|
998
|
-
ResultType: 'entity_object'
|
|
1049
|
+
ResultType: 'entity_object'
|
|
999
1050
|
}, this.currentUser);
|
|
1000
1051
|
if (convDetailArtifactsResult.Success && convDetailArtifactsResult.Results && convDetailArtifactsResult.Results.length > 0) {
|
|
1001
1052
|
const conversationDetailId = convDetailArtifactsResult.Results[0].ConversationDetailID;
|
|
1053
|
+
const artifactVersionId = convDetailArtifactsResult.Results[0].ArtifactVersionID;
|
|
1054
|
+
// Store which version came from the origin conversation
|
|
1055
|
+
this.originConversationVersionId = artifactVersionId;
|
|
1002
1056
|
// Load the conversation detail to get the conversation ID
|
|
1003
1057
|
const conversationDetail = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
1004
1058
|
const detailLoaded = await conversationDetail.Load(conversationDetailId);
|
|
@@ -1014,15 +1068,16 @@ export class ArtifactViewerPanelComponent {
|
|
|
1014
1068
|
EntityName: 'Conversation Details',
|
|
1015
1069
|
ExtraFilter: `ConversationID='${conversation.ID}' AND UserID='${this.currentUser.ID}'`,
|
|
1016
1070
|
MaxRows: 1,
|
|
1017
|
-
ResultType: 'simple'
|
|
1071
|
+
ResultType: 'simple'
|
|
1018
1072
|
}, this.currentUser);
|
|
1019
|
-
const userIsParticipant = participantResult.Success &&
|
|
1073
|
+
const userIsParticipant = participantResult.Success &&
|
|
1074
|
+
participantResult.Results &&
|
|
1075
|
+
participantResult.Results.length > 0;
|
|
1020
1076
|
this.hasAccessToOriginConversation = userIsOwner || userIsParticipant;
|
|
1021
1077
|
}
|
|
1022
1078
|
}
|
|
1023
1079
|
}
|
|
1024
1080
|
}
|
|
1025
|
-
console.log(`🔗 Loaded links: ${this.allCollections.length} collections, origin conversation: ${this.originConversation?.Name || 'none'}, viewContext: ${this.viewContext}`);
|
|
1026
1081
|
}
|
|
1027
1082
|
catch (error) {
|
|
1028
1083
|
console.error('Error loading links data:', error);
|
|
@@ -1030,28 +1085,34 @@ export class ArtifactViewerPanelComponent {
|
|
|
1030
1085
|
}
|
|
1031
1086
|
get linksToShow() {
|
|
1032
1087
|
const links = [];
|
|
1033
|
-
//
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1088
|
+
// Get current version ID being viewed
|
|
1089
|
+
const currentVersionId = this.artifactVersion?.ID;
|
|
1090
|
+
// RULE: In conversation context, show ONLY collection links
|
|
1091
|
+
// RULE: In collection context, show ONLY conversation links
|
|
1092
|
+
if (this.viewContext === 'conversation') {
|
|
1093
|
+
// Show all collections containing this artifact (any version)
|
|
1094
|
+
for (const collection of this.allCollections) {
|
|
1095
|
+
links.push({
|
|
1096
|
+
type: 'collection',
|
|
1097
|
+
id: collection.ID,
|
|
1098
|
+
name: collection.Name,
|
|
1099
|
+
hasAccess: true
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1041
1102
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1103
|
+
else if (this.viewContext === 'collection') {
|
|
1104
|
+
// Show origin conversation if it exists
|
|
1105
|
+
// Show for ALL versions of the artifact, not just the original version that was added
|
|
1106
|
+
if (this.originConversation) {
|
|
1107
|
+
links.push({
|
|
1108
|
+
type: 'conversation',
|
|
1109
|
+
id: this.originConversation.ID,
|
|
1110
|
+
name: this.originConversation.Name || 'Untitled Conversation',
|
|
1111
|
+
hasAccess: this.hasAccessToOriginConversation
|
|
1112
|
+
});
|
|
1047
1113
|
}
|
|
1048
|
-
links.push({
|
|
1049
|
-
type: 'collection',
|
|
1050
|
-
id: collection.ID,
|
|
1051
|
-
name: collection.Name,
|
|
1052
|
-
hasAccess: true, // User can see it, so they have access
|
|
1053
|
-
});
|
|
1054
1114
|
}
|
|
1115
|
+
// If viewContext is null, show nothing (no links)
|
|
1055
1116
|
return links;
|
|
1056
1117
|
}
|
|
1057
1118
|
/**
|
|
@@ -1061,9 +1122,13 @@ export class ArtifactViewerPanelComponent {
|
|
|
1061
1122
|
if (!link.hasAccess) {
|
|
1062
1123
|
return;
|
|
1063
1124
|
}
|
|
1125
|
+
// Include artifact ID, version number, and version ID so destination can show the artifact with correct URL
|
|
1064
1126
|
this.navigateToLink.emit({
|
|
1065
1127
|
type: link.type,
|
|
1066
1128
|
id: link.id,
|
|
1129
|
+
artifactId: this.artifactId,
|
|
1130
|
+
versionNumber: this.selectedVersionNumber,
|
|
1131
|
+
versionId: this.artifactVersion?.ID
|
|
1067
1132
|
});
|
|
1068
1133
|
}
|
|
1069
1134
|
onClose() {
|
|
@@ -1079,23 +1144,17 @@ export class ArtifactViewerPanelComponent {
|
|
|
1079
1144
|
async resolveDriverClassForType(artifactType) {
|
|
1080
1145
|
// Check if current artifact type has a DriverClass
|
|
1081
1146
|
if (artifactType.DriverClass) {
|
|
1082
|
-
console.log(`✅ Found DriverClass '${artifactType.DriverClass}' on artifact type '${artifactType.Name}'`);
|
|
1083
1147
|
return artifactType.DriverClass;
|
|
1084
1148
|
}
|
|
1085
1149
|
// No DriverClass on current type - check if it has a parent
|
|
1086
1150
|
if (artifactType.ParentID) {
|
|
1087
|
-
console.log(`🔍 No DriverClass on '${artifactType.Name}', checking parent...`);
|
|
1088
1151
|
const parentType = await this.getArtifactTypeById(artifactType.ParentID);
|
|
1089
1152
|
if (parentType) {
|
|
1090
1153
|
// Recursively check parent
|
|
1091
1154
|
return await this.resolveDriverClassForType(parentType);
|
|
1092
1155
|
}
|
|
1093
|
-
else {
|
|
1094
|
-
console.warn(`⚠️ Parent artifact type '${artifactType.ParentID}' not found`);
|
|
1095
|
-
}
|
|
1096
1156
|
}
|
|
1097
1157
|
// Reached root with no DriverClass
|
|
1098
|
-
console.log(`❌ No DriverClass found in hierarchy for '${artifactType.Name}'`);
|
|
1099
1158
|
return null;
|
|
1100
1159
|
}
|
|
1101
1160
|
/**
|
|
@@ -1127,7 +1186,7 @@ export class ArtifactViewerPanelComponent {
|
|
|
1127
1186
|
const parseOptions = {
|
|
1128
1187
|
extractInlineJson: true,
|
|
1129
1188
|
maxDepth: 100,
|
|
1130
|
-
debug: false
|
|
1189
|
+
debug: false
|
|
1131
1190
|
};
|
|
1132
1191
|
const parsed = ParseJSONRecursive(obj, parseOptions);
|
|
1133
1192
|
// Finally stringify with formatting
|
|
@@ -1151,11 +1210,11 @@ export class ArtifactViewerPanelComponent {
|
|
|
1151
1210
|
GetTabIcon(tabName) {
|
|
1152
1211
|
// Base tabs
|
|
1153
1212
|
const baseIcons = {
|
|
1154
|
-
Display: 'fas fa-eye',
|
|
1155
|
-
Code: 'fas fa-code',
|
|
1156
|
-
JSON: 'fas fa-file-code',
|
|
1157
|
-
Details: 'fas fa-info-circle',
|
|
1158
|
-
Links: 'fas fa-link'
|
|
1213
|
+
'Display': 'fas fa-eye',
|
|
1214
|
+
'Code': 'fas fa-code',
|
|
1215
|
+
'JSON': 'fas fa-file-code',
|
|
1216
|
+
'Details': 'fas fa-info-circle',
|
|
1217
|
+
'Links': 'fas fa-link'
|
|
1159
1218
|
};
|
|
1160
1219
|
if (baseIcons[tabName]) {
|
|
1161
1220
|
return baseIcons[tabName];
|
|
@@ -1189,13 +1248,40 @@ export class ArtifactViewerPanelComponent {
|
|
|
1189
1248
|
SetActiveTab(tabName) {
|
|
1190
1249
|
this.activeTab = tabName.toLowerCase();
|
|
1191
1250
|
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Track artifact usage event
|
|
1253
|
+
*/
|
|
1254
|
+
async trackArtifactUsage(usageType) {
|
|
1255
|
+
try {
|
|
1256
|
+
if (!this.artifactVersion?.ID || !this.currentUser?.ID) {
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const md = new Metadata();
|
|
1260
|
+
const usage = await md.GetEntityObject('MJ: Artifact Uses');
|
|
1261
|
+
usage.ArtifactVersionID = this.artifactVersion.ID;
|
|
1262
|
+
usage.UserID = this.currentUser.ID;
|
|
1263
|
+
usage.UsageType = usageType;
|
|
1264
|
+
usage.UsageContext = JSON.stringify({
|
|
1265
|
+
viewContext: this.viewContext,
|
|
1266
|
+
contextCollectionId: this.contextCollectionId,
|
|
1267
|
+
timestamp: new Date().toISOString()
|
|
1268
|
+
});
|
|
1269
|
+
// Save asynchronously - don't block UI
|
|
1270
|
+
usage.Save().catch(error => {
|
|
1271
|
+
console.error('Failed to track artifact usage:', error);
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
catch (error) {
|
|
1275
|
+
console.error('Error tracking artifact usage:', error);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1192
1278
|
static ɵfac = function ArtifactViewerPanelComponent_Factory(t) { return new (t || ArtifactViewerPanelComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService), i0.ɵɵdirectiveInject(i2.DomSanitizer)); };
|
|
1193
1279
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactViewerPanelComponent, selectors: [["mj-artifact-viewer-panel"]], viewQuery: function ArtifactViewerPanelComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1194
1280
|
i0.ɵɵviewQuery(ArtifactTypePluginViewerComponent, 5);
|
|
1195
1281
|
} if (rf & 2) {
|
|
1196
1282
|
let _t;
|
|
1197
1283
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.pluginViewer = _t.first);
|
|
1198
|
-
} }, inputs: { artifactId: "artifactId", currentUser: "currentUser", environmentId: "environmentId", versionNumber: "versionNumber", showSaveToCollection: "showSaveToCollection", refreshTrigger: "refreshTrigger", viewContext: "viewContext", contextCollectionId: "contextCollectionId", canShare: "canShare", canEdit: "canEdit" }, outputs: { closed: "closed", saveToCollectionRequested: "saveToCollectionRequested", navigateToLink: "navigateToLink", shareRequested: "shareRequested" }, features: [i0.ɵɵNgOnChangesFeature], decls: 22, vars: 12, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-header-left"], [1, "fas", "fa-cube"], [1, "header-description"], [1, "panel-header-right"], [1, "version-selector", 3, "click"], [1, "fas", "fa-history"], [1, "version-label"], [1, "fas", "fa-chevron-down", "dropdown-icon", 3, "open"], [1, "version-dropdown"], [1, "save-to-collection-btn", 3, "in-collection", "title"], ["title", "Share", 1, "share-btn"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "panel-content"], [1, "loading-state"], [1, "error-state"], [1, "artifact-content-wrapper"], [1, "fas", "fa-chevron-down", "dropdown-icon"], [1, "version-dropdown", 3, "click"], [1, "version-option", 3, "selected"], [1, "version-option", 3, "click"], [1, "version-number"], [1, "version-date"], [1, "fas", "fa-check"], [1, "save-to-collection-btn", 3, "click", "title"], ["title", "Share", 1, "share-btn", 3, "click"], [1, "fas", "fa-share-nodes"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-exclamation-triangle"], [1, "tab-navigation"], [1, "tab-btn", 3, "active"], [1, "tab-content"], [1, "plugin-container", 3, "display"], [1, "display-content"], [1, "details-content"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "links-container"], [1, "links-section"], [1, "empty-state"], [1, "tab-btn", 3, "click"], [3, "class"], [1, "plugin-container"], [3, "artifactVersion", "artifactTypeName", "contentType", "readonly"], [1, "display-toolbar"], ["title", "Print", 1, "btn-icon", 3, "click"], [1, "fas", "fa-print"], ["title", "Copy Content", 1, "btn-icon", 3, "click"], [1, "fas", "fa-copy"], [1, "markdown-content"], [1, "html-content", 3, "innerHTML"], [3, "data"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "link-item"], [1, "link-icon"], [1, "fas", "fa-comments"], [1, "fas", "fa-folder"], [1, "link-content"], [1, "link-name"], [1, "link-type"], [1, "link-actions"], [1, "
|
|
1284
|
+
} }, inputs: { artifactId: "artifactId", currentUser: "currentUser", environmentId: "environmentId", versionNumber: "versionNumber", showSaveToCollection: "showSaveToCollection", refreshTrigger: "refreshTrigger", viewContext: "viewContext", contextCollectionId: "contextCollectionId", canShare: "canShare", canEdit: "canEdit" }, outputs: { closed: "closed", saveToCollectionRequested: "saveToCollectionRequested", navigateToLink: "navigateToLink", shareRequested: "shareRequested" }, features: [i0.ɵɵNgOnChangesFeature], decls: 22, vars: 12, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-header-left"], [1, "fas", "fa-cube"], [1, "header-description"], [1, "panel-header-right"], [1, "version-selector", 3, "click"], [1, "fas", "fa-history"], [1, "version-label"], [1, "fas", "fa-chevron-down", "dropdown-icon", 3, "open"], [1, "version-dropdown"], [1, "save-to-collection-btn", 3, "in-collection", "title"], ["title", "Share", 1, "share-btn"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "panel-content"], [1, "loading-state"], [1, "error-state"], [1, "artifact-content-wrapper"], [1, "fas", "fa-chevron-down", "dropdown-icon"], [1, "version-dropdown", 3, "click"], [1, "version-option", 3, "selected"], [1, "version-option", 3, "click"], [1, "version-number"], [1, "version-date"], [1, "fas", "fa-check"], [1, "save-to-collection-btn", 3, "click", "title"], ["title", "Share", 1, "share-btn", 3, "click"], [1, "fas", "fa-share-nodes"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-exclamation-triangle"], [1, "tab-navigation"], [1, "tab-btn", 3, "active"], [1, "tab-content"], [1, "plugin-container", 3, "display"], [1, "display-content"], [1, "details-content"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "links-container"], [1, "links-section"], [1, "empty-state"], [1, "tab-btn", 3, "click"], [3, "class"], [1, "plugin-container"], [3, "artifactVersion", "artifactTypeName", "contentType", "readonly"], [1, "display-toolbar"], ["title", "Print", 1, "btn-icon", 3, "click"], [1, "fas", "fa-print"], ["title", "Copy Content", 1, "btn-icon", 3, "click"], [1, "fas", "fa-copy"], [1, "markdown-content"], [1, "html-content", 3, "innerHTML"], [3, "data"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "link-item", 3, "disabled", "clickable", "title"], [1, "link-item", 3, "click", "title"], [1, "link-icon"], [1, "fas", "fa-comments"], [1, "fas", "fa-folder"], [1, "link-content"], [1, "link-name"], [1, "link-type"], [1, "link-actions"], [1, "fas", "fa-arrow-right"], [1, "fas", "fa-link"], [1, "dynamic-tab-content"], [1, "markdown-viewer", 3, "innerHTML"], [1, "json-viewer"], [1, "code-viewer"], [1, "html-viewer", 3, "innerHTML"], [1, "plaintext-viewer"], [1, "json-toolbar"], ["title", "Copy JSON", 1, "btn-icon", 3, "click"], [1, "json-editor-container"], [2, "width", "100%", "height", "100%", 3, "value", "language", "readonly", "lineWrapping"], [1, "code-toolbar"], ["title", "Copy Code", 1, "btn-icon", 3, "click"], [1, "code-editor-container"]], template: function ArtifactViewerPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1199
1285
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h3");
|
|
1200
1286
|
i0.ɵɵelement(4, "i", 3);
|
|
1201
1287
|
i0.ɵɵtext(5);
|
|
@@ -1203,7 +1289,7 @@ export class ArtifactViewerPanelComponent {
|
|
|
1203
1289
|
i0.ɵɵtemplate(6, ArtifactViewerPanelComponent_Conditional_6_Template, 2, 1, "p", 4);
|
|
1204
1290
|
i0.ɵɵelementEnd();
|
|
1205
1291
|
i0.ɵɵelementStart(7, "div", 5)(8, "div", 6);
|
|
1206
|
-
i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Template_div_click_8_listener() { return ctx.toggleVersionDropdown(); });
|
|
1292
|
+
i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Template_div_click_8_listener() { return ctx.viewContext !== "collection" && ctx.toggleVersionDropdown(); });
|
|
1207
1293
|
i0.ɵɵelement(9, "i", 7);
|
|
1208
1294
|
i0.ɵɵelementStart(10, "span", 8);
|
|
1209
1295
|
i0.ɵɵtext(11);
|
|
@@ -1224,11 +1310,11 @@ export class ArtifactViewerPanelComponent {
|
|
|
1224
1310
|
i0.ɵɵadvance();
|
|
1225
1311
|
i0.ɵɵconditional(ctx.displayDescription ? 6 : -1);
|
|
1226
1312
|
i0.ɵɵadvance(2);
|
|
1227
|
-
i0.ɵɵclassProp("clickable", ctx.allVersions.length > 1);
|
|
1313
|
+
i0.ɵɵclassProp("clickable", ctx.allVersions.length > 1 && ctx.viewContext !== "collection");
|
|
1228
1314
|
i0.ɵɵadvance(3);
|
|
1229
1315
|
i0.ɵɵtextInterpolate1("v", ctx.selectedVersionNumber, "");
|
|
1230
1316
|
i0.ɵɵadvance();
|
|
1231
|
-
i0.ɵɵconditional(ctx.allVersions.length > 1 ? 12 : -1);
|
|
1317
|
+
i0.ɵɵconditional(ctx.allVersions.length > 1 && ctx.viewContext !== "collection" ? 12 : -1);
|
|
1232
1318
|
i0.ɵɵadvance();
|
|
1233
1319
|
i0.ɵɵconditional(ctx.showVersionDropdown ? 13 : -1);
|
|
1234
1320
|
i0.ɵɵadvance();
|
|
@@ -1241,11 +1327,11 @@ export class ArtifactViewerPanelComponent {
|
|
|
1241
1327
|
i0.ɵɵconditional(ctx.error ? 20 : -1);
|
|
1242
1328
|
i0.ɵɵadvance();
|
|
1243
1329
|
i0.ɵɵconditional(!ctx.isLoading && !ctx.error && ctx.artifact ? 21 : -1);
|
|
1244
|
-
} }, dependencies: [i3.MarkdownComponent, i4.CodeEditorComponent, i5.ArtifactTypePluginViewerComponent, i6.DatePipe], styles: [".artifact-viewer-panel[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366F1;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%]:hover {\n background: #E5E7EB;\n}\n\n.version-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon[_ngcontent-%COMP%] {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon.open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.version-label[_ngcontent-%COMP%] {\n font-family: monospace;\n}\n\n.version-dropdown[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 13px;\n}\n\n.version-option[_ngcontent-%COMP%]:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected[_ngcontent-%COMP%] {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option[_ngcontent-%COMP%] .version-number[_ngcontent-%COMP%] {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option[_ngcontent-%COMP%] .version-date[_ngcontent-%COMP%] {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option[_ngcontent-%COMP%] i.fa-check[_ngcontent-%COMP%] {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%] {\n color: #6366F1; \n\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%]:hover {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.share-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.share-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6366F1;\n}\n\n.share-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.artifact-content-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.loading-state[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #DC2626;\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n.artifact-meta[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin-bottom: 16px;\n padding: 16px;\n background: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description[_ngcontent-%COMP%] {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%]:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #F59E0B;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select[_ngcontent-%COMP%], \n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select[_ngcontent-%COMP%]:focus, \n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider[_ngcontent-%COMP%]::before, \n.divider[_ngcontent-%COMP%]::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n padding: 0 12px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n\n\n.tab-navigation[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n color: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn[_ngcontent-%COMP%]:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active[_ngcontent-%COMP%] {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n}\n\n.display-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 0;\n min-width: 0;\n padding: 7px;\n}\n\n.display-toolbar[_ngcontent-%COMP%] {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content[_ngcontent-%COMP%], \n.html-content[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; \n\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content[_ngcontent-%COMP%] .artifact-meta[_ngcontent-%COMP%] {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content[_ngcontent-%COMP%] .meta-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.attributes-section[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n\n\n.links-container[_ngcontent-%COMP%] {\n padding: 20px;\n}\n\n.links-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item[_ngcontent-%COMP%]:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n color: #1e40af;\n}\n\n.link-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.link-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.link-action-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #1e40af;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.link-action-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #EFF6FF;\n border-color: #1e40af;\n}\n\n.link-action-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n color: #9CA3AF;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.dynamic-tab-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n line-height: 1.6;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] { font-size: 24px; }\n.markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] { font-size: 20px; }\n.markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 18px; }\n\n.markdown-viewer[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] ul[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n padding: 0;\n}\n\n.code-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.code-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.code-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.plaintext-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n}"] });
|
|
1330
|
+
} }, dependencies: [i3.MarkdownComponent, i4.CodeEditorComponent, i5.ArtifactTypePluginViewerComponent, i6.DatePipe], styles: [".artifact-viewer-panel[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366F1;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%]:hover {\n background: #E5E7EB;\n}\n\n.version-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon[_ngcontent-%COMP%] {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon.open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.version-label[_ngcontent-%COMP%] {\n font-family: monospace;\n}\n\n.version-dropdown[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 13px;\n}\n\n.version-option[_ngcontent-%COMP%]:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected[_ngcontent-%COMP%] {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option[_ngcontent-%COMP%] .version-number[_ngcontent-%COMP%] {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option[_ngcontent-%COMP%] .version-date[_ngcontent-%COMP%] {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option[_ngcontent-%COMP%] i.fa-check[_ngcontent-%COMP%] {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%] {\n color: #6366F1; \n\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%]:hover {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.share-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.share-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6366F1;\n}\n\n.share-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.artifact-content-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.loading-state[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #DC2626;\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n.artifact-meta[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin-bottom: 16px;\n padding: 16px;\n background: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description[_ngcontent-%COMP%] {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%]:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #F59E0B;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select[_ngcontent-%COMP%], \n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select[_ngcontent-%COMP%]:focus, \n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider[_ngcontent-%COMP%]::before, \n.divider[_ngcontent-%COMP%]::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n padding: 0 12px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n\n\n.tab-navigation[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n color: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn[_ngcontent-%COMP%]:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active[_ngcontent-%COMP%] {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n}\n\n.display-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 0;\n min-width: 0;\n padding: 7px;\n}\n\n.display-toolbar[_ngcontent-%COMP%] {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content[_ngcontent-%COMP%], \n.html-content[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; \n\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content[_ngcontent-%COMP%] .artifact-meta[_ngcontent-%COMP%] {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content[_ngcontent-%COMP%] .meta-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.attributes-section[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n\n\n.links-container[_ngcontent-%COMP%] {\n padding: 20px;\n}\n\n.links-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.link-item.clickable[_ngcontent-%COMP%]:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n background: #F3F4F6;\n}\n\n.link-item.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.link-item[_ngcontent-%COMP%]:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n color: #1e40af;\n}\n\n.link-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.link-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n flex-shrink: 0;\n}\n\n.link-actions[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #6B7280;\n transition: all 0.15s;\n}\n\n.link-item.clickable[_ngcontent-%COMP%]:hover .link-actions[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #1e40af;\n transform: translateX(2px);\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.dynamic-tab-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n line-height: 1.6;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] { font-size: 24px; }\n.markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] { font-size: 20px; }\n.markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 18px; }\n\n.markdown-viewer[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] ul[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n padding: 0;\n}\n\n.code-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.code-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.code-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.plaintext-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n}"] });
|
|
1245
1331
|
}
|
|
1246
1332
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ArtifactViewerPanelComponent, [{
|
|
1247
1333
|
type: Component,
|
|
1248
|
-
args: [{ selector: 'mj-artifact-viewer-panel', template: "<div class=\"artifact-viewer-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <h3>\n <i class=\"fas fa-cube\"></i>\n {{ displayName }}\n </h3>\n @if (displayDescription) {\n <p class=\"header-description\">{{ displayDescription }}</p>\n }\n </div>\n <div class=\"panel-header-right\">\n <div class=\"version-selector\" [class.clickable]=\"allVersions.length > 1\" (click)=\"toggleVersionDropdown()\">\n <i class=\"fas fa-history\"></i>\n <span class=\"version-label\">v{{ selectedVersionNumber }}</span>\n @if (allVersions.length > 1) {\n <i class=\"fas fa-chevron-down dropdown-icon\" [class.open]=\"showVersionDropdown\"></i>\n }\n @if (showVersionDropdown) {\n <div class=\"version-dropdown\" (click)=\"$event.stopPropagation()\">\n @for (version of allVersions; track version.ID) {\n <div class=\"version-option\"\n [class.selected]=\"version.VersionNumber === selectedVersionNumber\"\n (click)=\"selectVersion(version); $event.stopPropagation()\">\n <span class=\"version-number\">v{{ version.VersionNumber }}</span>\n <span class=\"version-date\">{{ version.__mj_CreatedAt | date:'short' }}</span>\n @if (version.VersionNumber === selectedVersionNumber) {\n <i class=\"fas fa-check\"></i>\n }\n </div>\n }\n </div>\n }\n </div>\n @if (showSaveToCollection) {\n <button class=\"save-to-collection-btn\"\n [class.in-collection]=\"isInCollection\"\n (click)=\"onSaveToLibrary()\"\n [title]=\"isInCollection ? 'Saved to ' + artifactCollections.length + ' collection(s)' : 'Save to Collection'\">\n <i [class]=\"isInCollection ? 'fas fa-bookmark' : 'far fa-bookmark'\"></i>\n </button>\n }\n @if (canShare) {\n <button class=\"share-btn\"\n (click)=\"onShare()\"\n title=\"Share\">\n <i class=\"fas fa-share-nodes\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n\n <div class=\"panel-content\">\n @if (isLoading) {\n <div class=\"loading-state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading artifact...</span>\n </div>\n }\n\n @if (error) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ error }}</span>\n </div>\n }\n\n @if (!isLoading && !error && artifact) {\n <div class=\"artifact-content-wrapper\">\n <!-- Tab Navigation (Dynamic) -->\n <div class=\"tab-navigation\">\n @for (tab of allTabs; track tab) {\n <button class=\"tab-btn\"\n [class.active]=\"activeTab === tab.toLowerCase()\"\n (click)=\"SetActiveTab(tab)\">\n @if (GetTabIcon(tab)) {\n <i [class]=\"GetTabIcon(tab)!\"></i>\n }\n {{ tab }}\n </button>\n }\n </div>\n\n <!-- Tab Content (Dynamic) -->\n <div class=\"tab-content\">\n <!-- Plugin Viewer - Created once, kept alive, shown/hidden with CSS -->\n @if (hasPlugin && artifactVersion && artifactTypeName) {\n <div class=\"plugin-container\" [style.display]=\"activeTab === 'display' ? 'block' : 'none'\">\n <mj-artifact-type-plugin-viewer\n [artifactVersion]=\"artifactVersion\"\n [artifactTypeName]=\"artifactTypeName\"\n [contentType]=\"contentType\"\n [readonly]=\"true\">\n </mj-artifact-type-plugin-viewer>\n </div>\n }\n\n <!-- Display Tab - Fallback content when no plugin -->\n @if (activeTab === 'display' && (!hasPlugin || !artifactVersion)) {\n <div class=\"display-content\">\n @if (displayMarkdown || displayHtml) {\n <!-- Fallback to extracted markdown/HTML attributes -->\n <div class=\"display-toolbar\">\n <button class=\"btn-icon\" title=\"Print\" (click)=\"onPrintDisplayContent()\">\n <i class=\"fas fa-print\"></i> Print\n </button>\n <button class=\"btn-icon\" title=\"Copy Content\" (click)=\"onCopyDisplayContent()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n @if (displayMarkdown) {\n <div class=\"markdown-content\">\n <markdown [data]=\"displayMarkdown\"></markdown>\n </div>\n } @else if (displayHtml) {\n <div class=\"html-content\" [innerHTML]=\"displayHtml\"></div>\n }\n }\n </div>\n }\n\n <!-- Details Tab - Artifact metadata (always in DOM, hidden with CSS) -->\n <div class=\"details-content\" [style.display]=\"activeTab === 'details' ? 'block' : 'none'\">\n <div class=\"artifact-meta\">\n <div class=\"meta-item\">\n <label>Type</label>\n <span>{{ artifact.Type }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Version</label>\n <span>{{ artifactVersion?.VersionNumber || 1 }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Created</label>\n <span>{{ artifact.__mj_CreatedAt | date:'short' }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Updated</label>\n <span>{{ artifactVersion?.__mj_UpdatedAt | date:'short' }}</span>\n </div>\n @if (artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Artifact Description</label>\n <span>{{ artifact.Description }}</span>\n </div>\n }\n @if (artifactVersion?.Description && artifact.Description && artifactVersion?.Description !== artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Version Description</label>\n <span>{{ artifactVersion?.Description }}</span>\n </div>\n }\n </div>\n\n <!-- Version Attributes -->\n @if (filteredAttributes.length > 0) {\n <div class=\"attributes-section\">\n <h4>Version Attributes</h4>\n <div class=\"attributes-list\">\n @for (attr of filteredAttributes; track attr.ID) {\n <div class=\"attribute-item\">\n <label>{{ attr.Name }}</label>\n @if (attr.Value) {\n <span>{{ attr.Value }}</span>\n } @else {\n <span class=\"attribute-empty-pill\">Empty</span>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Links Tab - Conversations and Collections (always in DOM, hidden with CSS) -->\n <div class=\"links-container\" [style.display]=\"activeTab === 'links' ? 'block' : 'none'\">\n @if (linksToShow.length > 0) {\n <div class=\"links-section\">\n @for (link of linksToShow; track link.id) {\n <div class=\"link-item\">\n <div class=\"link-icon\">\n @if (link.type === 'conversation') {\n <i class=\"fas fa-comments\"></i>\n } @else {\n <i class=\"fas fa-folder\"></i>\n }\n </div>\n <div class=\"link-content\">\n <div class=\"link-name\">{{ link.name }}</div>\n <div class=\"link-type\">{{ link.type === 'conversation' ? 'Conversation' : 'Collection' }}</div>\n </div>\n <div class=\"link-actions\">\n <button\n class=\"link-action-btn\"\n [disabled]=\"!link.hasAccess\"\n [title]=\"link.hasAccess ? 'Open' : 'No access'\"\n (click)=\"onNavigateToLink(link)\">\n <i class=\"fas fa-arrow-right\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-link\"></i>\n <p>No links available</p>\n </div>\n }\n </div>\n\n <!-- Dynamic Plugin Tabs and Base Tabs (JSON, etc.) -->\n @if (activeTab !== 'display' && activeTab !== 'details' && activeTab !== 'links') {\n @if (GetTabContent(activeTab); as tabData) {\n <div class=\"dynamic-tab-content\">\n @switch (tabData.type) {\n @case ('markdown') {\n <div class=\"markdown-viewer\" [innerHTML]=\"RenderMarkdown(tabData.content)\"></div>\n }\n @case ('json') {\n <div class=\"json-viewer\">\n <div class=\"json-toolbar\">\n <button class=\"btn-icon\" title=\"Copy JSON\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"json-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('code') {\n <div class=\"code-viewer\">\n <div class=\"code-toolbar\">\n <button class=\"btn-icon\" title=\"Copy Code\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"tabData.language || 'typescript'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('html') {\n <div class=\"html-viewer\" [innerHTML]=\"tabData.content\"></div>\n }\n @case ('plaintext') {\n <pre class=\"plaintext-viewer\">{{ tabData.content }}</pre>\n }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n</div>\n\n", styles: [".artifact-viewer-panel {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header h3 i {\n color: #6366F1;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable {\n cursor: pointer;\n}\n\n.version-selector.clickable:hover {\n background: #E5E7EB;\n}\n\n.version-selector i {\n font-size: 11px;\n}\n\n.version-selector .dropdown-icon {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector .dropdown-icon.open {\n transform: rotate(180deg);\n}\n\n.version-label {\n font-family: monospace;\n}\n\n.version-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 13px;\n}\n\n.version-option:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option .version-number {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option .version-date {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option i.fa-check {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.save-to-collection-btn:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn i {\n font-size: 14px;\n}\n\n.save-to-collection-btn.in-collection {\n color: #6366F1; /* Indigo color to indicate it's saved */\n}\n\n.save-to-collection-btn.in-collection:hover {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.share-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.share-btn:hover {\n background: #F3F4F6;\n color: #6366F1;\n}\n\n.share-btn i {\n font-size: 14px;\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.close-btn:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn i {\n font-size: 14px;\n}\n\n.panel-content {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.artifact-content-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.loading-state,\n.error-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state {\n color: #DC2626;\n}\n\n.loading-state i {\n font-size: 24px;\n}\n\n.artifact-meta {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin-bottom: 16px;\n padding: 16px;\n background: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item label {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item span {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon i {\n font-size: 14px;\n}\n\n/* Library Dialog Styles */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-header h3 i {\n color: #F59E0B;\n}\n\n.modal-body {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section {\n margin-bottom: 20px;\n}\n\n.form-section label {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select,\n.form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select:focus,\n.form-input:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider::before,\n.divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider span {\n padding: 0 12px;\n}\n\n.create-collection-row {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row .form-input {\n flex: 1;\n}\n\n.btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n/* Tab Navigation */\n.tab-navigation {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n color: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn i {\n font-size: 14px;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n}\n\n.display-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 0;\n min-width: 0;\n padding: 7px;\n}\n\n.display-toolbar {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content,\n.html-content {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; /* top right bottom left */\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content .artifact-meta {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content .meta-item.full-width {\n grid-column: 1 / -1;\n}\n\n.attributes-section {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section h4 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item label {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item span {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Links Tab */\n.links-container {\n padding: 20px;\n}\n\n.links-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon i {\n font-size: 18px;\n color: #1e40af;\n}\n\n.link-content {\n flex: 1;\n min-width: 0;\n}\n\n.link-name {\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions {\n display: flex;\n gap: 8px;\n}\n\n.link-action-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #1e40af;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.link-action-btn:hover:not(:disabled) {\n background: #EFF6FF;\n border-color: #1e40af;\n}\n\n.link-action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n color: #9CA3AF;\n}\n\n.links-container .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container .empty-state p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Dynamic Tab Content Styles */\n.dynamic-tab-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n.markdown-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n line-height: 1.6;\n}\n\n.markdown-viewer h1, .markdown-viewer h2, .markdown-viewer h3 {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer h1 { font-size: 24px; }\n.markdown-viewer h2 { font-size: 20px; }\n.markdown-viewer h3 { font-size: 18px; }\n\n.markdown-viewer p {\n margin-bottom: 12px;\n}\n\n.markdown-viewer ul, .markdown-viewer ol {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer code {\n background: #f3f4f6;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer pre {\n background: #f3f4f6;\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer pre code {\n background: none;\n padding: 0;\n}\n\n.code-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.code-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.code-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.plaintext-viewer {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n}\n"] }]
|
|
1334
|
+
args: [{ selector: 'mj-artifact-viewer-panel', template: "<div class=\"artifact-viewer-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <h3>\n <i class=\"fas fa-cube\"></i>\n {{ displayName }}\n </h3>\n @if (displayDescription) {\n <p class=\"header-description\">{{ displayDescription }}</p>\n }\n </div>\n <div class=\"panel-header-right\">\n <div class=\"version-selector\"\n [class.clickable]=\"allVersions.length > 1 && viewContext !== 'collection'\"\n (click)=\"viewContext !== 'collection' && toggleVersionDropdown()\">\n <i class=\"fas fa-history\"></i>\n <span class=\"version-label\">v{{ selectedVersionNumber }}</span>\n @if (allVersions.length > 1 && viewContext !== 'collection') {\n <i class=\"fas fa-chevron-down dropdown-icon\" [class.open]=\"showVersionDropdown\"></i>\n }\n @if (showVersionDropdown) {\n <div class=\"version-dropdown\" (click)=\"$event.stopPropagation()\">\n @for (version of allVersions; track version.ID) {\n <div class=\"version-option\"\n [class.selected]=\"version.VersionNumber === selectedVersionNumber\"\n (click)=\"selectVersion(version); $event.stopPropagation()\">\n <span class=\"version-number\">v{{ version.VersionNumber }}</span>\n <span class=\"version-date\">{{ version.__mj_CreatedAt | date:'short' }}</span>\n @if (version.VersionNumber === selectedVersionNumber) {\n <i class=\"fas fa-check\"></i>\n }\n </div>\n }\n </div>\n }\n </div>\n @if (showSaveToCollection) {\n <button class=\"save-to-collection-btn\"\n [class.in-collection]=\"isInCollection\"\n (click)=\"onSaveToLibrary()\"\n [title]=\"isInCollection ? 'Current version saved to ' + currentVersionCollections.length + ' collection(s)' : 'Save to Collection'\">\n <i [class]=\"isInCollection ? 'fas fa-bookmark' : 'far fa-bookmark'\"></i>\n </button>\n }\n @if (canShare) {\n <button class=\"share-btn\"\n (click)=\"onShare()\"\n title=\"Share\">\n <i class=\"fas fa-share-nodes\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n\n <div class=\"panel-content\">\n @if (isLoading) {\n <div class=\"loading-state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading artifact...</span>\n </div>\n }\n\n @if (error) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ error }}</span>\n </div>\n }\n\n @if (!isLoading && !error && artifact) {\n <div class=\"artifact-content-wrapper\">\n <!-- Tab Navigation (Dynamic) -->\n <div class=\"tab-navigation\">\n @for (tab of allTabs; track tab) {\n <button class=\"tab-btn\"\n [class.active]=\"activeTab === tab.toLowerCase()\"\n (click)=\"SetActiveTab(tab)\">\n @if (GetTabIcon(tab)) {\n <i [class]=\"GetTabIcon(tab)!\"></i>\n }\n {{ tab }}\n </button>\n }\n </div>\n\n <!-- Tab Content (Dynamic) -->\n <div class=\"tab-content\">\n <!-- Plugin Viewer - Created once, kept alive, shown/hidden with CSS -->\n @if (hasPlugin && artifactVersion && artifactTypeName) {\n <div class=\"plugin-container\" [style.display]=\"activeTab === 'display' ? 'block' : 'none'\">\n <mj-artifact-type-plugin-viewer\n [artifactVersion]=\"artifactVersion\"\n [artifactTypeName]=\"artifactTypeName\"\n [contentType]=\"contentType\"\n [readonly]=\"true\">\n </mj-artifact-type-plugin-viewer>\n </div>\n }\n\n <!-- Display Tab - Fallback content when no plugin -->\n @if (activeTab === 'display' && (!hasPlugin || !artifactVersion)) {\n <div class=\"display-content\">\n @if (displayMarkdown || displayHtml) {\n <!-- Fallback to extracted markdown/HTML attributes -->\n <div class=\"display-toolbar\">\n <button class=\"btn-icon\" title=\"Print\" (click)=\"onPrintDisplayContent()\">\n <i class=\"fas fa-print\"></i> Print\n </button>\n <button class=\"btn-icon\" title=\"Copy Content\" (click)=\"onCopyDisplayContent()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n @if (displayMarkdown) {\n <div class=\"markdown-content\">\n <markdown [data]=\"displayMarkdown\"></markdown>\n </div>\n } @else if (displayHtml) {\n <div class=\"html-content\" [innerHTML]=\"displayHtml\"></div>\n }\n }\n </div>\n }\n\n <!-- Details Tab - Artifact metadata (always in DOM, hidden with CSS) -->\n <div class=\"details-content\" [style.display]=\"activeTab === 'details' ? 'block' : 'none'\">\n <div class=\"artifact-meta\">\n <div class=\"meta-item\">\n <label>Type</label>\n <span>{{ artifact.Type }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Version</label>\n <span>{{ artifactVersion?.VersionNumber || 1 }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Created</label>\n <span>{{ artifact.__mj_CreatedAt | date:'short' }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Updated</label>\n <span>{{ artifactVersion?.__mj_UpdatedAt | date:'short' }}</span>\n </div>\n @if (artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Artifact Description</label>\n <span>{{ artifact.Description }}</span>\n </div>\n }\n @if (artifactVersion?.Description && artifact.Description && artifactVersion?.Description !== artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Version Description</label>\n <span>{{ artifactVersion?.Description }}</span>\n </div>\n }\n </div>\n\n <!-- Version Attributes -->\n @if (filteredAttributes.length > 0) {\n <div class=\"attributes-section\">\n <h4>Version Attributes</h4>\n <div class=\"attributes-list\">\n @for (attr of filteredAttributes; track attr.ID) {\n <div class=\"attribute-item\">\n <label>{{ attr.Name }}</label>\n @if (attr.Value) {\n <span>{{ attr.Value }}</span>\n } @else {\n <span class=\"attribute-empty-pill\">Empty</span>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Links Tab - Conversations and Collections (always in DOM, hidden with CSS) -->\n <div class=\"links-container\" [style.display]=\"activeTab === 'links' ? 'block' : 'none'\">\n @if (linksToShow.length > 0) {\n <div class=\"links-section\">\n @for (link of linksToShow; track link.id) {\n <div class=\"link-item\"\n [class.disabled]=\"!link.hasAccess\"\n [class.clickable]=\"link.hasAccess\"\n (click)=\"link.hasAccess ? onNavigateToLink(link) : null\"\n [title]=\"link.hasAccess ? 'Click to open' : 'No access'\">\n <div class=\"link-icon\">\n @if (link.type === 'conversation') {\n <i class=\"fas fa-comments\"></i>\n } @else {\n <i class=\"fas fa-folder\"></i>\n }\n </div>\n <div class=\"link-content\">\n <div class=\"link-name\">{{ link.name }}</div>\n <div class=\"link-type\">{{ link.type === 'conversation' ? 'Conversation' : 'Collection' }}</div>\n </div>\n <div class=\"link-actions\">\n <i class=\"fas fa-arrow-right\"></i>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-link\"></i>\n <p>No links available</p>\n </div>\n }\n </div>\n\n <!-- Dynamic Plugin Tabs and Base Tabs (JSON, etc.) -->\n @if (activeTab !== 'display' && activeTab !== 'details' && activeTab !== 'links') {\n @if (GetTabContent(activeTab); as tabData) {\n <div class=\"dynamic-tab-content\">\n @switch (tabData.type) {\n @case ('markdown') {\n <div class=\"markdown-viewer\" [innerHTML]=\"RenderMarkdown(tabData.content)\"></div>\n }\n @case ('json') {\n <div class=\"json-viewer\">\n <div class=\"json-toolbar\">\n <button class=\"btn-icon\" title=\"Copy JSON\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"json-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('code') {\n <div class=\"code-viewer\">\n <div class=\"code-toolbar\">\n <button class=\"btn-icon\" title=\"Copy Code\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"tabData.language || 'typescript'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('html') {\n <div class=\"html-viewer\" [innerHTML]=\"tabData.content\"></div>\n }\n @case ('plaintext') {\n <pre class=\"plaintext-viewer\">{{ tabData.content }}</pre>\n }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n</div>\n\n", styles: [".artifact-viewer-panel {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header h3 i {\n color: #6366F1;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable {\n cursor: pointer;\n}\n\n.version-selector.clickable:hover {\n background: #E5E7EB;\n}\n\n.version-selector i {\n font-size: 11px;\n}\n\n.version-selector .dropdown-icon {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector .dropdown-icon.open {\n transform: rotate(180deg);\n}\n\n.version-label {\n font-family: monospace;\n}\n\n.version-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 13px;\n}\n\n.version-option:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option .version-number {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option .version-date {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option i.fa-check {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.save-to-collection-btn:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn i {\n font-size: 14px;\n}\n\n.save-to-collection-btn.in-collection {\n color: #6366F1; /* Indigo color to indicate it's saved */\n}\n\n.save-to-collection-btn.in-collection:hover {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.share-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.share-btn:hover {\n background: #F3F4F6;\n color: #6366F1;\n}\n\n.share-btn i {\n font-size: 14px;\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.close-btn:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn i {\n font-size: 14px;\n}\n\n.panel-content {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.artifact-content-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.loading-state,\n.error-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state {\n color: #DC2626;\n}\n\n.loading-state i {\n font-size: 24px;\n}\n\n.artifact-meta {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin-bottom: 16px;\n padding: 16px;\n background: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item label {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item span {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon i {\n font-size: 14px;\n}\n\n/* Library Dialog Styles */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-header h3 i {\n color: #F59E0B;\n}\n\n.modal-body {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section {\n margin-bottom: 20px;\n}\n\n.form-section label {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select,\n.form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select:focus,\n.form-input:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider::before,\n.divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider span {\n padding: 0 12px;\n}\n\n.create-collection-row {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row .form-input {\n flex: 1;\n}\n\n.btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n/* Tab Navigation */\n.tab-navigation {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n color: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn i {\n font-size: 14px;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n}\n\n.display-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 0;\n min-width: 0;\n padding: 7px;\n}\n\n.display-toolbar {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content,\n.html-content {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; /* top right bottom left */\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content .artifact-meta {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content .meta-item.full-width {\n grid-column: 1 / -1;\n}\n\n.attributes-section {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section h4 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item label {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item span {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Links Tab */\n.links-container {\n padding: 20px;\n}\n\n.links-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item.clickable {\n cursor: pointer;\n}\n\n.link-item.clickable:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n background: #F3F4F6;\n}\n\n.link-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.link-item:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon i {\n font-size: 18px;\n color: #1e40af;\n}\n\n.link-content {\n flex: 1;\n min-width: 0;\n}\n\n.link-name {\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n flex-shrink: 0;\n}\n\n.link-actions i {\n font-size: 14px;\n color: #6B7280;\n transition: all 0.15s;\n}\n\n.link-item.clickable:hover .link-actions i {\n color: #1e40af;\n transform: translateX(2px);\n}\n\n.links-container .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container .empty-state p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Dynamic Tab Content Styles */\n.dynamic-tab-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n.markdown-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n line-height: 1.6;\n}\n\n.markdown-viewer h1, .markdown-viewer h2, .markdown-viewer h3 {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer h1 { font-size: 24px; }\n.markdown-viewer h2 { font-size: 20px; }\n.markdown-viewer h3 { font-size: 18px; }\n\n.markdown-viewer p {\n margin-bottom: 12px;\n}\n\n.markdown-viewer ul, .markdown-viewer ol {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer code {\n background: #f3f4f6;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer pre {\n background: #f3f4f6;\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer pre code {\n background: none;\n padding: 0;\n}\n\n.code-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.code-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.code-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.plaintext-viewer {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n}\n"] }]
|
|
1249
1335
|
}], () => [{ type: i1.MJNotificationService }, { type: i2.DomSanitizer }], { artifactId: [{
|
|
1250
1336
|
type: Input
|
|
1251
1337
|
}], currentUser: [{
|
|
@@ -1278,5 +1364,5 @@ export class ArtifactViewerPanelComponent {
|
|
|
1278
1364
|
type: ViewChild,
|
|
1279
1365
|
args: [ArtifactTypePluginViewerComponent]
|
|
1280
1366
|
}] }); })();
|
|
1281
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactViewerPanelComponent, { className: "ArtifactViewerPanelComponent", filePath: "src/lib/components/artifact-viewer-panel.component.ts", lineNumber:
|
|
1367
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactViewerPanelComponent, { className: "ArtifactViewerPanelComponent", filePath: "src/lib/components/artifact-viewer-panel.component.ts", lineNumber: 18 }); })();
|
|
1282
1368
|
//# sourceMappingURL=artifact-viewer-panel.component.js.map
|