cloud-ide-shared 1.0.1 → 1.0.3
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 +178 -2
- package/fesm2022/cloud-ide-shared.mjs.map +1 -1
- package/index.d.ts +66 -7
- package/package.json +4 -2
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, InjectionToken, inject } from '@angular/core';
|
|
2
|
+
import { Component, InjectionToken, inject, input, output, signal } from '@angular/core';
|
|
3
3
|
import { Router } from '@angular/router';
|
|
4
|
+
import * as i1 from '@angular/common';
|
|
5
|
+
import { CommonModule } from '@angular/common';
|
|
6
|
+
import { CideEleButtonComponent, CideIconComponent, CideSpinnerComponent } from 'cloud-ide-element';
|
|
4
7
|
|
|
5
8
|
class CloudIdeShared {
|
|
6
9
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CloudIdeShared, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -42,6 +45,179 @@ const authGuard = (route, state) => {
|
|
|
42
45
|
return false;
|
|
43
46
|
};
|
|
44
47
|
|
|
48
|
+
// Injection token for entity service
|
|
49
|
+
const ENTITY_SERVICE_TOKEN = new InjectionToken('EntityService');
|
|
50
|
+
class CideSharedOrgStructureComponent {
|
|
51
|
+
// Input parameters for configuration
|
|
52
|
+
allowSwitching = input(true, ...(ngDevMode ? [{ debugName: "allowSwitching" }] : [])); // Allow entity switching (default: true)
|
|
53
|
+
showActions = input(true, ...(ngDevMode ? [{ debugName: "showActions" }] : [])); // Show action buttons (default: true)
|
|
54
|
+
mode = input('view', ...(ngDevMode ? [{ debugName: "mode" }] : [])); // Mode: selection or view-only
|
|
55
|
+
// Output events
|
|
56
|
+
entityClick = output(); // Emit when entity is clicked
|
|
57
|
+
entitySelect = output(); // Emit when entity is selected for switching
|
|
58
|
+
entityView = output(); // Emit when entity is viewed
|
|
59
|
+
entityService = inject(ENTITY_SERVICE_TOKEN);
|
|
60
|
+
router = inject(Router);
|
|
61
|
+
// Signals
|
|
62
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
63
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
64
|
+
orgStructure = signal([], ...(ngDevMode ? [{ debugName: "orgStructure" }] : []));
|
|
65
|
+
ngOnInit() {
|
|
66
|
+
this.loadOrgStructure();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load organization structure
|
|
70
|
+
*/
|
|
71
|
+
loadOrgStructure() {
|
|
72
|
+
this.loading.set(true);
|
|
73
|
+
this.error.set(null);
|
|
74
|
+
this.entityService.getEntityList({}).subscribe({
|
|
75
|
+
next: (response) => {
|
|
76
|
+
if (response?.success && response?.data) {
|
|
77
|
+
const structure = this.buildOrgStructure(response.data);
|
|
78
|
+
this.orgStructure.set(structure);
|
|
79
|
+
console.log('🏢 [OrgStructure] Loaded organization structure:', structure.length, 'root entities');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.error.set('Failed to load organization structure');
|
|
83
|
+
console.error('❌ [OrgStructure] Failed to load entities:', response);
|
|
84
|
+
}
|
|
85
|
+
this.loading.set(false);
|
|
86
|
+
},
|
|
87
|
+
error: (error) => {
|
|
88
|
+
this.error.set('Error loading organization structure');
|
|
89
|
+
console.error('❌ [OrgStructure] Error loading entities:', error);
|
|
90
|
+
this.loading.set(false);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build organization structure from flat entity list
|
|
96
|
+
*/
|
|
97
|
+
buildOrgStructure(entities) {
|
|
98
|
+
const nodeMap = new Map();
|
|
99
|
+
const rootNodes = [];
|
|
100
|
+
// First pass: create all nodes
|
|
101
|
+
entities.forEach(entity => {
|
|
102
|
+
const node = {
|
|
103
|
+
_id: entity._id || '',
|
|
104
|
+
syen_name: entity.syen_name || 'Unnamed Entity',
|
|
105
|
+
syen_entity_code: entity.syen_entity_code || '',
|
|
106
|
+
syen_entity_type_sygms: entity.syen_entity_type_sygms || '',
|
|
107
|
+
syen_isactive: entity.syen_isactive || false,
|
|
108
|
+
children: [],
|
|
109
|
+
level: 0,
|
|
110
|
+
parentId: entity.syen_id_syen || undefined
|
|
111
|
+
};
|
|
112
|
+
nodeMap.set(node._id, node);
|
|
113
|
+
});
|
|
114
|
+
// Second pass: build hierarchy
|
|
115
|
+
entities.forEach(entity => {
|
|
116
|
+
const node = nodeMap.get(entity._id || '');
|
|
117
|
+
if (node) {
|
|
118
|
+
const parentId = entity.syen_id_syen;
|
|
119
|
+
if (parentId && parentId !== "" && nodeMap.has(parentId)) {
|
|
120
|
+
const parent = nodeMap.get(parentId);
|
|
121
|
+
parent.children = parent.children || [];
|
|
122
|
+
parent.children.push(node);
|
|
123
|
+
node.level = this.calculateLevel(parent, nodeMap);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
node.level = 0;
|
|
127
|
+
rootNodes.push(node);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// Sort children recursively
|
|
132
|
+
this.sortChildrenRecursively(rootNodes);
|
|
133
|
+
return rootNodes;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Calculate level of a node based on its parent
|
|
137
|
+
*/
|
|
138
|
+
calculateLevel(node, nodeMap) {
|
|
139
|
+
let level = 0;
|
|
140
|
+
let current = node;
|
|
141
|
+
while (current.parentId && nodeMap.has(current.parentId)) {
|
|
142
|
+
level++;
|
|
143
|
+
current = nodeMap.get(current.parentId);
|
|
144
|
+
}
|
|
145
|
+
return level;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Sort children recursively by name
|
|
149
|
+
*/
|
|
150
|
+
sortChildrenRecursively(nodes) {
|
|
151
|
+
nodes.sort((a, b) => a.syen_name.localeCompare(b.syen_name));
|
|
152
|
+
nodes.forEach(node => {
|
|
153
|
+
if (node.children && node.children.length > 0) {
|
|
154
|
+
this.sortChildrenRecursively(node.children);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* View entity details
|
|
160
|
+
*/
|
|
161
|
+
viewEntity(entityId) {
|
|
162
|
+
// Find the entity in the structure
|
|
163
|
+
const entity = this.findEntityById(entityId);
|
|
164
|
+
if (entity) {
|
|
165
|
+
// Emit the appropriate event based on mode
|
|
166
|
+
this.entityClick.emit(entity);
|
|
167
|
+
if (this.mode() === 'selection' && this.allowSwitching()) {
|
|
168
|
+
this.entitySelect.emit(entity);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
this.entityView.emit(entity);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Only navigate if not in selection mode
|
|
175
|
+
if (this.mode() !== 'selection') {
|
|
176
|
+
this.router.navigate(['/control-panel/entity-list'], {
|
|
177
|
+
queryParams: { view: entityId }
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Find entity by ID in the structure
|
|
183
|
+
*/
|
|
184
|
+
findEntityById(entityId) {
|
|
185
|
+
const findInNodes = (nodes) => {
|
|
186
|
+
for (const node of nodes) {
|
|
187
|
+
if (node._id === entityId) {
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
if (node.children && node.children.length > 0) {
|
|
191
|
+
const found = findInNodes(node.children);
|
|
192
|
+
if (found)
|
|
193
|
+
return found;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
};
|
|
198
|
+
return findInNodes(this.orgStructure());
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Edit entity
|
|
202
|
+
*/
|
|
203
|
+
editEntity(entityId) {
|
|
204
|
+
this.router.navigate(['/control-panel/entity-list/entity-create'], {
|
|
205
|
+
queryParams: { edit: entityId }
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideSharedOrgStructureComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
209
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", 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 -->\r\n<div class=\"tw-flex-1 tw-overflow-hidden\">\r\n @if (loading()) {\r\n <div class=\"tw-flex tw-items-center tw-justify-center tw-py-12\">\r\n <cide-ele-spinner size=\"md\"></cide-ele-spinner>\r\n <span class=\"tw-ml-3 tw-text-gray-600 tw-text-sm\">Loading organization structure...</span>\r\n </div>\r\n } @else if (error()) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-red-500\">error</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">Error Loading Structure</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">{{ error() }}</p>\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\r\n <cide-ele-icon>refresh</cide-ele-icon>\r\n Try Again\r\n </button>\r\n </div>\r\n } @else if (orgStructure().length === 0) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">account_tree</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">No Entities Found</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">No entities are available to display in the organization structure.</p>\r\n @if (mode() === 'view') {\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\r\n <cide-ele-icon>add</cide-ele-icon>\r\n Create First Entity\r\n </button>\r\n }\r\n </div>\r\n } @else {\r\n <!-- Organization Chart Container -->\r\n <div class=\"tw-relative tw-min-h-screen tw-bg-gray-50 tw-py-8\">\r\n <!-- Background Grid Pattern -->\r\n <div class=\"tw-absolute tw-inset-0 tw-opacity-30\" style=\"background-image: radial-gradient(circle, #e5e7eb 1px, transparent 1px); background-size: 20px 20px;\"></div>\r\n \r\n <!-- Chart Content -->\r\n <div class=\"tw-relative tw-z-10\">\r\n @for (rootNode of orgStructure(); track rootNode._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center tw-mb-12\">\r\n <!-- Render node recursively with unlimited depth -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Entity Node Template (Recursive) -->\r\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n \r\n <!-- Entity Card -->\r\n <div class=\"tw-bg-white tw-shadow-lg tw-rounded-lg tw-p-4 tw-min-w-64 tw-max-w-72 tw-border-t-4 tw-transition-shadow tw-cursor-pointer hover:tw-shadow-xl\"\r\n [class.level-0]=\"level === 0\"\r\n [class.level-1]=\"level === 1\"\r\n [class.level-2]=\"level === 2\"\r\n [class.level-3]=\"level === 3\"\r\n [class.level-4]=\"level === 4\"\r\n [class.level-5]=\"level === 5\"\r\n (click)=\"viewEntity(node._id)\">\r\n \r\n <!-- Card Content -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <!-- Avatar -->\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-purple-600\">person</cide-ele-icon>\r\n </div>\r\n \r\n <!-- Entity Info -->\r\n <div class=\"tw-flex-1 tw-min-w-0\">\r\n <h3 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis\">{{ node.syen_name }}</h3>\r\n <p class=\"tw-text-xs tw-text-gray-600 tw-mt-1\">{{ node.syen_entity_code }}</p>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ node.syen_entity_type_sygms }}</p>\r\n </div>\r\n </div>\r\n \r\n <!-- Action Icons -->\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mt-3\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <!-- Phone Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">phone</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Email Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">email</cide-ele-icon>\r\n </button>\r\n \r\n <!-- LinkedIn Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">attach_money</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Document Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">description</cide-ele-icon>\r\n </button>\r\n \r\n <!-- More Options Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">more_horiz</cide-ele-icon>\r\n </button>\r\n </div>\r\n \r\n <!-- Status Badge -->\r\n <div class=\"tw-flex-shrink-0\">\r\n @if (node.syen_isactive) {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-green-500 tw-rounded-full tw-mr-1\"></div>\r\n Active\r\n </div>\r\n } @else {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-red-500 tw-rounded-full tw-mr-1\"></div>\r\n Inactive\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Children Entities (Recursive) -->\r\n @if (node.children && node.children.length > 0) {\r\n <!-- Ultra-Compact Connection Lines -->\r\n <div class=\"tw-relative tw-flex tw-flex-col tw-items-center tw-mt-2\">\r\n <!-- Minimal connection dot -->\r\n <div class=\"tw-absolute tw-left-1/2 tw-transform tw--translate-x-1/2\" style=\"top: -8px;\">\r\n <div class=\"tw-w-2 tw-h-2 tw-bg-purple-600 tw-rounded-full tw-border tw-border-white\"></div>\r\n </div>\r\n \r\n <!-- Ultra-Compact SVG Lines -->\r\n <div class=\"tw-relative tw-w-full\" style=\"height: 30px;\">\r\n @if (node.children && node.children.length === 1) {\r\n <!-- Single child - minimal line -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" style=\"transform: translateX(-50%); width: 2px; height: 30px; top: 0;\">\r\n <line x1=\"1\" y1=\"0\" x2=\"1\" y2=\"30\" stroke=\"#9333ea\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n </svg>\r\n }\r\n @else if (node.children && node.children.length > 1) {\r\n <!-- Multiple children - minimal design -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" [attr.style]=\"'transform: translateX(-50%); width: ' + ((node.children.length - 1) * 336 + 256) + 'px; height: 30px; top: 0;'\">\r\n <!-- Vertical line -->\r\n <line [attr.x1]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y1=\"0\" \r\n [attr.x2]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y2=\"12\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Horizontal line -->\r\n <path [attr.d]=\"'M 128 15 L ' + ((node.children.length - 1) * 336 + 128) + ' 15'\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Vertical lines to children -->\r\n @for (child of node.children; track child._id; let i = $index) {\r\n <line [attr.x1]=\"(i * 336) + 128\" \r\n y1=\"15\" \r\n [attr.x2]=\"(i * 336) + 128\" \r\n y2=\"28\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n <!-- Tiny dot -->\r\n <circle [attr.cx]=\"(i * 336) + 128\" cy=\"28\" r=\"2.5\" fill=\"#9333ea\" stroke=\"#fff\" stroke-width=\"1\"/>\r\n }\r\n </svg>\r\n }\r\n </div>\r\n \r\n <!-- Children -->\r\n <div class=\"tw-flex tw-justify-center tw-gap-20\">\r\n @for (child of node.children; track child._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n <!-- Child node -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [":host{height:100%;display:flex;flex-direction:column}.tw-overflow-y-auto::-webkit-scrollbar{width:6px}.tw-overflow-y-auto::-webkit-scrollbar-track{background:#f1f5f9;border-radius:3px}.tw-overflow-y-auto::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}.tw-overflow-y-auto::-webkit-scrollbar-thumb:hover{background:#94a3b8}.tw-transition-shadow{transition:box-shadow .2s ease-in-out}.tw-shadow-lg:hover{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a;transform:translateY(-2px);transition:all .2s ease-in-out}.tw-bg-purple-300,.tw-bg-purple-400{transition:all .3s ease-in-out}.connection-line-compact{display:block;overflow:visible}.connection-line-compact path,.connection-line-compact line{stroke-linecap:round;stroke-linejoin:round;transition:stroke-width .2s ease}.connection-line-compact:hover path,.connection-line-compact:hover line{stroke-width:3}.connection-line-compact circle{transition:all .2s ease}.connection-line-compact circle:hover{filter:drop-shadow(0 2px 4px rgba(147,51,234,.4))}.level-0{border-color:#fb923c!important}.level-1{border-color:#60a5fa!important}.level-2{border-color:#a78bfa!important}.level-3{border-color:#4ade80!important}.level-4{border-color:#818cf8!important}.level-5{border-color:#f472b6!important}@media (max-width: 1200px){.tw-max-w-7xl{max-width:100%}.tw-gap-6{gap:1rem}.tw-min-w-64{min-width:14rem}.tw-max-w-72{max-width:16rem}}@media (max-width: 768px){.tw-min-w-64{min-width:12rem}.tw-max-w-72{max-width:14rem}.tw-max-w-7xl{max-width:100%}.tw-gap-6{gap:.75rem}.tw-p-4{padding:.75rem}.tw-mb-4{margin-bottom:.75rem}.tw-space-x-3{gap:.5rem}.tw-space-x-2{gap:.375rem}.tw-w-12{width:2.5rem}.tw-h-12{height:2.5rem}}@media (max-width: 480px){.tw-min-w-72{min-width:12rem}.tw-max-w-80{max-width:14rem}.tw-p-4{padding:.5rem}.tw-space-x-3{gap:.375rem}.tw-space-x-2{gap:.25rem}.tw-mb-3{margin-bottom:.5rem}.tw-w-12{width:2rem}.tw-h-12{height:2rem}.tw-w-8{width:1.5rem}.tw-h-8{height:1.5rem}}@media print{.tw-bg-gray-50{background:#fff!important}.tw-shadow-lg{box-shadow:none!important;border:1px solid #e5e7eb!important}.tw-bg-purple-300{background:#6b7280!important}.tw-border-purple-300{border-color:#6b7280!important}}\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]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], 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"] }] });
|
|
210
|
+
}
|
|
211
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideSharedOrgStructureComponent, decorators: [{
|
|
212
|
+
type: Component,
|
|
213
|
+
args: [{ selector: 'cide-shared-org-structure', standalone: true, imports: [
|
|
214
|
+
CommonModule,
|
|
215
|
+
CideEleButtonComponent,
|
|
216
|
+
CideIconComponent,
|
|
217
|
+
CideSpinnerComponent
|
|
218
|
+
], template: "<!-- Organization Structure Component -->\r\n<div class=\"tw-flex-1 tw-overflow-hidden\">\r\n @if (loading()) {\r\n <div class=\"tw-flex tw-items-center tw-justify-center tw-py-12\">\r\n <cide-ele-spinner size=\"md\"></cide-ele-spinner>\r\n <span class=\"tw-ml-3 tw-text-gray-600 tw-text-sm\">Loading organization structure...</span>\r\n </div>\r\n } @else if (error()) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-red-500\">error</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">Error Loading Structure</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">{{ error() }}</p>\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\r\n <cide-ele-icon>refresh</cide-ele-icon>\r\n Try Again\r\n </button>\r\n </div>\r\n } @else if (orgStructure().length === 0) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">account_tree</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">No Entities Found</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">No entities are available to display in the organization structure.</p>\r\n @if (mode() === 'view') {\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\r\n <cide-ele-icon>add</cide-ele-icon>\r\n Create First Entity\r\n </button>\r\n }\r\n </div>\r\n } @else {\r\n <!-- Organization Chart Container -->\r\n <div class=\"tw-relative tw-min-h-screen tw-bg-gray-50 tw-py-8\">\r\n <!-- Background Grid Pattern -->\r\n <div class=\"tw-absolute tw-inset-0 tw-opacity-30\" style=\"background-image: radial-gradient(circle, #e5e7eb 1px, transparent 1px); background-size: 20px 20px;\"></div>\r\n \r\n <!-- Chart Content -->\r\n <div class=\"tw-relative tw-z-10\">\r\n @for (rootNode of orgStructure(); track rootNode._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center tw-mb-12\">\r\n <!-- Render node recursively with unlimited depth -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Entity Node Template (Recursive) -->\r\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n \r\n <!-- Entity Card -->\r\n <div class=\"tw-bg-white tw-shadow-lg tw-rounded-lg tw-p-4 tw-min-w-64 tw-max-w-72 tw-border-t-4 tw-transition-shadow tw-cursor-pointer hover:tw-shadow-xl\"\r\n [class.level-0]=\"level === 0\"\r\n [class.level-1]=\"level === 1\"\r\n [class.level-2]=\"level === 2\"\r\n [class.level-3]=\"level === 3\"\r\n [class.level-4]=\"level === 4\"\r\n [class.level-5]=\"level === 5\"\r\n (click)=\"viewEntity(node._id)\">\r\n \r\n <!-- Card Content -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <!-- Avatar -->\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-purple-600\">person</cide-ele-icon>\r\n </div>\r\n \r\n <!-- Entity Info -->\r\n <div class=\"tw-flex-1 tw-min-w-0\">\r\n <h3 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis\">{{ node.syen_name }}</h3>\r\n <p class=\"tw-text-xs tw-text-gray-600 tw-mt-1\">{{ node.syen_entity_code }}</p>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ node.syen_entity_type_sygms }}</p>\r\n </div>\r\n </div>\r\n \r\n <!-- Action Icons -->\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mt-3\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <!-- Phone Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">phone</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Email Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">email</cide-ele-icon>\r\n </button>\r\n \r\n <!-- LinkedIn Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">attach_money</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Document Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">description</cide-ele-icon>\r\n </button>\r\n \r\n <!-- More Options Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">more_horiz</cide-ele-icon>\r\n </button>\r\n </div>\r\n \r\n <!-- Status Badge -->\r\n <div class=\"tw-flex-shrink-0\">\r\n @if (node.syen_isactive) {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-green-500 tw-rounded-full tw-mr-1\"></div>\r\n Active\r\n </div>\r\n } @else {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-red-500 tw-rounded-full tw-mr-1\"></div>\r\n Inactive\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Children Entities (Recursive) -->\r\n @if (node.children && node.children.length > 0) {\r\n <!-- Ultra-Compact Connection Lines -->\r\n <div class=\"tw-relative tw-flex tw-flex-col tw-items-center tw-mt-2\">\r\n <!-- Minimal connection dot -->\r\n <div class=\"tw-absolute tw-left-1/2 tw-transform tw--translate-x-1/2\" style=\"top: -8px;\">\r\n <div class=\"tw-w-2 tw-h-2 tw-bg-purple-600 tw-rounded-full tw-border tw-border-white\"></div>\r\n </div>\r\n \r\n <!-- Ultra-Compact SVG Lines -->\r\n <div class=\"tw-relative tw-w-full\" style=\"height: 30px;\">\r\n @if (node.children && node.children.length === 1) {\r\n <!-- Single child - minimal line -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" style=\"transform: translateX(-50%); width: 2px; height: 30px; top: 0;\">\r\n <line x1=\"1\" y1=\"0\" x2=\"1\" y2=\"30\" stroke=\"#9333ea\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n </svg>\r\n }\r\n @else if (node.children && node.children.length > 1) {\r\n <!-- Multiple children - minimal design -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" [attr.style]=\"'transform: translateX(-50%); width: ' + ((node.children.length - 1) * 336 + 256) + 'px; height: 30px; top: 0;'\">\r\n <!-- Vertical line -->\r\n <line [attr.x1]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y1=\"0\" \r\n [attr.x2]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y2=\"12\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Horizontal line -->\r\n <path [attr.d]=\"'M 128 15 L ' + ((node.children.length - 1) * 336 + 128) + ' 15'\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Vertical lines to children -->\r\n @for (child of node.children; track child._id; let i = $index) {\r\n <line [attr.x1]=\"(i * 336) + 128\" \r\n y1=\"15\" \r\n [attr.x2]=\"(i * 336) + 128\" \r\n y2=\"28\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n <!-- Tiny dot -->\r\n <circle [attr.cx]=\"(i * 336) + 128\" cy=\"28\" r=\"2.5\" fill=\"#9333ea\" stroke=\"#fff\" stroke-width=\"1\"/>\r\n }\r\n </svg>\r\n }\r\n </div>\r\n \r\n <!-- Children -->\r\n <div class=\"tw-flex tw-justify-center tw-gap-20\">\r\n @for (child of node.children; track child._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n <!-- Child node -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [":host{height:100%;display:flex;flex-direction:column}.tw-overflow-y-auto::-webkit-scrollbar{width:6px}.tw-overflow-y-auto::-webkit-scrollbar-track{background:#f1f5f9;border-radius:3px}.tw-overflow-y-auto::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}.tw-overflow-y-auto::-webkit-scrollbar-thumb:hover{background:#94a3b8}.tw-transition-shadow{transition:box-shadow .2s ease-in-out}.tw-shadow-lg:hover{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a;transform:translateY(-2px);transition:all .2s ease-in-out}.tw-bg-purple-300,.tw-bg-purple-400{transition:all .3s ease-in-out}.connection-line-compact{display:block;overflow:visible}.connection-line-compact path,.connection-line-compact line{stroke-linecap:round;stroke-linejoin:round;transition:stroke-width .2s ease}.connection-line-compact:hover path,.connection-line-compact:hover line{stroke-width:3}.connection-line-compact circle{transition:all .2s ease}.connection-line-compact circle:hover{filter:drop-shadow(0 2px 4px rgba(147,51,234,.4))}.level-0{border-color:#fb923c!important}.level-1{border-color:#60a5fa!important}.level-2{border-color:#a78bfa!important}.level-3{border-color:#4ade80!important}.level-4{border-color:#818cf8!important}.level-5{border-color:#f472b6!important}@media (max-width: 1200px){.tw-max-w-7xl{max-width:100%}.tw-gap-6{gap:1rem}.tw-min-w-64{min-width:14rem}.tw-max-w-72{max-width:16rem}}@media (max-width: 768px){.tw-min-w-64{min-width:12rem}.tw-max-w-72{max-width:14rem}.tw-max-w-7xl{max-width:100%}.tw-gap-6{gap:.75rem}.tw-p-4{padding:.75rem}.tw-mb-4{margin-bottom:.75rem}.tw-space-x-3{gap:.5rem}.tw-space-x-2{gap:.375rem}.tw-w-12{width:2.5rem}.tw-h-12{height:2.5rem}}@media (max-width: 480px){.tw-min-w-72{min-width:12rem}.tw-max-w-80{max-width:14rem}.tw-p-4{padding:.5rem}.tw-space-x-3{gap:.375rem}.tw-space-x-2{gap:.25rem}.tw-mb-3{margin-bottom:.5rem}.tw-w-12{width:2rem}.tw-h-12{height:2rem}.tw-w-8{width:1.5rem}.tw-h-8{height:1.5rem}}@media print{.tw-bg-gray-50{background:#fff!important}.tw-shadow-lg{box-shadow:none!important;border:1px solid #e5e7eb!important}.tw-bg-purple-300{background:#6b7280!important}.tw-border-purple-300{border-color:#6b7280!important}}\n"] }]
|
|
219
|
+
}] });
|
|
220
|
+
|
|
45
221
|
/*
|
|
46
222
|
* Public API Surface of cloud-ide-shared
|
|
47
223
|
*/
|
|
@@ -50,5 +226,5 @@ const authGuard = (route, state) => {
|
|
|
50
226
|
* Generated bundle index. Do not edit.
|
|
51
227
|
*/
|
|
52
228
|
|
|
53
|
-
export { APP_STATE_SERVICE_TOKEN, AUTH_SERVICE_TOKEN, CloudIdeShared, authGuard };
|
|
229
|
+
export { APP_STATE_SERVICE_TOKEN, AUTH_SERVICE_TOKEN, CideSharedOrgStructureComponent, CloudIdeShared, ENTITY_SERVICE_TOKEN, authGuard };
|
|
54
230
|
//# sourceMappingURL=cloud-ide-shared.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-ide-shared.mjs","sources":["../../../projects/cloud-ide-shared/src/lib/cloud-ide-shared.ts","../../../projects/cloud-ide-shared/src/lib/services/auth.service.interface.ts","../../../projects/cloud-ide-shared/src/lib/guards/auth.guard.ts","../../../projects/cloud-ide-shared/src/public-api.ts","../../../projects/cloud-ide-shared/src/cloud-ide-shared.ts"],"sourcesContent":["import { Component } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'lib-cloud-ide-shared',\r\n imports: [],\r\n template: `\r\n <p>\r\n cloud-ide-shared works!\r\n </p>\r\n `,\r\n styles: ``\r\n})\r\nexport class CloudIdeShared {\r\n\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\n\r\n// Interface for auth service to avoid circular dependency\r\nexport interface IAuthService {\r\n isAuthenticated(): boolean;\r\n isTokenExpired(): boolean;\r\n signOut(): void;\r\n refreshAuthState(): void;\r\n}\r\n\r\n// Interface for app state service to avoid circular dependency\r\nexport interface IAppStateService {\r\n isUserAuthenticated(): boolean;\r\n refreshFromLocalStorage(): void;\r\n}\r\n\r\n// Tokens for dependency injection\r\nexport const AUTH_SERVICE_TOKEN = new InjectionToken<IAuthService>('AuthService');\r\nexport const APP_STATE_SERVICE_TOKEN = new InjectionToken<IAppStateService>('AppStateService');\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { IAuthService, AUTH_SERVICE_TOKEN, IAppStateService, APP_STATE_SERVICE_TOKEN } from '../services/auth.service.interface';\r\n\r\nexport const authGuard: CanActivateFn = (route, state) => {\r\n const authService = inject(AUTH_SERVICE_TOKEN) as IAuthService;\r\n const appState = inject(APP_STATE_SERVICE_TOKEN) as IAppStateService;\r\n const router = inject(Router);\r\n \r\n // Refresh auth state to make sure it's current\r\n authService.refreshAuthState();\r\n \r\n // Refresh app state from localStorage to ensure synchronization\r\n appState.refreshFromLocalStorage();\r\n \r\n // Check if user is authenticated using app state (modern approach)\r\n if (appState.isUserAuthenticated() && !authService.isTokenExpired()) {\r\n return true;\r\n }\r\n \r\n // Redirect to login page with the intended destination\r\n router.navigate(['/auth/sign-in'], { \r\n queryParams: { returnUrl: state.url }\r\n });\r\n \r\n return false;\r\n};\r\n","/*\r\n * Public API Surface of cloud-ide-shared\r\n */\r\n\r\nexport * from './lib/cloud-ide-shared';\r\n\r\n// Guards\r\nexport * from './lib/guards/auth.guard';\r\n\r\n// Services\r\nexport * from './lib/services/auth.service.interface';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAYa,cAAc,CAAA;uGAAd,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAPf,CAAA;;;;AAIT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAGU,cAAc,EAAA,UAAA,EAAA,CAAA;kBAV1B,SAAS;+BACE,sBAAsB,EAAA,OAAA,EACvB,EAAE,EAAA,QAAA,EACD,CAAA;;;;AAIT,EAAA,CAAA,EAAA;;;ACOH;MACa,kBAAkB,GAAG,IAAI,cAAc,CAAe,aAAa;MACnE,uBAAuB,GAAG,IAAI,cAAc,CAAmB,iBAAiB;;MCdhF,SAAS,GAAkB,CAAC,KAAK,EAAE,KAAK,KAAI;AACvD,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,kBAAkB,CAAiB;AAC9D,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,uBAAuB,CAAqB;AACpE,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;;IAG7B,WAAW,CAAC,gBAAgB,EAAE;;IAG9B,QAAQ,CAAC,uBAAuB,EAAE;;IAGlC,IAAI,QAAQ,CAAC,mBAAmB,EAAE,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE;AACnE,QAAA,OAAO,IAAI;;;AAIb,IAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE;AACjC,QAAA,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG;AACpC,KAAA,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;;AC1BA;;AAEG;;ACFH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"cloud-ide-shared.mjs","sources":["../../../projects/cloud-ide-shared/src/lib/cloud-ide-shared.ts","../../../projects/cloud-ide-shared/src/lib/services/auth.service.interface.ts","../../../projects/cloud-ide-shared/src/lib/guards/auth.guard.ts","../../../projects/cloud-ide-shared/src/lib/components/org-structure/org-structure.component.ts","../../../projects/cloud-ide-shared/src/lib/components/org-structure/org-structure.component.html","../../../projects/cloud-ide-shared/src/public-api.ts","../../../projects/cloud-ide-shared/src/cloud-ide-shared.ts"],"sourcesContent":["import { Component } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'lib-cloud-ide-shared',\r\n imports: [],\r\n template: `\r\n <p>\r\n cloud-ide-shared works!\r\n </p>\r\n `,\r\n styles: ``\r\n})\r\nexport class CloudIdeShared {\r\n\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\n\r\n// Interface for auth service to avoid circular dependency\r\nexport interface IAuthService {\r\n isAuthenticated(): boolean;\r\n isTokenExpired(): boolean;\r\n signOut(): void;\r\n refreshAuthState(): void;\r\n}\r\n\r\n// Interface for app state service to avoid circular dependency\r\nexport interface IAppStateService {\r\n isUserAuthenticated(): boolean;\r\n refreshFromLocalStorage(): void;\r\n}\r\n\r\n// Tokens for dependency injection\r\nexport const AUTH_SERVICE_TOKEN = new InjectionToken<IAuthService>('AuthService');\r\nexport const APP_STATE_SERVICE_TOKEN = new InjectionToken<IAppStateService>('AppStateService');\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { IAuthService, AUTH_SERVICE_TOKEN, IAppStateService, APP_STATE_SERVICE_TOKEN } from '../services/auth.service.interface';\r\n\r\nexport const authGuard: CanActivateFn = (route, state) => {\r\n const authService = inject(AUTH_SERVICE_TOKEN) as IAuthService;\r\n const appState = inject(APP_STATE_SERVICE_TOKEN) as IAppStateService;\r\n const router = inject(Router);\r\n \r\n // Refresh auth state to make sure it's current\r\n authService.refreshAuthState();\r\n \r\n // Refresh app state from localStorage to ensure synchronization\r\n appState.refreshFromLocalStorage();\r\n \r\n // Check if user is authenticated using app state (modern approach)\r\n if (appState.isUserAuthenticated() && !authService.isTokenExpired()) {\r\n return true;\r\n }\r\n \r\n // Redirect to login page with the intended destination\r\n router.navigate(['/auth/sign-in'], { \r\n queryParams: { returnUrl: state.url }\r\n });\r\n \r\n return false;\r\n};\r\n","import { Component, signal, OnInit, inject, input, output, InjectionToken } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Router } from '@angular/router';\r\nimport { CideEleButtonComponent, CideIconComponent, CideSpinnerComponent } from 'cloud-ide-element';\r\n\r\nexport interface OrgStructureNode {\r\n _id: string; // Primary key\r\n syen_name: string;\r\n syen_entity_code: string;\r\n syen_entity_type_sygms: string;\r\n syen_isactive: boolean;\r\n children?: OrgStructureNode[];\r\n level: number;\r\n parentId?: string; // Foreign key referencing syen_id_syen (empty string \"\" means root level)\r\n}\r\n\r\n// Interface for entity service to avoid circular dependency\r\nexport interface IEntityService {\r\n getEntityList(params: any): any;\r\n}\r\n\r\n// Injection token for entity service\r\nexport const ENTITY_SERVICE_TOKEN = new InjectionToken<IEntityService>('EntityService');\r\n\r\n@Component({\r\n selector: 'cide-shared-org-structure',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n CideEleButtonComponent,\r\n CideIconComponent,\r\n CideSpinnerComponent\r\n ],\r\n templateUrl: './org-structure.component.html',\r\n styleUrl: './org-structure.component.scss'\r\n})\r\nexport class CideSharedOrgStructureComponent implements OnInit {\r\n // Input parameters for configuration\r\n allowSwitching = input<boolean>(true); // Allow entity switching (default: true)\r\n showActions = input<boolean>(true); // Show action buttons (default: true)\r\n mode = input<'selection' | 'view'>('view'); // Mode: selection or view-only\r\n\r\n // Output events\r\n entityClick = output<OrgStructureNode>(); // Emit when entity is clicked\r\n entitySelect = output<OrgStructureNode>(); // Emit when entity is selected for switching\r\n entityView = output<OrgStructureNode>(); // Emit when entity is viewed\r\n\r\n private entityService = inject(ENTITY_SERVICE_TOKEN) as IEntityService;\r\n public router = inject(Router);\r\n\r\n // Signals\r\n loading = signal(false);\r\n error = signal<string | null>(null);\r\n orgStructure = signal<OrgStructureNode[]>([]);\r\n\r\n ngOnInit(): void {\r\n this.loadOrgStructure();\r\n }\r\n\r\n /**\r\n * Load organization structure\r\n */\r\n loadOrgStructure(): void {\r\n this.loading.set(true);\r\n this.error.set(null);\r\n\r\n this.entityService.getEntityList({}).subscribe({\r\n next: (response: any) => {\r\n if (response?.success && response?.data) {\r\n const structure = this.buildOrgStructure(response.data);\r\n this.orgStructure.set(structure);\r\n console.log('🏢 [OrgStructure] Loaded organization structure:', structure.length, 'root entities');\r\n } else {\r\n this.error.set('Failed to load organization structure');\r\n console.error('❌ [OrgStructure] Failed to load entities:', response);\r\n }\r\n this.loading.set(false);\r\n },\r\n error: (error: any) => {\r\n this.error.set('Error loading organization structure');\r\n console.error('❌ [OrgStructure] Error loading entities:', error);\r\n this.loading.set(false);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Build organization structure from flat entity list\r\n */\r\n private buildOrgStructure(entities: any[]): OrgStructureNode[] {\r\n const nodeMap = new Map<string, OrgStructureNode>();\r\n const rootNodes: OrgStructureNode[] = [];\r\n\r\n // First pass: create all nodes\r\n entities.forEach(entity => {\r\n const node: OrgStructureNode = {\r\n _id: entity._id || '',\r\n syen_name: entity.syen_name || 'Unnamed Entity',\r\n syen_entity_code: entity.syen_entity_code || '',\r\n syen_entity_type_sygms: entity.syen_entity_type_sygms || '',\r\n syen_isactive: entity.syen_isactive || false,\r\n children: [],\r\n level: 0,\r\n parentId: entity.syen_id_syen || undefined\r\n };\r\n nodeMap.set(node._id, node);\r\n });\r\n\r\n // Second pass: build hierarchy\r\n entities.forEach(entity => {\r\n const node = nodeMap.get(entity._id || '');\r\n if (node) {\r\n const parentId = entity.syen_id_syen;\r\n if (parentId && parentId !== \"\" && nodeMap.has(parentId)) {\r\n const parent = nodeMap.get(parentId)!;\r\n parent.children = parent.children || [];\r\n parent.children.push(node);\r\n node.level = this.calculateLevel(parent, nodeMap);\r\n } else {\r\n node.level = 0;\r\n rootNodes.push(node);\r\n }\r\n }\r\n });\r\n\r\n // Sort children recursively\r\n this.sortChildrenRecursively(rootNodes);\r\n return rootNodes;\r\n }\r\n\r\n /**\r\n * Calculate level of a node based on its parent\r\n */\r\n private calculateLevel(node: OrgStructureNode, nodeMap: Map<string, OrgStructureNode>): number {\r\n let level = 0;\r\n let current = node;\r\n \r\n while (current.parentId && nodeMap.has(current.parentId)) {\r\n level++;\r\n current = nodeMap.get(current.parentId)!;\r\n }\r\n \r\n return level;\r\n }\r\n\r\n /**\r\n * Sort children recursively by name\r\n */\r\n private sortChildrenRecursively(nodes: OrgStructureNode[]): void {\r\n nodes.sort((a, b) => a.syen_name.localeCompare(b.syen_name));\r\n \r\n nodes.forEach(node => {\r\n if (node.children && node.children.length > 0) {\r\n this.sortChildrenRecursively(node.children);\r\n }\r\n });\r\n }\r\n\r\n\r\n /**\r\n * View entity details\r\n */\r\n viewEntity(entityId: string): void {\r\n // Find the entity in the structure\r\n const entity = this.findEntityById(entityId);\r\n if (entity) {\r\n // Emit the appropriate event based on mode\r\n this.entityClick.emit(entity);\r\n \r\n if (this.mode() === 'selection' && this.allowSwitching()) {\r\n this.entitySelect.emit(entity);\r\n } else {\r\n this.entityView.emit(entity);\r\n }\r\n }\r\n\r\n // Only navigate if not in selection mode\r\n if (this.mode() !== 'selection') {\r\n this.router.navigate(['/control-panel/entity-list'], { \r\n queryParams: { view: entityId } \r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Find entity by ID in the structure\r\n */\r\n private findEntityById(entityId: string): OrgStructureNode | null {\r\n const findInNodes = (nodes: OrgStructureNode[]): OrgStructureNode | null => {\r\n for (const node of nodes) {\r\n if (node._id === entityId) {\r\n return node;\r\n }\r\n if (node.children && node.children.length > 0) {\r\n const found = findInNodes(node.children);\r\n if (found) return found;\r\n }\r\n }\r\n return null;\r\n };\r\n \r\n return findInNodes(this.orgStructure());\r\n }\r\n\r\n /**\r\n * Edit entity\r\n */\r\n editEntity(entityId: string): void {\r\n this.router.navigate(['/control-panel/entity-list/entity-create'], { \r\n queryParams: { edit: entityId } \r\n });\r\n }\r\n}\r\n","<!-- Organization Structure Component -->\r\n<div class=\"tw-flex-1 tw-overflow-hidden\">\r\n @if (loading()) {\r\n <div class=\"tw-flex tw-items-center tw-justify-center tw-py-12\">\r\n <cide-ele-spinner size=\"md\"></cide-ele-spinner>\r\n <span class=\"tw-ml-3 tw-text-gray-600 tw-text-sm\">Loading organization structure...</span>\r\n </div>\r\n } @else if (error()) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-red-500\">error</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">Error Loading Structure</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">{{ error() }}</p>\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"loadOrgStructure()\">\r\n <cide-ele-icon>refresh</cide-ele-icon>\r\n Try Again\r\n </button>\r\n </div>\r\n } @else if (orgStructure().length === 0) {\r\n <div class=\"tw-text-center tw-py-12\">\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">account_tree</cide-ele-icon>\r\n </div>\r\n <h3 class=\"tw-text-lg tw-font-medium tw-text-gray-900 tw-mb-2\">No Entities Found</h3>\r\n <p class=\"tw-text-gray-600 tw-mb-4\">No entities are available to display in the organization structure.</p>\r\n @if (mode() === 'view') {\r\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"router.navigate(['/control-panel/entity-list'])\">\r\n <cide-ele-icon>add</cide-ele-icon>\r\n Create First Entity\r\n </button>\r\n }\r\n </div>\r\n } @else {\r\n <!-- Organization Chart Container -->\r\n <div class=\"tw-relative tw-min-h-screen tw-bg-gray-50 tw-py-8\">\r\n <!-- Background Grid Pattern -->\r\n <div class=\"tw-absolute tw-inset-0 tw-opacity-30\" style=\"background-image: radial-gradient(circle, #e5e7eb 1px, transparent 1px); background-size: 20px 20px;\"></div>\r\n \r\n <!-- Chart Content -->\r\n <div class=\"tw-relative tw-z-10\">\r\n @for (rootNode of orgStructure(); track rootNode._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center tw-mb-12\">\r\n <!-- Render node recursively with unlimited depth -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: rootNode, level: 0 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Entity Node Template (Recursive) -->\r\n<ng-template #entityNodeTemplate let-node let-level=\"level\">\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n \r\n <!-- Entity Card -->\r\n <div class=\"tw-bg-white tw-shadow-lg tw-rounded-lg tw-p-4 tw-min-w-64 tw-max-w-72 tw-border-t-4 tw-transition-shadow tw-cursor-pointer hover:tw-shadow-xl\"\r\n [class.level-0]=\"level === 0\"\r\n [class.level-1]=\"level === 1\"\r\n [class.level-2]=\"level === 2\"\r\n [class.level-3]=\"level === 3\"\r\n [class.level-4]=\"level === 4\"\r\n [class.level-5]=\"level === 5\"\r\n (click)=\"viewEntity(node._id)\">\r\n \r\n <!-- Card Content -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <!-- Avatar -->\r\n <div 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\">\r\n <cide-ele-icon class=\"tw-w-6 tw-h-6 tw-text-purple-600\">person</cide-ele-icon>\r\n </div>\r\n \r\n <!-- Entity Info -->\r\n <div class=\"tw-flex-1 tw-min-w-0\">\r\n <h3 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis\">{{ node.syen_name }}</h3>\r\n <p class=\"tw-text-xs tw-text-gray-600 tw-mt-1\">{{ node.syen_entity_code }}</p>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ node.syen_entity_type_sygms }}</p>\r\n </div>\r\n </div>\r\n \r\n <!-- Action Icons -->\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mt-3\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <!-- Phone Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">phone</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Email Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">email</cide-ele-icon>\r\n </button>\r\n \r\n <!-- LinkedIn Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">attach_money</cide-ele-icon>\r\n </button>\r\n \r\n <!-- Document Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">description</cide-ele-icon>\r\n </button>\r\n \r\n <!-- More Options Icon -->\r\n <button 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\">\r\n <cide-ele-icon class=\"tw-text-xs\">more_horiz</cide-ele-icon>\r\n </button>\r\n </div>\r\n \r\n <!-- Status Badge -->\r\n <div class=\"tw-flex-shrink-0\">\r\n @if (node.syen_isactive) {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-green-500 tw-rounded-full tw-mr-1\"></div>\r\n Active\r\n </div>\r\n } @else {\r\n <div 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\">\r\n <div class=\"tw-w-1.5 tw-h-1.5 tw-bg-red-500 tw-rounded-full tw-mr-1\"></div>\r\n Inactive\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Children Entities (Recursive) -->\r\n @if (node.children && node.children.length > 0) {\r\n <!-- Ultra-Compact Connection Lines -->\r\n <div class=\"tw-relative tw-flex tw-flex-col tw-items-center tw-mt-2\">\r\n <!-- Minimal connection dot -->\r\n <div class=\"tw-absolute tw-left-1/2 tw-transform tw--translate-x-1/2\" style=\"top: -8px;\">\r\n <div class=\"tw-w-2 tw-h-2 tw-bg-purple-600 tw-rounded-full tw-border tw-border-white\"></div>\r\n </div>\r\n \r\n <!-- Ultra-Compact SVG Lines -->\r\n <div class=\"tw-relative tw-w-full\" style=\"height: 30px;\">\r\n @if (node.children && node.children.length === 1) {\r\n <!-- Single child - minimal line -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" style=\"transform: translateX(-50%); width: 2px; height: 30px; top: 0;\">\r\n <line x1=\"1\" y1=\"0\" x2=\"1\" y2=\"30\" stroke=\"#9333ea\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n </svg>\r\n }\r\n @else if (node.children && node.children.length > 1) {\r\n <!-- Multiple children - minimal design -->\r\n <svg class=\"tw-absolute tw-left-1/2 connection-line-compact\" [attr.style]=\"'transform: translateX(-50%); width: ' + ((node.children.length - 1) * 336 + 256) + 'px; height: 30px; top: 0;'\">\r\n <!-- Vertical line -->\r\n <line [attr.x1]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y1=\"0\" \r\n [attr.x2]=\"((node.children.length - 1) * 336 + 256) / 2\" \r\n y2=\"12\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Horizontal line -->\r\n <path [attr.d]=\"'M 128 15 L ' + ((node.children.length - 1) * 336 + 128) + ' 15'\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n \r\n <!-- Vertical lines to children -->\r\n @for (child of node.children; track child._id; let i = $index) {\r\n <line [attr.x1]=\"(i * 336) + 128\" \r\n y1=\"15\" \r\n [attr.x2]=\"(i * 336) + 128\" \r\n y2=\"28\" \r\n stroke=\"#9333ea\" \r\n stroke-width=\"2\" \r\n stroke-linecap=\"round\"/>\r\n <!-- Tiny dot -->\r\n <circle [attr.cx]=\"(i * 336) + 128\" cy=\"28\" r=\"2.5\" fill=\"#9333ea\" stroke=\"#fff\" stroke-width=\"1\"/>\r\n }\r\n </svg>\r\n }\r\n </div>\r\n \r\n <!-- Children -->\r\n <div class=\"tw-flex tw-justify-center tw-gap-20\">\r\n @for (child of node.children; track child._id) {\r\n <div class=\"tw-flex tw-flex-col tw-items-center\">\r\n <!-- Child node -->\r\n <ng-container [ngTemplateOutlet]=\"entityNodeTemplate\" [ngTemplateOutletContext]=\"{ $implicit: child, level: level + 1 }\"></ng-container>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n","/*\r\n * Public API Surface of cloud-ide-shared\r\n */\r\n\r\nexport * from './lib/cloud-ide-shared';\r\n\r\n// Guards\r\nexport * from './lib/guards/auth.guard';\r\n\r\n// Services\r\nexport * from './lib/services/auth.service.interface';\r\n\r\n// Components\r\nexport * from './lib/components/org-structure/org-structure.component';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { InjectionToken } from '@angular/core';
|
|
3
|
-
import { CanActivateFn } from '@angular/router';
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { InjectionToken, OnInit } from '@angular/core';
|
|
3
|
+
import { CanActivateFn, Router } from '@angular/router';
|
|
4
4
|
|
|
5
5
|
declare class CloudIdeShared {
|
|
6
|
-
static ɵfac:
|
|
7
|
-
static ɵcmp:
|
|
6
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<CloudIdeShared, never>;
|
|
7
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<CloudIdeShared, "lib-cloud-ide-shared", never, {}, {}, never, never, true, never>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
declare const authGuard: CanActivateFn;
|
|
@@ -22,5 +22,64 @@ interface IAppStateService {
|
|
|
22
22
|
declare const AUTH_SERVICE_TOKEN: InjectionToken<IAuthService>;
|
|
23
23
|
declare const APP_STATE_SERVICE_TOKEN: InjectionToken<IAppStateService>;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
interface OrgStructureNode {
|
|
26
|
+
_id: string;
|
|
27
|
+
syen_name: string;
|
|
28
|
+
syen_entity_code: string;
|
|
29
|
+
syen_entity_type_sygms: string;
|
|
30
|
+
syen_isactive: boolean;
|
|
31
|
+
children?: OrgStructureNode[];
|
|
32
|
+
level: number;
|
|
33
|
+
parentId?: string;
|
|
34
|
+
}
|
|
35
|
+
interface IEntityService {
|
|
36
|
+
getEntityList(params: any): any;
|
|
37
|
+
}
|
|
38
|
+
declare const ENTITY_SERVICE_TOKEN: InjectionToken<IEntityService>;
|
|
39
|
+
declare class CideSharedOrgStructureComponent implements OnInit {
|
|
40
|
+
allowSwitching: _angular_core.InputSignal<boolean>;
|
|
41
|
+
showActions: _angular_core.InputSignal<boolean>;
|
|
42
|
+
mode: _angular_core.InputSignal<"selection" | "view">;
|
|
43
|
+
entityClick: _angular_core.OutputEmitterRef<OrgStructureNode>;
|
|
44
|
+
entitySelect: _angular_core.OutputEmitterRef<OrgStructureNode>;
|
|
45
|
+
entityView: _angular_core.OutputEmitterRef<OrgStructureNode>;
|
|
46
|
+
private entityService;
|
|
47
|
+
router: Router;
|
|
48
|
+
loading: _angular_core.WritableSignal<boolean>;
|
|
49
|
+
error: _angular_core.WritableSignal<string | null>;
|
|
50
|
+
orgStructure: _angular_core.WritableSignal<OrgStructureNode[]>;
|
|
51
|
+
ngOnInit(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Load organization structure
|
|
54
|
+
*/
|
|
55
|
+
loadOrgStructure(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Build organization structure from flat entity list
|
|
58
|
+
*/
|
|
59
|
+
private buildOrgStructure;
|
|
60
|
+
/**
|
|
61
|
+
* Calculate level of a node based on its parent
|
|
62
|
+
*/
|
|
63
|
+
private calculateLevel;
|
|
64
|
+
/**
|
|
65
|
+
* Sort children recursively by name
|
|
66
|
+
*/
|
|
67
|
+
private sortChildrenRecursively;
|
|
68
|
+
/**
|
|
69
|
+
* View entity details
|
|
70
|
+
*/
|
|
71
|
+
viewEntity(entityId: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Find entity by ID in the structure
|
|
74
|
+
*/
|
|
75
|
+
private findEntityById;
|
|
76
|
+
/**
|
|
77
|
+
* Edit entity
|
|
78
|
+
*/
|
|
79
|
+
editEntity(entityId: string): void;
|
|
80
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<CideSharedOrgStructureComponent, never>;
|
|
81
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<CideSharedOrgStructureComponent, "cide-shared-org-structure", never, { "allowSwitching": { "alias": "allowSwitching"; "required": false; "isSignal": true; }; "showActions": { "alias": "showActions"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; }, { "entityClick": "entityClick"; "entitySelect": "entitySelect"; "entityView": "entityView"; }, never, never, true, never>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { APP_STATE_SERVICE_TOKEN, AUTH_SERVICE_TOKEN, CideSharedOrgStructureComponent, CloudIdeShared, ENTITY_SERVICE_TOKEN, authGuard };
|
|
85
|
+
export type { IAppStateService, IAuthService, IEntityService, OrgStructureNode };
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-ide-shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": "^20.1.0",
|
|
6
|
-
"@angular/core": "^20.1.0"
|
|
6
|
+
"@angular/core": "^20.1.0",
|
|
7
|
+
"@angular/router": "^20.1.0",
|
|
8
|
+
"cloud-ide-element": "*"
|
|
7
9
|
},
|
|
8
10
|
"dependencies": {
|
|
9
11
|
"tslib": "^2.3.0"
|