@memberjunction/ng-explorer-core 5.43.0 → 5.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/lazy-feature-config.d.ts +1 -1
- package/dist/generated/lazy-feature-config.d.ts.map +1 -1
- package/dist/generated/lazy-feature-config.js +11 -3
- package/dist/generated/lazy-feature-config.js.map +1 -1
- package/dist/lib/about/about-dialog.component.d.ts +0 -1
- package/dist/lib/about/about-dialog.component.d.ts.map +1 -1
- package/dist/lib/about/about-dialog.component.js +217 -218
- package/dist/lib/about/about-dialog.component.js.map +1 -1
- package/dist/lib/command-palette/command-palette.component.js +8 -14
- package/dist/lib/command-palette/command-palette.component.js.map +1 -1
- package/dist/lib/conversation-feedback/conversation-feedback.js +66 -73
- package/dist/lib/conversation-feedback/conversation-feedback.js.map +1 -1
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js +35 -45
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +2 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +14 -8
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.js +9 -8
- package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.js +35 -43
- package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +10 -2
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.js +19 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts +1 -0
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.js +3 -2
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/shell.module.d.ts +1 -1
- package/dist/lib/shell/shell.module.d.ts.map +1 -1
- package/dist/lib/shell/shell.module.js +4 -1
- package/dist/lib/shell/shell.module.js.map +1 -1
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.js +5 -7
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.js.map +1 -1
- package/dist/lib/single-dashboard/single-dashboard.component.js +17 -27
- package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
- package/dist/lib/single-list-detail/single-list-detail.component.d.ts +6 -2
- package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -1
- package/dist/lib/single-list-detail/single-list-detail.component.js +48 -57
- package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
- package/dist/lib/single-search-result/single-search-result.component.js +17 -22
- package/dist/lib/single-search-result/single-search-result.component.js.map +1 -1
- package/dist/lib/user-notifications/user-notifications.component.js +60 -75
- package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +12 -5
- package/dist/module.js.map +1 -1
- package/package.json +47 -47
- package/dist/lib/__tests__/explorer-core.test.d.ts +0 -2
- package/dist/lib/__tests__/explorer-core.test.d.ts.map +0 -1
- package/dist/lib/__tests__/explorer-core.test.js +0 -229
- package/dist/lib/__tests__/explorer-core.test.js.map +0 -1
|
@@ -5,7 +5,8 @@ import * as i0 from "@angular/core";
|
|
|
5
5
|
import * as i1 from "@memberjunction/ng-shared";
|
|
6
6
|
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
7
7
|
import * as i3 from "@memberjunction/ng-entity-viewer";
|
|
8
|
-
import * as i4 from "@
|
|
8
|
+
import * as i4 from "@memberjunction/ng-ui-components";
|
|
9
|
+
import * as i5 from "@angular/common";
|
|
9
10
|
function SingleSearchResultComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
10
11
|
i0.ɵɵelementStart(0, "span", 5);
|
|
11
12
|
i0.ɵɵtext(1);
|
|
@@ -47,35 +48,29 @@ function SingleSearchResultComponent_Conditional_10_Template(rf, ctx) { if (rf &
|
|
|
47
48
|
i0.ɵɵelementEnd();
|
|
48
49
|
} }
|
|
49
50
|
function SingleSearchResultComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
50
|
-
i0.ɵɵelementStart(0, "
|
|
51
|
-
i0.ɵɵ
|
|
52
|
-
i0.ɵɵelementStart(
|
|
53
|
-
i0.ɵɵtext(
|
|
54
|
-
i0.ɵɵelementStart(4, "strong");
|
|
55
|
-
i0.ɵɵtext(5);
|
|
51
|
+
i0.ɵɵelementStart(0, "mj-empty-state", 8)(1, "p", 14);
|
|
52
|
+
i0.ɵɵtext(2, "No results found for \"");
|
|
53
|
+
i0.ɵɵelementStart(3, "strong");
|
|
54
|
+
i0.ɵɵtext(4);
|
|
56
55
|
i0.ɵɵelementEnd();
|
|
57
|
-
i0.ɵɵtext(
|
|
56
|
+
i0.ɵɵtext(5);
|
|
58
57
|
i0.ɵɵelementEnd();
|
|
59
|
-
i0.ɵɵelementStart(
|
|
60
|
-
i0.ɵɵtext(
|
|
58
|
+
i0.ɵɵelementStart(6, "p", 15);
|
|
59
|
+
i0.ɵɵtext(7, "Try a different search term or entity");
|
|
61
60
|
i0.ɵɵelementEnd()();
|
|
62
61
|
} if (rf & 2) {
|
|
63
62
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
64
|
-
i0.ɵɵadvance(
|
|
63
|
+
i0.ɵɵadvance(4);
|
|
65
64
|
i0.ɵɵtextInterpolate(ctx_r0.searchInput);
|
|
66
65
|
i0.ɵɵadvance();
|
|
67
66
|
i0.ɵɵtextInterpolate1("\" in ", ctx_r0.entity);
|
|
68
67
|
} }
|
|
69
68
|
function SingleSearchResultComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
70
|
-
i0.ɵɵ
|
|
71
|
-
i0.ɵɵelement(1, "i", 16);
|
|
72
|
-
i0.ɵɵelementStart(2, "p");
|
|
73
|
-
i0.ɵɵtext(3, "Found 1 result \u2014 opening record...");
|
|
74
|
-
i0.ɵɵelementEnd()();
|
|
69
|
+
i0.ɵɵelement(0, "mj-empty-state", 9);
|
|
75
70
|
} }
|
|
76
71
|
function SingleSearchResultComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
77
72
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
78
|
-
i0.ɵɵelementStart(0, "div", 10)(1, "mj-entity-viewer",
|
|
73
|
+
i0.ɵɵelementStart(0, "div", 10)(1, "mj-entity-viewer", 16);
|
|
79
74
|
i0.ɵɵlistener("DataLoaded", function SingleSearchResultComponent_Conditional_13_Template_mj_entity_viewer_DataLoaded_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnDataLoaded($event)); })("RecordOpened", function SingleSearchResultComponent_Conditional_13_Template_mj_entity_viewer_RecordOpened_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnRecordOpened($event)); })("OpenRelatedRecordRequested", function SingleSearchResultComponent_Conditional_13_Template_mj_entity_viewer_OpenRelatedRecordRequested_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnOpenRelatedRecord($event)); })("CreateRecordRequested", function SingleSearchResultComponent_Conditional_13_Template_mj_entity_viewer_CreateRecordRequested_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnCreateNewRecord()); });
|
|
80
75
|
i0.ɵɵelementEnd()();
|
|
81
76
|
} if (rf & 2) {
|
|
@@ -217,7 +212,7 @@ export class SingleSearchResultComponent extends BaseAngularComponent {
|
|
|
217
212
|
return `fa-solid fa-${icon}`;
|
|
218
213
|
}
|
|
219
214
|
static ɵfac = function SingleSearchResultComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SingleSearchResultComponent)(i0.ɵɵdirectiveInject(i1.NavigationService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
220
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SingleSearchResultComponent, selectors: [["mj-single-search-result"]], inputs: { entity: "entity", searchInput: "searchInput" }, outputs: { loadComplete: "loadComplete", loadStarted: "loadStarted" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 14, vars: 9, consts: [[1, "search-result-container"], [1, "content-header"], [1, "header-left"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "header-right"], [1, "loading-container"], [
|
|
215
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SingleSearchResultComponent, selectors: [["mj-single-search-result"]], inputs: { entity: "entity", searchInput: "searchInput" }, outputs: { loadComplete: "loadComplete", loadStarted: "loadStarted" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 14, vars: 9, consts: [[1, "search-result-container"], [1, "content-header"], [1, "header-left"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "header-right"], [1, "loading-container"], ["Variant", "no-results", "Icon", "fa-solid fa-magnifying-glass"], ["Icon", "fa-solid fa-arrow-right", "Title", "Found 1 result \u2014 opening record..."], [1, "viewer-container"], ["title", "New Record", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["text", "Searching..."], [1, "search-result-empty-message"], [1, "empty-hint"], [3, "DataLoaded", "RecordOpened", "OpenRelatedRecordRequested", "CreateRecordRequested", "Entity", "Provider", "FilterText", "Config"]], template: function SingleSearchResultComponent_Template(rf, ctx) { if (rf & 1) {
|
|
221
216
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
222
217
|
i0.ɵɵelement(3, "i", 3);
|
|
223
218
|
i0.ɵɵelementStart(4, "h2", 4);
|
|
@@ -228,8 +223,8 @@ export class SingleSearchResultComponent extends BaseAngularComponent {
|
|
|
228
223
|
i0.ɵɵconditionalCreate(9, SingleSearchResultComponent_Conditional_9_Template, 3, 0, "div", 6);
|
|
229
224
|
i0.ɵɵelementEnd();
|
|
230
225
|
i0.ɵɵconditionalCreate(10, SingleSearchResultComponent_Conditional_10_Template, 2, 0, "div", 7);
|
|
231
|
-
i0.ɵɵconditionalCreate(11, SingleSearchResultComponent_Conditional_11_Template,
|
|
232
|
-
i0.ɵɵconditionalCreate(12, SingleSearchResultComponent_Conditional_12_Template,
|
|
226
|
+
i0.ɵɵconditionalCreate(11, SingleSearchResultComponent_Conditional_11_Template, 8, 2, "mj-empty-state", 8);
|
|
227
|
+
i0.ɵɵconditionalCreate(12, SingleSearchResultComponent_Conditional_12_Template, 1, 0, "mj-empty-state", 9);
|
|
233
228
|
i0.ɵɵconditionalCreate(13, SingleSearchResultComponent_Conditional_13_Template, 2, 4, "div", 10);
|
|
234
229
|
i0.ɵɵelementEnd();
|
|
235
230
|
} if (rf & 2) {
|
|
@@ -249,11 +244,11 @@ export class SingleSearchResultComponent extends BaseAngularComponent {
|
|
|
249
244
|
i0.ɵɵconditional(ctx.SearchState === "single-result" ? 12 : -1);
|
|
250
245
|
i0.ɵɵadvance();
|
|
251
246
|
i0.ɵɵconditional(ctx.SearchState === "viewer" && ctx.EntityInfo ? 13 : -1);
|
|
252
|
-
} }, dependencies: [i2.LoadingComponent, i3.EntityViewerComponent, i4.DecimalPipe], styles: [".search-result-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n\n\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n\n\n\n\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 48px 0;\n}\n\n\n\n\n\n\n.
|
|
247
|
+
} }, dependencies: [i2.LoadingComponent, i3.EntityViewerComponent, i4.MJEmptyStateComponent, i5.DecimalPipe], styles: [".search-result-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n\n\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n\n\n\n\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 48px 0;\n}\n\n\n\n\n\n\n.search-result-empty-message[_ngcontent-%COMP%] {\n margin: 4px 0;\n font-size: 15px;\n}\n\n.empty-hint[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n\n\n\n\n\n.viewer-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n}"] });
|
|
253
248
|
}
|
|
254
249
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SingleSearchResultComponent, [{
|
|
255
250
|
type: Component,
|
|
256
|
-
args: [{ standalone: false, selector: 'mj-single-search-result', template: "<div class=\"search-result-container\">\n <!-- Content Header \u2014 matches Data Explorer layout -->\n <div class=\"content-header\">\n <div class=\"header-left\">\n <i [class]=\"EntityIcon\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ EntityInfo?.DisplayNameOrName || entity }}</h2>\n @if (SearchState === 'loading') {\n <span class=\"record-count\">Searching for \"{{ searchInput }}\"...</span>\n } @else if (SearchState === 'no-results') {\n <span class=\"record-count\">No results for \"{{ searchInput }}\"</span>\n } @else if (ResultCount > 0) {\n <span class=\"record-count\">{{ ResultCount | number }} {{ ResultCount === 1 ? 'result' : 'results' }} for \"{{ searchInput }}\"</span>\n }\n </div>\n\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"header-right\">\n <!-- New Record -->\n <button\n class=\"header-action-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"New Record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n }\n </div>\n\n <!-- Loading state -->\n @if (SearchState === 'loading') {\n <div class=\"loading-container\">\n <mj-loading text=\"Searching...\"></mj-loading>\n </div>\n }\n\n <!-- No results -->\n @if (SearchState === 'no-results') {\n <
|
|
251
|
+
args: [{ standalone: false, selector: 'mj-single-search-result', template: "<div class=\"search-result-container\">\n <!-- Content Header \u2014 matches Data Explorer layout -->\n <div class=\"content-header\">\n <div class=\"header-left\">\n <i [class]=\"EntityIcon\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ EntityInfo?.DisplayNameOrName || entity }}</h2>\n @if (SearchState === 'loading') {\n <span class=\"record-count\">Searching for \"{{ searchInput }}\"...</span>\n } @else if (SearchState === 'no-results') {\n <span class=\"record-count\">No results for \"{{ searchInput }}\"</span>\n } @else if (ResultCount > 0) {\n <span class=\"record-count\">{{ ResultCount | number }} {{ ResultCount === 1 ? 'result' : 'results' }} for \"{{ searchInput }}\"</span>\n }\n </div>\n\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"header-right\">\n <!-- New Record -->\n <button\n class=\"header-action-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"New Record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n }\n </div>\n\n <!-- Loading state -->\n @if (SearchState === 'loading') {\n <div class=\"loading-container\">\n <mj-loading text=\"Searching...\"></mj-loading>\n </div>\n }\n\n <!-- No results -->\n @if (SearchState === 'no-results') {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-magnifying-glass\">\n <p class=\"search-result-empty-message\">No results found for \"<strong>{{ searchInput }}</strong>\" in {{ entity }}</p>\n <p class=\"empty-hint\">Try a different search term or entity</p>\n </mj-empty-state>\n }\n\n <!-- Single result \u2014 auto-navigating to entity form -->\n @if (SearchState === 'single-result') {\n <mj-empty-state\n Icon=\"fa-solid fa-arrow-right\"\n Title=\"Found 1 result \u2014 opening record...\" />\n }\n\n <!-- Entity Viewer (2+ results) -->\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"viewer-container\">\n <mj-entity-viewer\n [Entity]=\"EntityInfo\"\n [Provider]=\"Provider\"\n [FilterText]=\"searchInput\"\n [Config]=\"ViewerConfig\"\n (DataLoaded)=\"OnDataLoaded($event)\"\n (RecordOpened)=\"OnRecordOpened($event)\"\n (OpenRelatedRecordRequested)=\"OnOpenRelatedRecord($event)\"\n (CreateRecordRequested)=\"OnCreateNewRecord()\">\n </mj-entity-viewer>\n </div>\n }\n</div>\n", styles: [".search-result-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n/* ============================================\n CONTENT HEADER \u2014 matches Data Explorer layout\n ============================================ */\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n/* ============================================\n HEADER RIGHT \u2014 action buttons, view mode toggle\n ============================================ */\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n/* Action Button (New Record, Export, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.header-action-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn i {\n font-size: 14px;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* ============================================\n LOADING STATE\n ============================================ */\n\n.loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 48px 0;\n}\n\n/* ============================================\n EMPTY STATE\n ============================================ */\n\n.search-result-empty-message {\n margin: 4px 0;\n font-size: 15px;\n}\n\n.empty-hint {\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n/* ============================================\n VIEWER CONTAINER\n ============================================ */\n\n.viewer-container {\n flex: 1;\n min-height: 0;\n}\n"] }]
|
|
257
252
|
}], () => [{ type: i1.NavigationService }, { type: i0.ChangeDetectorRef }], { entity: [{
|
|
258
253
|
type: Input
|
|
259
254
|
}], searchInput: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-search-result.component.js","sourceRoot":"","sources":["../../../src/lib/single-search-result/single-search-result.component.ts","../../../src/lib/single-search-result/single-search-result.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';\nimport { RunView, CompositeKey, EntityInfo } from '@memberjunction/core';\nimport { NavigationService } from '@memberjunction/ng-shared';\nimport { DataLoadedEvent, RecordOpenedEvent, EntityViewerConfig, ViewRelatedRecordNavigation } from '@memberjunction/ng-entity-viewer';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\ntype SearchState = 'loading' | 'no-results' | 'single-result' | 'viewer';\n\n@Component({\n standalone: false,\n selector: 'mj-single-search-result',\n templateUrl: './single-search-result.component.html',\n styleUrls: ['./single-search-result.component.css']\n})\nexport class SingleSearchResultComponent extends BaseAngularComponent implements OnChanges {\n @Input() public entity: string = '';\n @Input() public searchInput: string = '';\n @Output() public loadComplete = new EventEmitter<boolean>();\n @Output() public loadStarted = new EventEmitter<boolean>();\n\n public SearchState: SearchState = 'loading';\n public ResultCount = 0;\n public EntityInfo: EntityInfo | null = null;\n\n /** Resolved icon class for the entity, matching Data Explorer's format */\n public get EntityIcon(): string {\n if (this.EntityInfo?.Icon) {\n return this.formatEntityIcon(this.EntityInfo.Icon);\n }\n return 'fa-solid fa-table';\n }\n\n /** Configuration for the entity-viewer — matches the Data Explorer's setup */\n public ViewerConfig: Partial<EntityViewerConfig> = {\n showFilter: false,\n showViewModeToggle: false,\n showRecordCount: false,\n showPagination: true,\n serverSideFiltering: true,\n serverSideSorting: true,\n height: '100%'\n };\n\n constructor(\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {\n super();}\n\n ngOnChanges(changes: SimpleChanges): void {\n if ((changes['entity'] || changes['searchInput']) && this.entity && this.searchInput) {\n this.ExecuteSearch();\n }\n }\n\n /**\n * Runs a lightweight pre-query (MaxRows: 2, PK fields only) to determine result count,\n * then routes to the appropriate state: no-results, single-result auto-nav, or viewer.\n */\n private async ExecuteSearch(): Promise<void> {\n this.SearchState = 'loading';\n this.ResultCount = 0;\n this.loadStarted.emit(true);\n\n // Resolve EntityInfo early so the header can show icon + display name during loading\n const entityInfo = this.findEntityInfo();\n this.EntityInfo = entityInfo ?? null;\n this.cdr.detectChanges();\n\n if (!entityInfo) {\n this.setNoResults();\n return;\n }\n\n const result = await this.runPreQuery(entityInfo);\n if (!result.Success || result.Results.length === 0) {\n this.setNoResults();\n return;\n }\n\n if (result.Results.length === 1) {\n this.navigateToSingleResult(entityInfo, result.Results[0]);\n return;\n }\n\n // 2+ results — show the entity-viewer\n this.SearchState = 'viewer';\n this.cdr.detectChanges();\n }\n\n private findEntityInfo(): EntityInfo | undefined {\n const md = this.ProviderToUse;\n return md.Entities.find(e =>\n e.Name.trim().toLowerCase() === this.entity.trim().toLowerCase()\n );\n }\n\n private async runPreQuery(entityInfo: EntityInfo) {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const pkFields = entityInfo.PrimaryKeys.map(pk => pk.Name);\n return rv.RunView<Record<string, unknown>>({\n EntityName: this.entity,\n ExtraFilter: 'ID IS NOT NULL',\n UserSearchString: this.searchInput,\n Fields: pkFields,\n ResultType: 'simple',\n MaxRows: 2,\n });\n }\n\n private setNoResults(): void {\n this.SearchState = 'no-results';\n this.ResultCount = 0;\n this.loadComplete.emit(true);\n this.cdr.detectChanges();\n }\n\n private navigateToSingleResult(entityInfo: EntityInfo, record: Record<string, unknown>): void {\n this.SearchState = 'single-result';\n this.ResultCount = 1;\n this.cdr.detectChanges();\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(entityInfo, record);\n this.navigationService.OpenEntityRecord(entityInfo.Name, compositeKey);\n this.loadComplete.emit(true);\n }\n\n // ── Header action handlers ──\n\n public OnCreateNewRecord(): void {\n if (this.EntityInfo) {\n this.navigationService.OpenNewEntityRecord(this.EntityInfo.Name);\n }\n }\n\n // ── Entity-viewer event handlers ──\n\n public OnDataLoaded(event: DataLoadedEvent): void {\n this.ResultCount = event.totalRowCount;\n this.loadComplete.emit(true);\n this.cdr.detectChanges();\n }\n\n public OnRecordOpened(event: RecordOpenedEvent): void {\n this.navigationService.OpenEntityRecord(event.entity.Name, event.compositeKey);\n }\n\n /** Navigate to a related record requested from within a view-type renderer (e.g. a foreign-key cell). */\n public OnOpenRelatedRecord(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n this.navigationService.OpenEntityRecord(nav.entityName, CompositeKey.FromID(String(nav.recordKey)));\n }\n }\n\n /** Format entity icon to ensure proper Font Awesome class format */\n private formatEntityIcon(icon: string): string {\n if (!icon) {\n return 'fa-solid fa-table';\n }\n if (icon.startsWith('fa-solid') || icon.startsWith('fa-regular') ||\n icon.startsWith('fa-light') || icon.startsWith('fa-brands') ||\n icon.startsWith('fa ')) {\n return icon;\n }\n if (icon.startsWith('fa-')) {\n return `fa-solid ${icon}`;\n }\n return `fa-solid fa-${icon}`;\n }\n}\n","<div class=\"search-result-container\">\n <!-- Content Header — matches Data Explorer layout -->\n <div class=\"content-header\">\n <div class=\"header-left\">\n <i [class]=\"EntityIcon\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ EntityInfo?.DisplayNameOrName || entity }}</h2>\n @if (SearchState === 'loading') {\n <span class=\"record-count\">Searching for \"{{ searchInput }}\"...</span>\n } @else if (SearchState === 'no-results') {\n <span class=\"record-count\">No results for \"{{ searchInput }}\"</span>\n } @else if (ResultCount > 0) {\n <span class=\"record-count\">{{ ResultCount | number }} {{ ResultCount === 1 ? 'result' : 'results' }} for \"{{ searchInput }}\"</span>\n }\n </div>\n\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"header-right\">\n <!-- New Record -->\n <button\n class=\"header-action-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"New Record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n }\n </div>\n\n <!-- Loading state -->\n @if (SearchState === 'loading') {\n <div class=\"loading-container\">\n <mj-loading text=\"Searching...\"></mj-loading>\n </div>\n }\n\n <!-- No results -->\n @if (SearchState === 'no-results') {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-magnifying-glass empty-icon\"></i>\n <p>No results found for \"<strong>{{ searchInput }}</strong>\" in {{ entity }}</p>\n <p class=\"empty-hint\">Try a different search term or entity</p>\n </div>\n }\n\n <!-- Single result — auto-navigating to entity form -->\n @if (SearchState === 'single-result') {\n <div class=\"single-result-state\">\n <i class=\"fa-solid fa-arrow-right redirect-icon\"></i>\n <p>Found 1 result — opening record...</p>\n </div>\n }\n\n <!-- Entity Viewer (2+ results) -->\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"viewer-container\">\n <mj-entity-viewer\n [Entity]=\"EntityInfo\"\n [Provider]=\"Provider\"\n [FilterText]=\"searchInput\"\n [Config]=\"ViewerConfig\"\n (DataLoaded)=\"OnDataLoaded($event)\"\n (RecordOpened)=\"OnRecordOpened($event)\"\n (OpenRelatedRecordRequested)=\"OnOpenRelatedRecord($event)\"\n (CreateRecordRequested)=\"OnCreateNewRecord()\">\n </mj-entity-viewer>\n </div>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"single-search-result.component.js","sourceRoot":"","sources":["../../../src/lib/single-search-result/single-search-result.component.ts","../../../src/lib/single-search-result/single-search-result.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';\nimport { RunView, CompositeKey, EntityInfo } from '@memberjunction/core';\nimport { NavigationService } from '@memberjunction/ng-shared';\nimport { DataLoadedEvent, RecordOpenedEvent, EntityViewerConfig, ViewRelatedRecordNavigation } from '@memberjunction/ng-entity-viewer';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\ntype SearchState = 'loading' | 'no-results' | 'single-result' | 'viewer';\n\n@Component({\n standalone: false,\n selector: 'mj-single-search-result',\n templateUrl: './single-search-result.component.html',\n styleUrls: ['./single-search-result.component.css']\n})\nexport class SingleSearchResultComponent extends BaseAngularComponent implements OnChanges {\n @Input() public entity: string = '';\n @Input() public searchInput: string = '';\n @Output() public loadComplete = new EventEmitter<boolean>();\n @Output() public loadStarted = new EventEmitter<boolean>();\n\n public SearchState: SearchState = 'loading';\n public ResultCount = 0;\n public EntityInfo: EntityInfo | null = null;\n\n /** Resolved icon class for the entity, matching Data Explorer's format */\n public get EntityIcon(): string {\n if (this.EntityInfo?.Icon) {\n return this.formatEntityIcon(this.EntityInfo.Icon);\n }\n return 'fa-solid fa-table';\n }\n\n /** Configuration for the entity-viewer — matches the Data Explorer's setup */\n public ViewerConfig: Partial<EntityViewerConfig> = {\n showFilter: false,\n showViewModeToggle: false,\n showRecordCount: false,\n showPagination: true,\n serverSideFiltering: true,\n serverSideSorting: true,\n height: '100%'\n };\n\n constructor(\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {\n super();}\n\n ngOnChanges(changes: SimpleChanges): void {\n if ((changes['entity'] || changes['searchInput']) && this.entity && this.searchInput) {\n this.ExecuteSearch();\n }\n }\n\n /**\n * Runs a lightweight pre-query (MaxRows: 2, PK fields only) to determine result count,\n * then routes to the appropriate state: no-results, single-result auto-nav, or viewer.\n */\n private async ExecuteSearch(): Promise<void> {\n this.SearchState = 'loading';\n this.ResultCount = 0;\n this.loadStarted.emit(true);\n\n // Resolve EntityInfo early so the header can show icon + display name during loading\n const entityInfo = this.findEntityInfo();\n this.EntityInfo = entityInfo ?? null;\n this.cdr.detectChanges();\n\n if (!entityInfo) {\n this.setNoResults();\n return;\n }\n\n const result = await this.runPreQuery(entityInfo);\n if (!result.Success || result.Results.length === 0) {\n this.setNoResults();\n return;\n }\n\n if (result.Results.length === 1) {\n this.navigateToSingleResult(entityInfo, result.Results[0]);\n return;\n }\n\n // 2+ results — show the entity-viewer\n this.SearchState = 'viewer';\n this.cdr.detectChanges();\n }\n\n private findEntityInfo(): EntityInfo | undefined {\n const md = this.ProviderToUse;\n return md.Entities.find(e =>\n e.Name.trim().toLowerCase() === this.entity.trim().toLowerCase()\n );\n }\n\n private async runPreQuery(entityInfo: EntityInfo) {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const pkFields = entityInfo.PrimaryKeys.map(pk => pk.Name);\n return rv.RunView<Record<string, unknown>>({\n EntityName: this.entity,\n ExtraFilter: 'ID IS NOT NULL',\n UserSearchString: this.searchInput,\n Fields: pkFields,\n ResultType: 'simple',\n MaxRows: 2,\n });\n }\n\n private setNoResults(): void {\n this.SearchState = 'no-results';\n this.ResultCount = 0;\n this.loadComplete.emit(true);\n this.cdr.detectChanges();\n }\n\n private navigateToSingleResult(entityInfo: EntityInfo, record: Record<string, unknown>): void {\n this.SearchState = 'single-result';\n this.ResultCount = 1;\n this.cdr.detectChanges();\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(entityInfo, record);\n this.navigationService.OpenEntityRecord(entityInfo.Name, compositeKey);\n this.loadComplete.emit(true);\n }\n\n // ── Header action handlers ──\n\n public OnCreateNewRecord(): void {\n if (this.EntityInfo) {\n this.navigationService.OpenNewEntityRecord(this.EntityInfo.Name);\n }\n }\n\n // ── Entity-viewer event handlers ──\n\n public OnDataLoaded(event: DataLoadedEvent): void {\n this.ResultCount = event.totalRowCount;\n this.loadComplete.emit(true);\n this.cdr.detectChanges();\n }\n\n public OnRecordOpened(event: RecordOpenedEvent): void {\n this.navigationService.OpenEntityRecord(event.entity.Name, event.compositeKey);\n }\n\n /** Navigate to a related record requested from within a view-type renderer (e.g. a foreign-key cell). */\n public OnOpenRelatedRecord(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n this.navigationService.OpenEntityRecord(nav.entityName, CompositeKey.FromID(String(nav.recordKey)));\n }\n }\n\n /** Format entity icon to ensure proper Font Awesome class format */\n private formatEntityIcon(icon: string): string {\n if (!icon) {\n return 'fa-solid fa-table';\n }\n if (icon.startsWith('fa-solid') || icon.startsWith('fa-regular') ||\n icon.startsWith('fa-light') || icon.startsWith('fa-brands') ||\n icon.startsWith('fa ')) {\n return icon;\n }\n if (icon.startsWith('fa-')) {\n return `fa-solid ${icon}`;\n }\n return `fa-solid fa-${icon}`;\n }\n}\n","<div class=\"search-result-container\">\n <!-- Content Header — matches Data Explorer layout -->\n <div class=\"content-header\">\n <div class=\"header-left\">\n <i [class]=\"EntityIcon\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ EntityInfo?.DisplayNameOrName || entity }}</h2>\n @if (SearchState === 'loading') {\n <span class=\"record-count\">Searching for \"{{ searchInput }}\"...</span>\n } @else if (SearchState === 'no-results') {\n <span class=\"record-count\">No results for \"{{ searchInput }}\"</span>\n } @else if (ResultCount > 0) {\n <span class=\"record-count\">{{ ResultCount | number }} {{ ResultCount === 1 ? 'result' : 'results' }} for \"{{ searchInput }}\"</span>\n }\n </div>\n\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"header-right\">\n <!-- New Record -->\n <button\n class=\"header-action-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"New Record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n }\n </div>\n\n <!-- Loading state -->\n @if (SearchState === 'loading') {\n <div class=\"loading-container\">\n <mj-loading text=\"Searching...\"></mj-loading>\n </div>\n }\n\n <!-- No results -->\n @if (SearchState === 'no-results') {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-magnifying-glass\">\n <p class=\"search-result-empty-message\">No results found for \"<strong>{{ searchInput }}</strong>\" in {{ entity }}</p>\n <p class=\"empty-hint\">Try a different search term or entity</p>\n </mj-empty-state>\n }\n\n <!-- Single result — auto-navigating to entity form -->\n @if (SearchState === 'single-result') {\n <mj-empty-state\n Icon=\"fa-solid fa-arrow-right\"\n Title=\"Found 1 result — opening record...\" />\n }\n\n <!-- Entity Viewer (2+ results) -->\n @if (SearchState === 'viewer' && EntityInfo) {\n <div class=\"viewer-container\">\n <mj-entity-viewer\n [Entity]=\"EntityInfo\"\n [Provider]=\"Provider\"\n [FilterText]=\"searchInput\"\n [Config]=\"ViewerConfig\"\n (DataLoaded)=\"OnDataLoaded($event)\"\n (RecordOpened)=\"OnRecordOpened($event)\"\n (OpenRelatedRecordRequested)=\"OnOpenRelatedRecord($event)\"\n (CreateRecordRequested)=\"OnCreateNewRecord()\">\n </mj-entity-viewer>\n </div>\n }\n</div>\n"]}
|