cloud-ide-shared 1.0.74 → 1.0.78
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/fesm2022/cloud-ide-shared.mjs +79 -5
- package/fesm2022/cloud-ide-shared.mjs.map +1 -1
- package/index.d.ts +9 -0
- package/package.json +1 -1
- package/README.md +0 -63
|
@@ -725,9 +725,49 @@ class CideSharedOrgStructureComponent {
|
|
|
725
725
|
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
726
726
|
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
727
727
|
orgStructure = signal([], ...(ngDevMode ? [{ debugName: "orgStructure" }] : []));
|
|
728
|
+
/** Set of node IDs that are expanded (children visible). Default: all expanded. */
|
|
729
|
+
expandedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedIds" }] : []));
|
|
728
730
|
ngOnInit() {
|
|
729
731
|
this.loadOrgStructure();
|
|
730
732
|
}
|
|
733
|
+
/** Collect all node IDs from tree (for expand all / collapse all). */
|
|
734
|
+
getAllNodeIds(nodes) {
|
|
735
|
+
const ids = new Set();
|
|
736
|
+
const visit = (list) => {
|
|
737
|
+
list.forEach(n => {
|
|
738
|
+
if (n._id)
|
|
739
|
+
ids.add(n._id);
|
|
740
|
+
if (n.children?.length)
|
|
741
|
+
visit(n.children);
|
|
742
|
+
});
|
|
743
|
+
};
|
|
744
|
+
visit(nodes);
|
|
745
|
+
return ids;
|
|
746
|
+
}
|
|
747
|
+
isExpanded(nodeId) {
|
|
748
|
+
if (!nodeId)
|
|
749
|
+
return false;
|
|
750
|
+
return this.expandedIds().has(nodeId);
|
|
751
|
+
}
|
|
752
|
+
toggleExpand(nodeId) {
|
|
753
|
+
if (!nodeId)
|
|
754
|
+
return;
|
|
755
|
+
const next = new Set(this.expandedIds());
|
|
756
|
+
if (next.has(nodeId))
|
|
757
|
+
next.delete(nodeId);
|
|
758
|
+
else
|
|
759
|
+
next.add(nodeId);
|
|
760
|
+
this.expandedIds.set(next);
|
|
761
|
+
}
|
|
762
|
+
expandAll() {
|
|
763
|
+
this.expandedIds.set(this.getAllNodeIds(this.orgStructure()));
|
|
764
|
+
}
|
|
765
|
+
collapseAll() {
|
|
766
|
+
this.expandedIds.set(new Set());
|
|
767
|
+
}
|
|
768
|
+
hasChildren(node) {
|
|
769
|
+
return !!(node.children && node.children.length > 0);
|
|
770
|
+
}
|
|
731
771
|
/**
|
|
732
772
|
* Load organization structure
|
|
733
773
|
*/
|
|
@@ -742,6 +782,7 @@ class CideSharedOrgStructureComponent {
|
|
|
742
782
|
console.log('Built organization structure:', structure);
|
|
743
783
|
console.log('Root nodes count:', structure.length);
|
|
744
784
|
this.orgStructure.set(structure);
|
|
785
|
+
this.expandedIds.set(this.getAllNodeIds(structure));
|
|
745
786
|
}
|
|
746
787
|
else {
|
|
747
788
|
this.error.set('Failed to load organization structure');
|
|
@@ -997,7 +1038,7 @@ class CideSharedOrgStructureComponent {
|
|
|
997
1038
|
});
|
|
998
1039
|
}
|
|
999
1040
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideSharedOrgStructureComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1000
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CideSharedOrgStructureComponent, isStandalone: true, selector: "cide-shared-org-structure", inputs: { allowSwitching: { classPropertyName: "allowSwitching", publicName: "allowSwitching", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entityClick: "entityClick", entitySelect: "entitySelect", entityView: "entityView" }, ngImport: i0, template: "<!-- Organization Structure Component -->\n<div class=\"tw-flex-1 tw-overflow-auto !tw-h-full\">\n @if (loading()) {\n <div class=\"tw-flex tw-items-center !tw-h-full tw-justify-center tw-py-12\">\n <cide-ele-spinner size=\"md\"></cide-ele-spinner>\n <span class=\"tw-ml-3 tw-text-gray-600 tw-text-sm\">Loading organization structure...</span>\n </div>\n } @else if (error()) {\n <div class=\"tw-text-center tw-py-12\">\n <div\n class=\"tw-w-16 tw-h-16 tw-bg-red-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-red-500\">error</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">Error Loading Structure</h3>\n <p class=\"tw-text-gray-600 tw-mb-4\">{{ error() }}</p>\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\n <cide-ele-icon>refresh</cide-ele-icon>\n Try Again\n </button>\n </div>\n } @else if (orgStructure().length === 0) {\n <div class=\"tw-text-center tw-py-12\">\n <div\n class=\"tw-w-16 tw-h-16 tw-bg-gray-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">account_tree</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">No Entities Found</h3>\n <p class=\"tw-text-gray-600 tw-mb-4\">No entities are available to display in the organization structure.</p>\n @if (mode() === 'view') {\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\n <cide-ele-icon>add</cide-ele-icon>\n Create First Entity\n </button>\n }\n </div>\n } @else {\n <!-- Organization Chart Container -->\n <div class=\"tw-relative tw-h-full tw-bg-gray-50 tw-py-8 org-chart-container\">\n <!-- Chart Content with Background Pattern -->\n <div class=\"tw-relative tw-z-10 tw-min-w-max tw-px-4 org-chart-content org-chart-content-with-bg\">\n <div class=\"tree\">\n @for (rootNode of orgStructure(); track rootNode._id) {\n <!-- Root nodes don't need top lines, but using wrapper is fine as they are not inside .tree-children -->\n <div class=\"tree-node-wrapper tw-mb-12\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n\n<!-- Entity Node Template (Recursive) -->\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\n <div class=\"tree-node-content\">\n\n <!-- Entity Card -->\n <div class=\"tw-bg-white tw-shadow-lg tw-rounded-lg tw-p-4 entity-card tw-border-t-4 tw-cursor-pointer\"\n [class.level-0]=\"level === 0\" [class.level-1]=\"level === 1\" [class.level-2]=\"level === 2\"\n [class.level-3]=\"level === 3\" [class.level-4]=\"level === 4\" [class.level-5]=\"level === 5\"\n (click)=\"viewEntity(node._id)\">\n\n <!-- Card Content -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Avatar -->\n <div\n class=\"tw-w-12 tw-h-12 tw-bg-purple-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-flex-shrink-0\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-purple-600\">person</cide-ele-icon>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex-1 tw-min-w-0\">\n <h3\n class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis\"\n [cideEleTooltip]=\"node.syen_name || ''\" [tooltipPlacement]=\"'top'\" [tooltipType]=\"'default'\">{{\n node.syen_name }}</h3>\n <p class=\"tw-text-xs tw-text-gray-600 tw-mt-1\">{{ node.syen_entity_code }}</p>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ node.syen_entity_type_sygms }}</p>\n </div>\n </div>\n\n <!-- Action Icons -->\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mt-3\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <!-- Icons (unchanged) -->\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">phone</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">email</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-100 tw-flex tw-items-center tw-justify-center tw-text-blue-600 hover:tw-bg-blue-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">attach_money</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">description</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">more_horiz</cide-ele-icon>\n </button>\n </div>\n\n <!-- Status Badge -->\n <div class=\"tw-flex-shrink-0\">\n @if (node.syen_isactive) {\n <div\n class=\"tw-inline-flex tw-items-center tw-px-1.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-green-500 tw-rounded-full tw-mr-1\"></div>\n Active\n </div>\n } @else {\n <div\n class=\"tw-inline-flex tw-items-center tw-px-1.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800\">\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-red-500 tw-rounded-full tw-mr-1\"></div>\n Inactive\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Connector line extending downwards from parent -->\n @if (node.children && node.children.length > 0) {\n <div class=\"min-h-connector\"></div>\n }\n </div>\n\n <!-- Recursive Children Container -->\n @if (node.children && node.children.length > 0) {\n <div class=\"tree-children\">\n @for (child of node.children; track child._id) {\n <div class=\"tree-node-wrapper\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\n </div>\n }\n </div>\n }\n</ng-template>", styles: [".org-chart-container{overflow:auto;height:100%;position:relative;padding-top:2rem}.org-chart-content{min-width:max-content;min-height:max-content;padding:0 1rem 4rem;margin:0 auto;display:block}.org-chart-content-with-bg{position:relative}.org-chart-content-with-bg:before{content:\"\";position:absolute;inset:0;opacity:.3;pointer-events:none;background-image:radial-gradient(circle,#e5e7eb 1px,transparent 1px);background-size:20px 20px;background-repeat:repeat;z-index:-1}.tree{display:flex;flex-direction:column;align-items:center}.tree-children{display:flex;flex-direction:row;justify-content:center;position:relative}.tree-node-wrapper{display:flex;flex-direction:column;align-items:center;position:relative;padding:20px 1rem 0}.tree-node-wrapper:before{content:\"\";position:absolute;top:0;left:50%;border-left:2px solid #9333ea;width:0;height:20px;z-index:1}.tree-node-wrapper:after{content:\"\";position:absolute;top:0;right:50%;border-top:2px solid #9333ea;width:50%;height:20px;z-index:0}.tree-children>.tree-node-wrapper:before{height:20px}.tree-children>.tree-node-wrapper:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:20px;border-top:2px solid #9333ea;border-left:0;right:auto}.tree-children>.tree-node-wrapper:first-child:after{left:50%;width:50%;border-top:2px solid #9333ea}.tree-children>.tree-node-wrapper:last-child:after{left:0;width:50%;border-top:2px solid #9333ea}.tree-children>.tree-node-wrapper:only-child:after{display:none}.tree-children>.tree-node-wrapper:only-child:before{height:20px}.tree-node-content{position:relative;z-index:2;margin-bottom:0}.min-h-connector{height:20px;width:2px;background-color:#9333ea;margin:0 auto}.entity-card{width:18rem;transition:all .2s ease-in-out;flex-shrink:0}.entity-card:hover{transform:translateY(-2px) scale(1.02);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.connection-dot{width:6px;height:6px;background-color:#9333ea;border-radius:50%;position:absolute;top:-3px;left:50%;transform:translate(-50%);z-index:5}@media (max-width: 1400px){.entity-card{width:16rem}}@media (max-width: 1200px){.entity-card{width:14rem}}@media (max-width: 992px){.entity-card{width:13rem}}.level-0{border-top-color:#3b82f6!important}.level-1{border-top-color:#f59e0b!important}.level-2{border-top-color:#10b981!important}.level-3{border-top-color:#8b5cf6!important}.level-4{border-top-color:#ef4444!important}.level-5{border-top-color:#06b6d4!important}.org-chart-container::-webkit-scrollbar{height:8px;width:8px}.org-chart-container::-webkit-scrollbar-track{background:#f1f5f9}.org-chart-container::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.org-chart-container::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated", "adaptive"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSpinnerComponent, selector: "cide-ele-spinner", inputs: ["size", "type"] }, { kind: "directive", type: TooltipDirective, selector: "[cideEleTooltip]", inputs: ["cideEleTooltip", "tooltipColor", "tooltipBg", "tooltipPlacement", "tooltipType", "tooltipDelay", "tooltipDir", "tooltipShowArrow", "tooltipMultiline", "tooltipMaxWidth", "tooltipInteractive", "tooltipClass"] }] });
|
|
1041
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CideSharedOrgStructureComponent, isStandalone: true, selector: "cide-shared-org-structure", inputs: { allowSwitching: { classPropertyName: "allowSwitching", publicName: "allowSwitching", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entityClick: "entityClick", entitySelect: "entitySelect", entityView: "entityView" }, ngImport: i0, template: "<!-- Organization Structure Component -->\n<div class=\"org-structure tw-flex tw-flex-col tw-h-full tw-overflow-hidden\">\n @if (loading()) {\n <div class=\"org-structure__loading tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-spinner size=\"lg\"></cide-ele-spinner>\n <span class=\"tw-text-sm tw-text-slate-500 tw-font-medium\">Loading organization structure\u2026</span>\n </div>\n </div>\n } @else if (error()) {\n <div class=\"org-structure__error tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"org-structure__error-card tw-text-center tw-max-w-md tw-px-6\">\n <div class=\"org-structure__error-icon tw-w-14 tw-h-14 tw-rounded-2xl tw-bg-red-100 tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-7 tw-h-7 tw-text-red-600\">error</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-semibold tw-text-slate-900 tw-mb-2\">Error loading structure</h3>\n <p class=\"tw-text-slate-600 tw-mb-6\">{{ error() }}</p>\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-mr-2\">refresh</cide-ele-icon>\n Try again\n </button>\n </div>\n </div>\n } @else if (orgStructure().length === 0) {\n <div class=\"org-structure__empty tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"tw-text-center tw-max-w-md tw-px-6\">\n <div class=\"tw-w-16 tw-h-16 tw-rounded-2xl tw-bg-slate-100 tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-slate-400\">account_tree</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-semibold tw-text-slate-900 tw-mb-2\">No entities found</h3>\n <p class=\"tw-text-slate-600 tw-mb-6\">No entities are available to display in the organization structure.</p>\n @if (mode() === 'view') {\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-mr-2\">add</cide-ele-icon>\n Create first entity\n </button>\n }\n </div>\n </div>\n } @else {\n <!-- Toolbar: title + Expand all / Collapse all -->\n <div class=\"org-structure__toolbar\">\n <div class=\"org-structure__toolbar-inner\">\n <h2 class=\"org-structure__title\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-mr-2 tw-text-indigo-500\">account_tree</cide-ele-icon>\n Organization structure\n </h2>\n <div class=\"org-structure__actions\">\n <button type=\"button\" class=\"org-structure__btn\" (click)=\"expandAll()\"\n cideEleTooltip=\"Expand all\" tooltipPlacement=\"bottom\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">unfold_more</cide-ele-icon>\n <span class=\"tw-ml-1.5 tw-hidden sm:tw-inline\">Expand all</span>\n </button>\n <button type=\"button\" class=\"org-structure__btn\" (click)=\"collapseAll()\"\n cideEleTooltip=\"Collapse all\" tooltipPlacement=\"bottom\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">unfold_less</cide-ele-icon>\n <span class=\"tw-ml-1.5 tw-hidden sm:tw-inline\">Collapse all</span>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Chart area -->\n <div class=\"org-structure__chart\">\n <div class=\"org-structure__chart-inner\">\n <div class=\"org-tree\">\n @for (rootNode of orgStructure(); track rootNode._id) {\n <div class=\"org-tree__branch\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n\n<!-- Entity node (recursive) -->\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\n <div class=\"org-node\">\n <div class=\"org-node__card\"\n [class.org-node__card--root]=\"level === 0\"\n [class.org-node__card--level-1]=\"level === 1\"\n [class.org-node__card--level-2]=\"level === 2\"\n [class.org-node__card--level-3]=\"level >= 3\"\n (click)=\"viewEntity(node._id)\">\n <div class=\"org-node__main\">\n @if (hasChildren(node)) {\n <button type=\"button\" class=\"org-node__expand\"\n (click)=\"toggleExpand(node._id); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isExpanded(node._id)\"\n cideEleTooltip=\"{{ isExpanded(node._id) ? 'Collapse' : 'Expand' }}\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"org-node__expand-icon\" [class.org-node__expand-icon--open]=\"isExpanded(node._id)\">expand_more</cide-ele-icon>\n </button>\n } @else {\n <span class=\"org-node__expand-placeholder\"></span>\n }\n <div class=\"org-node__avatar\">\n <span class=\"org-node__avatar-text\">{{ (node.syen_name || '?').substring(0, 2).toUpperCase() }}</span>\n </div>\n <div class=\"org-node__info\">\n <h3 class=\"org-node__name\" [cideEleTooltip]=\"node.syen_name || ''\" tooltipPlacement=\"top\" tooltipType=\"default\">\n {{ node.syen_name }}\n </h3>\n <p class=\"org-node__meta\">{{ node.syen_entity_code }}</p>\n @if (node.entity_type_details?.sygms_title) {\n <p class=\"org-node__type\">{{ node.entity_type_details.sygms_title }}</p>\n } @else if (node.syen_entity_type_sygms) {\n <p class=\"org-node__type\">{{ node.syen_entity_type_sygms }}</p>\n }\n </div>\n <div class=\"org-node__badge\">\n @if (node.syen_isactive) {\n <span class=\"org-node__status org-node__status--active\">Active</span>\n } @else {\n <span class=\"org-node__status org-node__status--inactive\">Inactive</span>\n }\n </div>\n </div>\n @if (showActions()) {\n <div class=\"org-node__actions\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"Phone\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">phone</cide-ele-icon>\n </button>\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"Email\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">email</cide-ele-icon>\n </button>\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"More\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">more_horiz</cide-ele-icon>\n </button>\n </div>\n }\n </div>\n\n @if (node.children && node.children.length > 0 && isExpanded(node._id)) {\n <div class=\"org-node__connector\"></div>\n }\n </div>\n\n @if (node.children && node.children.length > 0 && isExpanded(node._id)) {\n <div class=\"org-tree__children\">\n @for (child of node.children; track child._id) {\n <div class=\"org-tree__branch\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.org-structure{background:#f8fafc}.org-structure__toolbar{flex-shrink:0;background:#fff;border-bottom:1px solid #e2e8f0;padding:.75rem 1.25rem;position:sticky;top:0;z-index:10}.org-structure__toolbar-inner{display:flex;align-items:center;justify-content:space-between;gap:1rem;max-width:100%}.org-structure__title{display:flex;align-items:center;margin:0;font-size:1.125rem;font-weight:600;color:#0f172a;letter-spacing:-.01em}.org-structure__actions{display:flex;align-items:center;gap:.5rem}.org-structure__btn{display:inline-flex;align-items:center;padding:.5rem .75rem;font-size:.8125rem;font-weight:500;color:#475569;background:#f1f5f9;border:none;border-radius:8px;cursor:pointer;transition:color .15s,background .15s,box-shadow .15s}.org-structure__btn:hover{color:#6366f1;background:#eef2ff}.org-structure__btn:active{background:#e0e7ff}.org-structure__chart{flex:1;overflow:auto;padding:1.5rem 1rem 3rem}.org-structure__chart-inner{min-width:max-content;min-height:max-content;position:relative}.org-tree{display:flex;flex-direction:column;align-items:center}.org-tree__branch{display:flex;flex-direction:column;align-items:center;position:relative;padding-top:0}.org-tree__children{display:flex;flex-direction:row;justify-content:center;align-items:flex-start;position:relative;padding-top:0;gap:0 1.5rem}.org-node__connector{width:2px;height:20px;background:#6366f1;margin:0 auto;flex-shrink:0}.org-tree__children>.org-tree__branch{position:relative;padding-top:20px}.org-tree__children>.org-tree__branch:before{content:\"\";position:absolute;top:0;left:50%;width:0;height:20px;border-left:2px solid #6366f1;z-index:0}.org-tree__children>.org-tree__branch:after{content:\"\";position:absolute;top:0;left:0;right:0;height:20px;border-top:2px solid #6366f1;z-index:0}.org-tree__children>.org-tree__branch:first-child:after{left:50%;width:50%}.org-tree__children>.org-tree__branch:last-child:after{left:0;width:50%}.org-tree__children>.org-tree__branch:only-child:after{display:none}.org-tree__children>.org-tree__branch:only-child:before{height:20px}.org-node{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;margin-bottom:0}.org-node__card{width:100%;min-width:280px;max-width:320px;background:#fff;border-radius:12px;box-shadow:0 1px 3px #0000000f;border:1px solid #e2e8f0;padding:.875rem 1rem;cursor:pointer;transition:box-shadow .2s ease,transform .2s ease,border-color .2s ease}.org-node__card:hover{box-shadow:0 10px 40px -10px #6366f133,0 4px 12px -4px #00000014;border-color:#6366f140}.org-node__card:active{transform:scale(.995)}.org-node__card--root{border-left:3px solid #6366f1}.org-node__card--level-1{border-left:3px solid #8b5cf6}.org-node__card--level-2{border-left:3px solid #06b6d4}.org-node__card--level-3{border-left:3px solid #10b981}.org-node__main{display:flex;align-items:center;gap:.75rem}.org-node__expand{flex-shrink:0;width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;margin:-4px 0;background:#f1f5f9;border:none;border-radius:6px;cursor:pointer;color:#64748b;transition:background .15s,color .15s,transform .2s ease}.org-node__expand:hover{background:#e0e7ff;color:#6366f1}.org-node__expand-icon{transition:transform .25s ease;font-size:1.25rem}.org-node__expand-icon--open{transform:rotate(0)}.org-node__expand:not([aria-expanded=true]) .org-node__expand-icon{transform:rotate(-90deg)}.org-node__expand-placeholder{width:28px;flex-shrink:0;display:inline-block}.org-node__avatar{width:40px;height:40px;flex-shrink:0;border-radius:10px;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center}.org-node__avatar-text{font-size:.75rem;font-weight:700;color:#fff;letter-spacing:.02em}.org-node__info{flex:1;min-width:0}.org-node__name{margin:0;font-size:.9375rem;font-weight:600;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}.org-node__meta{margin:.125rem 0 0;font-size:.75rem;color:#64748b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-node__type{margin:.125rem 0 0;font-size:.6875rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.04em}.org-node__badge{flex-shrink:0}.org-node__status{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:600;border-radius:6px;text-transform:uppercase;letter-spacing:.03em}.org-node__status--active{background:#dcfce7;color:#166534}.org-node__status--inactive{background:#fee2e2;color:#991b1b}.org-node__actions{display:flex;align-items:center;gap:.25rem;margin-top:.75rem;padding-top:.75rem;border-top:1px solid #f1f5f9}.org-node__action{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:6px;color:#94a3b8;cursor:pointer;transition:background .15s,color .15s}.org-node__action:hover{background:#f1f5f9;color:#6366f1}.org-structure__loading,.org-structure__error,.org-structure__empty{background:#f8fafc}.org-structure__error-icon{box-shadow:0 4px 12px #ef444426}.org-structure__chart::-webkit-scrollbar{width:8px;height:8px}.org-structure__chart::-webkit-scrollbar-track{background:#f1f5f9;border-radius:4px}.org-structure__chart::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.org-structure__chart::-webkit-scrollbar-thumb:hover{background:#94a3b8}@media (max-width: 640px){.org-node__card{min-width:260px;max-width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated", "adaptive"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip", "active", "name"] }, { kind: "component", type: CideSpinnerComponent, selector: "cide-ele-spinner", inputs: ["size", "type"] }, { kind: "directive", type: TooltipDirective, selector: "[cideEleTooltip]", inputs: ["cideEleTooltip", "tooltipColor", "tooltipBg", "tooltipPlacement", "tooltipType", "tooltipDelay", "tooltipDir", "tooltipShowArrow", "tooltipMultiline", "tooltipMaxWidth", "tooltipInteractive", "tooltipClass"] }] });
|
|
1001
1042
|
}
|
|
1002
1043
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideSharedOrgStructureComponent, decorators: [{
|
|
1003
1044
|
type: Component,
|
|
@@ -1007,7 +1048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1007
1048
|
CideIconComponent,
|
|
1008
1049
|
CideSpinnerComponent,
|
|
1009
1050
|
TooltipDirective
|
|
1010
|
-
], template: "<!-- Organization Structure Component -->\n<div class=\"tw-flex-1 tw-overflow-auto !tw-h-full\">\n @if (loading()) {\n <div class=\"tw-flex tw-items-center !tw-h-full tw-justify-center tw-py-12\">\n <cide-ele-spinner size=\"md\"></cide-ele-spinner>\n <span class=\"tw-ml-3 tw-text-gray-600 tw-text-sm\">Loading organization structure...</span>\n </div>\n } @else if (error()) {\n <div class=\"tw-text-center tw-py-12\">\n <div\n class=\"tw-w-16 tw-h-16 tw-bg-red-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-red-500\">error</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">Error Loading Structure</h3>\n <p class=\"tw-text-gray-600 tw-mb-4\">{{ error() }}</p>\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\n <cide-ele-icon>refresh</cide-ele-icon>\n Try Again\n </button>\n </div>\n } @else if (orgStructure().length === 0) {\n <div class=\"tw-text-center tw-py-12\">\n <div\n class=\"tw-w-16 tw-h-16 tw-bg-gray-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">account_tree</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">No Entities Found</h3>\n <p class=\"tw-text-gray-600 tw-mb-4\">No entities are available to display in the organization structure.</p>\n @if (mode() === 'view') {\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\n <cide-ele-icon>add</cide-ele-icon>\n Create First Entity\n </button>\n }\n </div>\n } @else {\n <!-- Organization Chart Container -->\n <div class=\"tw-relative tw-h-full tw-bg-gray-50 tw-py-8 org-chart-container\">\n <!-- Chart Content with Background Pattern -->\n <div class=\"tw-relative tw-z-10 tw-min-w-max tw-px-4 org-chart-content org-chart-content-with-bg\">\n <div class=\"tree\">\n @for (rootNode of orgStructure(); track rootNode._id) {\n <!-- Root nodes don't need top lines, but using wrapper is fine as they are not inside .tree-children -->\n <div class=\"tree-node-wrapper tw-mb-12\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n\n<!-- Entity Node Template (Recursive) -->\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\n <div class=\"tree-node-content\">\n\n <!-- Entity Card -->\n <div class=\"tw-bg-white tw-shadow-lg tw-rounded-lg tw-p-4 entity-card tw-border-t-4 tw-cursor-pointer\"\n [class.level-0]=\"level === 0\" [class.level-1]=\"level === 1\" [class.level-2]=\"level === 2\"\n [class.level-3]=\"level === 3\" [class.level-4]=\"level === 4\" [class.level-5]=\"level === 5\"\n (click)=\"viewEntity(node._id)\">\n\n <!-- Card Content -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Avatar -->\n <div\n class=\"tw-w-12 tw-h-12 tw-bg-purple-100 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-flex-shrink-0\">\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-purple-600\">person</cide-ele-icon>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex-1 tw-min-w-0\">\n <h3\n class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis\"\n [cideEleTooltip]=\"node.syen_name || ''\" [tooltipPlacement]=\"'top'\" [tooltipType]=\"'default'\">{{\n node.syen_name }}</h3>\n <p class=\"tw-text-xs tw-text-gray-600 tw-mt-1\">{{ node.syen_entity_code }}</p>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ node.syen_entity_type_sygms }}</p>\n </div>\n </div>\n\n <!-- Action Icons -->\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mt-3\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <!-- Icons (unchanged) -->\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">phone</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">email</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-100 tw-flex tw-items-center tw-justify-center tw-text-blue-600 hover:tw-bg-blue-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">attach_money</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">description</cide-ele-icon>\n </button>\n <button\n class=\"tw-w-6 tw-h-6 tw-rounded-full tw-bg-gray-100 tw-flex tw-items-center tw-justify-center tw-text-gray-600 hover:tw-bg-gray-200 tw-transition-colors\">\n <cide-ele-icon class=\"tw-text-xs\">more_horiz</cide-ele-icon>\n </button>\n </div>\n\n <!-- Status Badge -->\n <div class=\"tw-flex-shrink-0\">\n @if (node.syen_isactive) {\n <div\n class=\"tw-inline-flex tw-items-center tw-px-1.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-green-500 tw-rounded-full tw-mr-1\"></div>\n Active\n </div>\n } @else {\n <div\n class=\"tw-inline-flex tw-items-center tw-px-1.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800\">\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-red-500 tw-rounded-full tw-mr-1\"></div>\n Inactive\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Connector line extending downwards from parent -->\n @if (node.children && node.children.length > 0) {\n <div class=\"min-h-connector\"></div>\n }\n </div>\n\n <!-- Recursive Children Container -->\n @if (node.children && node.children.length > 0) {\n <div class=\"tree-children\">\n @for (child of node.children; track child._id) {\n <div class=\"tree-node-wrapper\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\n </div>\n }\n </div>\n }\n</ng-template>", styles: [".org-chart-container{overflow:auto;height:100%;position:relative;padding-top:2rem}.org-chart-content{min-width:max-content;min-height:max-content;padding:0 1rem 4rem;margin:0 auto;display:block}.org-chart-content-with-bg{position:relative}.org-chart-content-with-bg:before{content:\"\";position:absolute;inset:0;opacity:.3;pointer-events:none;background-image:radial-gradient(circle,#e5e7eb 1px,transparent 1px);background-size:20px 20px;background-repeat:repeat;z-index:-1}.tree{display:flex;flex-direction:column;align-items:center}.tree-children{display:flex;flex-direction:row;justify-content:center;position:relative}.tree-node-wrapper{display:flex;flex-direction:column;align-items:center;position:relative;padding:20px 1rem 0}.tree-node-wrapper:before{content:\"\";position:absolute;top:0;left:50%;border-left:2px solid #9333ea;width:0;height:20px;z-index:1}.tree-node-wrapper:after{content:\"\";position:absolute;top:0;right:50%;border-top:2px solid #9333ea;width:50%;height:20px;z-index:0}.tree-children>.tree-node-wrapper:before{height:20px}.tree-children>.tree-node-wrapper:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:20px;border-top:2px solid #9333ea;border-left:0;right:auto}.tree-children>.tree-node-wrapper:first-child:after{left:50%;width:50%;border-top:2px solid #9333ea}.tree-children>.tree-node-wrapper:last-child:after{left:0;width:50%;border-top:2px solid #9333ea}.tree-children>.tree-node-wrapper:only-child:after{display:none}.tree-children>.tree-node-wrapper:only-child:before{height:20px}.tree-node-content{position:relative;z-index:2;margin-bottom:0}.min-h-connector{height:20px;width:2px;background-color:#9333ea;margin:0 auto}.entity-card{width:18rem;transition:all .2s ease-in-out;flex-shrink:0}.entity-card:hover{transform:translateY(-2px) scale(1.02);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.connection-dot{width:6px;height:6px;background-color:#9333ea;border-radius:50%;position:absolute;top:-3px;left:50%;transform:translate(-50%);z-index:5}@media (max-width: 1400px){.entity-card{width:16rem}}@media (max-width: 1200px){.entity-card{width:14rem}}@media (max-width: 992px){.entity-card{width:13rem}}.level-0{border-top-color:#3b82f6!important}.level-1{border-top-color:#f59e0b!important}.level-2{border-top-color:#10b981!important}.level-3{border-top-color:#8b5cf6!important}.level-4{border-top-color:#ef4444!important}.level-5{border-top-color:#06b6d4!important}.org-chart-container::-webkit-scrollbar{height:8px;width:8px}.org-chart-container::-webkit-scrollbar-track{background:#f1f5f9}.org-chart-container::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.org-chart-container::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"] }]
|
|
1051
|
+
], template: "<!-- Organization Structure Component -->\n<div class=\"org-structure tw-flex tw-flex-col tw-h-full tw-overflow-hidden\">\n @if (loading()) {\n <div class=\"org-structure__loading tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-spinner size=\"lg\"></cide-ele-spinner>\n <span class=\"tw-text-sm tw-text-slate-500 tw-font-medium\">Loading organization structure\u2026</span>\n </div>\n </div>\n } @else if (error()) {\n <div class=\"org-structure__error tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"org-structure__error-card tw-text-center tw-max-w-md tw-px-6\">\n <div class=\"org-structure__error-icon tw-w-14 tw-h-14 tw-rounded-2xl tw-bg-red-100 tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-7 tw-h-7 tw-text-red-600\">error</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-semibold tw-text-slate-900 tw-mb-2\">Error loading structure</h3>\n <p class=\"tw-text-slate-600 tw-mb-6\">{{ error() }}</p>\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-mr-2\">refresh</cide-ele-icon>\n Try again\n </button>\n </div>\n </div>\n } @else if (orgStructure().length === 0) {\n <div class=\"org-structure__empty tw-flex tw-items-center tw-justify-center tw-flex-1 tw-py-16\">\n <div class=\"tw-text-center tw-max-w-md tw-px-6\">\n <div class=\"tw-w-16 tw-h-16 tw-rounded-2xl tw-bg-slate-100 tw-flex tw-items-center tw-justify-center tw-mx-auto tw-mb-4\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-slate-400\">account_tree</cide-ele-icon>\n </div>\n <h3 class=\"tw-text-lg tw-font-semibold tw-text-slate-900 tw-mb-2\">No entities found</h3>\n <p class=\"tw-text-slate-600 tw-mb-6\">No entities are available to display in the organization structure.</p>\n @if (mode() === 'view') {\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-mr-2\">add</cide-ele-icon>\n Create first entity\n </button>\n }\n </div>\n </div>\n } @else {\n <!-- Toolbar: title + Expand all / Collapse all -->\n <div class=\"org-structure__toolbar\">\n <div class=\"org-structure__toolbar-inner\">\n <h2 class=\"org-structure__title\">\n <cide-ele-icon class=\"tw-w-5 tw-h-5 tw-mr-2 tw-text-indigo-500\">account_tree</cide-ele-icon>\n Organization structure\n </h2>\n <div class=\"org-structure__actions\">\n <button type=\"button\" class=\"org-structure__btn\" (click)=\"expandAll()\"\n cideEleTooltip=\"Expand all\" tooltipPlacement=\"bottom\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">unfold_more</cide-ele-icon>\n <span class=\"tw-ml-1.5 tw-hidden sm:tw-inline\">Expand all</span>\n </button>\n <button type=\"button\" class=\"org-structure__btn\" (click)=\"collapseAll()\"\n cideEleTooltip=\"Collapse all\" tooltipPlacement=\"bottom\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">unfold_less</cide-ele-icon>\n <span class=\"tw-ml-1.5 tw-hidden sm:tw-inline\">Collapse all</span>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Chart area -->\n <div class=\"org-structure__chart\">\n <div class=\"org-structure__chart-inner\">\n <div class=\"org-tree\">\n @for (rootNode of orgStructure(); track rootNode._id) {\n <div class=\"org-tree__branch\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n\n<!-- Entity node (recursive) -->\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\n <div class=\"org-node\">\n <div class=\"org-node__card\"\n [class.org-node__card--root]=\"level === 0\"\n [class.org-node__card--level-1]=\"level === 1\"\n [class.org-node__card--level-2]=\"level === 2\"\n [class.org-node__card--level-3]=\"level >= 3\"\n (click)=\"viewEntity(node._id)\">\n <div class=\"org-node__main\">\n @if (hasChildren(node)) {\n <button type=\"button\" class=\"org-node__expand\"\n (click)=\"toggleExpand(node._id); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isExpanded(node._id)\"\n cideEleTooltip=\"{{ isExpanded(node._id) ? 'Collapse' : 'Expand' }}\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"org-node__expand-icon\" [class.org-node__expand-icon--open]=\"isExpanded(node._id)\">expand_more</cide-ele-icon>\n </button>\n } @else {\n <span class=\"org-node__expand-placeholder\"></span>\n }\n <div class=\"org-node__avatar\">\n <span class=\"org-node__avatar-text\">{{ (node.syen_name || '?').substring(0, 2).toUpperCase() }}</span>\n </div>\n <div class=\"org-node__info\">\n <h3 class=\"org-node__name\" [cideEleTooltip]=\"node.syen_name || ''\" tooltipPlacement=\"top\" tooltipType=\"default\">\n {{ node.syen_name }}\n </h3>\n <p class=\"org-node__meta\">{{ node.syen_entity_code }}</p>\n @if (node.entity_type_details?.sygms_title) {\n <p class=\"org-node__type\">{{ node.entity_type_details.sygms_title }}</p>\n } @else if (node.syen_entity_type_sygms) {\n <p class=\"org-node__type\">{{ node.syen_entity_type_sygms }}</p>\n }\n </div>\n <div class=\"org-node__badge\">\n @if (node.syen_isactive) {\n <span class=\"org-node__status org-node__status--active\">Active</span>\n } @else {\n <span class=\"org-node__status org-node__status--inactive\">Inactive</span>\n }\n </div>\n </div>\n @if (showActions()) {\n <div class=\"org-node__actions\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"Phone\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">phone</cide-ele-icon>\n </button>\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"Email\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">email</cide-ele-icon>\n </button>\n <button type=\"button\" class=\"org-node__action\" cideEleTooltip=\"More\" tooltipPlacement=\"top\" tooltipType=\"default\">\n <cide-ele-icon class=\"tw-w-3.5 tw-h-3.5\">more_horiz</cide-ele-icon>\n </button>\n </div>\n }\n </div>\n\n @if (node.children && node.children.length > 0 && isExpanded(node._id)) {\n <div class=\"org-node__connector\"></div>\n }\n </div>\n\n @if (node.children && node.children.length > 0 && isExpanded(node._id)) {\n <div class=\"org-tree__children\">\n @for (child of node.children; track child._id) {\n <div class=\"org-tree__branch\">\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.org-structure{background:#f8fafc}.org-structure__toolbar{flex-shrink:0;background:#fff;border-bottom:1px solid #e2e8f0;padding:.75rem 1.25rem;position:sticky;top:0;z-index:10}.org-structure__toolbar-inner{display:flex;align-items:center;justify-content:space-between;gap:1rem;max-width:100%}.org-structure__title{display:flex;align-items:center;margin:0;font-size:1.125rem;font-weight:600;color:#0f172a;letter-spacing:-.01em}.org-structure__actions{display:flex;align-items:center;gap:.5rem}.org-structure__btn{display:inline-flex;align-items:center;padding:.5rem .75rem;font-size:.8125rem;font-weight:500;color:#475569;background:#f1f5f9;border:none;border-radius:8px;cursor:pointer;transition:color .15s,background .15s,box-shadow .15s}.org-structure__btn:hover{color:#6366f1;background:#eef2ff}.org-structure__btn:active{background:#e0e7ff}.org-structure__chart{flex:1;overflow:auto;padding:1.5rem 1rem 3rem}.org-structure__chart-inner{min-width:max-content;min-height:max-content;position:relative}.org-tree{display:flex;flex-direction:column;align-items:center}.org-tree__branch{display:flex;flex-direction:column;align-items:center;position:relative;padding-top:0}.org-tree__children{display:flex;flex-direction:row;justify-content:center;align-items:flex-start;position:relative;padding-top:0;gap:0 1.5rem}.org-node__connector{width:2px;height:20px;background:#6366f1;margin:0 auto;flex-shrink:0}.org-tree__children>.org-tree__branch{position:relative;padding-top:20px}.org-tree__children>.org-tree__branch:before{content:\"\";position:absolute;top:0;left:50%;width:0;height:20px;border-left:2px solid #6366f1;z-index:0}.org-tree__children>.org-tree__branch:after{content:\"\";position:absolute;top:0;left:0;right:0;height:20px;border-top:2px solid #6366f1;z-index:0}.org-tree__children>.org-tree__branch:first-child:after{left:50%;width:50%}.org-tree__children>.org-tree__branch:last-child:after{left:0;width:50%}.org-tree__children>.org-tree__branch:only-child:after{display:none}.org-tree__children>.org-tree__branch:only-child:before{height:20px}.org-node{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;margin-bottom:0}.org-node__card{width:100%;min-width:280px;max-width:320px;background:#fff;border-radius:12px;box-shadow:0 1px 3px #0000000f;border:1px solid #e2e8f0;padding:.875rem 1rem;cursor:pointer;transition:box-shadow .2s ease,transform .2s ease,border-color .2s ease}.org-node__card:hover{box-shadow:0 10px 40px -10px #6366f133,0 4px 12px -4px #00000014;border-color:#6366f140}.org-node__card:active{transform:scale(.995)}.org-node__card--root{border-left:3px solid #6366f1}.org-node__card--level-1{border-left:3px solid #8b5cf6}.org-node__card--level-2{border-left:3px solid #06b6d4}.org-node__card--level-3{border-left:3px solid #10b981}.org-node__main{display:flex;align-items:center;gap:.75rem}.org-node__expand{flex-shrink:0;width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;margin:-4px 0;background:#f1f5f9;border:none;border-radius:6px;cursor:pointer;color:#64748b;transition:background .15s,color .15s,transform .2s ease}.org-node__expand:hover{background:#e0e7ff;color:#6366f1}.org-node__expand-icon{transition:transform .25s ease;font-size:1.25rem}.org-node__expand-icon--open{transform:rotate(0)}.org-node__expand:not([aria-expanded=true]) .org-node__expand-icon{transform:rotate(-90deg)}.org-node__expand-placeholder{width:28px;flex-shrink:0;display:inline-block}.org-node__avatar{width:40px;height:40px;flex-shrink:0;border-radius:10px;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center}.org-node__avatar-text{font-size:.75rem;font-weight:700;color:#fff;letter-spacing:.02em}.org-node__info{flex:1;min-width:0}.org-node__name{margin:0;font-size:.9375rem;font-weight:600;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}.org-node__meta{margin:.125rem 0 0;font-size:.75rem;color:#64748b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.org-node__type{margin:.125rem 0 0;font-size:.6875rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.04em}.org-node__badge{flex-shrink:0}.org-node__status{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:600;border-radius:6px;text-transform:uppercase;letter-spacing:.03em}.org-node__status--active{background:#dcfce7;color:#166534}.org-node__status--inactive{background:#fee2e2;color:#991b1b}.org-node__actions{display:flex;align-items:center;gap:.25rem;margin-top:.75rem;padding-top:.75rem;border-top:1px solid #f1f5f9}.org-node__action{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:6px;color:#94a3b8;cursor:pointer;transition:background .15s,color .15s}.org-node__action:hover{background:#f1f5f9;color:#6366f1}.org-structure__loading,.org-structure__error,.org-structure__empty{background:#f8fafc}.org-structure__error-icon{box-shadow:0 4px 12px #ef444426}.org-structure__chart::-webkit-scrollbar{width:8px;height:8px}.org-structure__chart::-webkit-scrollbar-track{background:#f1f5f9;border-radius:4px}.org-structure__chart::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.org-structure__chart::-webkit-scrollbar-thumb:hover{background:#94a3b8}@media (max-width: 640px){.org-node__card{min-width:260px;max-width:100%}}\n"] }]
|
|
1011
1052
|
}], propDecorators: { allowSwitching: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowSwitching", required: false }] }], showActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActions", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], entityClick: [{ type: i0.Output, args: ["entityClick"] }], entitySelect: [{ type: i0.Output, args: ["entitySelect"] }], entityView: [{ type: i0.Output, args: ["entityView"] }] } });
|
|
1012
1053
|
|
|
1013
1054
|
class CideSharedProgramSectionSelectorComponent {
|
|
@@ -1500,13 +1541,39 @@ class CideSharedProgramSectionSelectorComponent {
|
|
|
1500
1541
|
setTimeout(() => clearInterval(branchCheckInterval), 5000);
|
|
1501
1542
|
}
|
|
1502
1543
|
else {
|
|
1503
|
-
//
|
|
1504
|
-
|
|
1544
|
+
// Extract config to check for one-to-one term relationship
|
|
1545
|
+
const selectedProgram = this.selectedClassProgram();
|
|
1546
|
+
const generalMaster = selectedProgram?.acacpm_class_program_id_sygms || selectedProgram?.acacpm_class_program_id_sygmt;
|
|
1547
|
+
let config;
|
|
1548
|
+
if (generalMaster && typeof generalMaster === 'object' && 'sygms_configuration' in generalMaster) {
|
|
1549
|
+
const configValue = generalMaster.sygms_configuration;
|
|
1550
|
+
if (typeof configValue === 'string') {
|
|
1551
|
+
try {
|
|
1552
|
+
config = JSON.parse(configValue);
|
|
1553
|
+
}
|
|
1554
|
+
catch { }
|
|
1555
|
+
}
|
|
1556
|
+
else if (typeof configValue === 'object' && configValue !== null) {
|
|
1557
|
+
config = configValue;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
// Check if one-to-one term (dropdown hidden but term exists)
|
|
1561
|
+
const isOneToOneTerm = config?.termType === true && config?.termLevelUpTo === 1 && config?.termProgramLevelOneConnected === true;
|
|
1562
|
+
// Load terms if dropdown shown OR one-to-one relationship
|
|
1563
|
+
if (this.showTermDropdown() || isOneToOneTerm) {
|
|
1564
|
+
console.log('📚 Loading terms - dropdown:', this.showTermDropdown(), 'oneToOne:', isOneToOneTerm);
|
|
1505
1565
|
this.loadClassProgramTerms(classProgramId, undefined);
|
|
1506
|
-
// After terms load,
|
|
1566
|
+
// After terms load, auto-select if one-to-one OR validate if dropdown shown
|
|
1507
1567
|
const termCheckInterval = setInterval(() => {
|
|
1508
1568
|
if (!this.classProgramTermsLoading()) {
|
|
1509
1569
|
clearInterval(termCheckInterval);
|
|
1570
|
+
if (isOneToOneTerm && this.classProgramTerms().length > 0) {
|
|
1571
|
+
// One-to-one: Auto-select the first term
|
|
1572
|
+
const firstTerm = this.classProgramTerms()[0];
|
|
1573
|
+
console.log('🎯 Auto-selecting one-to-one term:', firstTerm);
|
|
1574
|
+
form.patchValue({ [this.termControlName()]: firstTerm.value }, { emitEvent: true });
|
|
1575
|
+
return; // Exit early, onTermChange will load sections
|
|
1576
|
+
}
|
|
1510
1577
|
// Check if current term value exists in loaded terms
|
|
1511
1578
|
const termExists = currentTermId &&
|
|
1512
1579
|
this.classProgramTerms().some(t => t.value === currentTermId);
|
|
@@ -1676,6 +1743,7 @@ class CideSharedProgramSectionSelectorComponent {
|
|
|
1676
1743
|
}
|
|
1677
1744
|
}
|
|
1678
1745
|
loadProgramTermSections(termId) {
|
|
1746
|
+
console.log('🔍 loadProgramTermSections called with termId:', termId);
|
|
1679
1747
|
this.programTermSectionsLoading.set(true);
|
|
1680
1748
|
const payload = new MPrgTrmSection({
|
|
1681
1749
|
acapts_parent_class_prog_term_acapt: termId,
|
|
@@ -1695,12 +1763,16 @@ class CideSharedProgramSectionSelectorComponent {
|
|
|
1695
1763
|
academicsRoutesUrl.programTermSection,
|
|
1696
1764
|
query
|
|
1697
1765
|
]);
|
|
1766
|
+
console.log('📡 Fetching sections from URL:', url);
|
|
1767
|
+
console.log('📦 Payload:', payload);
|
|
1698
1768
|
this.http.get(url)
|
|
1699
1769
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1700
1770
|
.subscribe({
|
|
1701
1771
|
next: (response) => {
|
|
1772
|
+
console.log('✅ Section API response:', response);
|
|
1702
1773
|
if (response?.success && response?.data) {
|
|
1703
1774
|
const sections = Array.isArray(response.data) ? response.data : [];
|
|
1775
|
+
console.log(`📊 Found ${sections.length} sections:`, sections);
|
|
1704
1776
|
const hasSections = sections.length > 0;
|
|
1705
1777
|
this.hasSections.set(hasSections);
|
|
1706
1778
|
if (hasSections) {
|
|
@@ -1708,6 +1780,7 @@ class CideSharedProgramSectionSelectorComponent {
|
|
|
1708
1780
|
value: section._id || '',
|
|
1709
1781
|
label: section.acapts_name || section.acapts_code || ''
|
|
1710
1782
|
})));
|
|
1783
|
+
console.log('✅ Section dropdown will be shown. hasSections =', hasSections);
|
|
1711
1784
|
const form = this.formGroup();
|
|
1712
1785
|
const sectionControl = form?.get(this.sectionControlName());
|
|
1713
1786
|
if (sectionControl) {
|
|
@@ -1716,6 +1789,7 @@ class CideSharedProgramSectionSelectorComponent {
|
|
|
1716
1789
|
}
|
|
1717
1790
|
}
|
|
1718
1791
|
else {
|
|
1792
|
+
console.warn('⚠️ No sections found! Section dropdown will be hidden.');
|
|
1719
1793
|
this.programTermSections.set([]);
|
|
1720
1794
|
const form = this.formGroup();
|
|
1721
1795
|
const sectionControl = form?.get(this.sectionControlName());
|