Skip to content

Commit 78862f0

Browse files
committed
perf: merge with dev
2 parents 254b096 + 74542a3 commit 78862f0

18 files changed

Lines changed: 14943 additions & 10165 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ luna.tar.gz
4747
luna/
4848
package-lock.json
4949
.angular
50+
.yarn
5051

5152
# generated at build time by scripts/generate-build-info.mjs
5253
/src/environments/build-info.ts

.yarnrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules

src/app/elements/asset-tree/asset-tree.component.scss

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,33 @@
1111
@content;
1212
}
1313

14+
:host {
15+
display: block;
16+
height: 100%;
17+
min-height: 0;
18+
overflow: hidden;
19+
}
20+
1421
.tree-container {
1522
display: flex;
1623
flex-direction: column;
1724
height: 100%;
25+
min-height: 0;
26+
overflow: hidden;
1827
background-color: var(--el-asset-tree-bg-color);
1928

2029
.tree-type {
30+
flex: 0 0 30px;
31+
min-height: 30px;
32+
overflow: hidden;
2133
transition: all 0.3s;
2234

2335
.tree-type-banner {
2436
position: relative;
2537
display: flex;
38+
flex: 0 0 30px;
2639
height: 30px;
40+
min-height: 30px;
2741
line-height: 30px;
2842
padding-right: 11px;
2943
padding-left: 15px;
@@ -141,9 +155,10 @@
141155

142156
.tree-type-content {
143157
position: relative;
144-
padding: 5px 10px;
145-
min-height: 40px;
146-
height: calc(100% - 31px);
158+
flex: 1 1 0;
159+
padding: 1px;
160+
min-height: 0;
161+
height: auto;
147162
background-color: var(--el-asset-tree-bg-color);
148163
overflow: hidden;
149164
scrollbar-gutter: stable both-edges;
@@ -170,7 +185,11 @@
170185
}
171186

172187
&.expand-tree {
173-
height: calc(100% - 31px);
188+
display: flex;
189+
flex: 1 1 0;
190+
flex-direction: column;
191+
min-height: 0;
192+
height: auto;
174193
}
175194
}
176195
}

src/app/elements/asset-tree/asset-tree.component.ts

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ export class ElementAssetTreeComponent implements OnInit {
204204
];
205205
}
206206

207-
// Asset node inside a favorite folder: connect / remove favorite
208-
if (cnode.favoriteFolderId) {
209-
const isK8sFav = cnode.meta.data.platform_type === 'k8s';
207+
// Favorite asset leaf (under a folder or directly under root): connect / move / remove
208+
if (cnode.isFavoriteLeaf) {
209+
const isK8sFav = cnode.meta?.data?.platform_type === 'k8s';
210210
const favViewList = this._viewSrv.viewList;
211211
return [
212212
{
@@ -230,6 +230,7 @@ export class ElementAssetTreeComponent implements OnInit {
230230
hide: favViewList.length <= 0 || isK8sFav,
231231
click: this.onFavoriteConnect.bind(this, true)
232232
},
233+
...this.getMoveToMenus(cnode),
233234
{
234235
id: 'remove-favorite',
235236
name: this._i18n.instant('Remove favorite'),
@@ -324,12 +325,45 @@ export class ElementAssetTreeComponent implements OnInit {
324325
if (cnode.isParent) {
325326
return [];
326327
}
328+
return this.buildFolderTargetMenus({
329+
id: 'favorite-to',
330+
name: this._i18n.instant('Favorite to'),
331+
fa: 'fa-star-o',
332+
assetId: this.resolveAssetId(cnode),
333+
onSelect: this.onFavoriteTo.bind(this)
334+
});
335+
}
336+
337+
/**
338+
* Build a "Move to" parent menu for a favorite-tree asset leaf,
339+
* so it can be relocated into another favorite folder.
340+
*/
341+
getMoveToMenus(cnode): any[] {
342+
return this.buildFolderTargetMenus({
343+
id: 'move-to',
344+
name: this._i18n.instant('Move to'),
345+
fa: 'fa-folder-o',
346+
assetId: this.resolveAssetId(cnode),
347+
onSelect: this.onMoveTo.bind(this)
348+
});
349+
}
350+
351+
/**
352+
* Shared folder submenu builder for "Favorite to" / "Move to".
353+
*/
354+
private buildFolderTargetMenus(options: {
355+
id: string;
356+
name: string;
357+
fa: string;
358+
assetId: string;
359+
onSelect: (folderId: string) => void;
360+
}): any[] {
327361
if (this.favoriteFolders.length === 0) {
328362
return [
329363
{
330-
id: 'favorite-to',
331-
name: this._i18n.instant('Favorite to'),
332-
fa: 'fa-star-o',
364+
id: options.id,
365+
name: options.name,
366+
fa: options.fa,
333367
hide: false,
334368
children: [
335369
{
@@ -341,21 +375,20 @@ export class ElementAssetTreeComponent implements OnInit {
341375
}
342376
];
343377
}
344-
const assetId = this.resolveAssetId(cnode);
345-
const favoritedFolderIds = this.getAssetFavoriteFolderIds(assetId);
378+
const favoritedFolderIds = this.getAssetFavoriteFolderIds(options.assetId);
346379
return [
347380
{
348-
id: 'favorite-to',
349-
name: this._i18n.instant('Favorite to'),
350-
fa: 'fa-star-o',
381+
id: options.id,
382+
name: options.name,
383+
fa: options.fa,
351384
hide: false,
352385
children: this.favoriteFolders.map(folder => {
353386
const folderId = this.resolveFolderId(folder);
354387
return {
355-
id: 'favorite-to-' + folderId,
388+
id: options.id + '-' + folderId,
356389
name: folder.name,
357390
checked: favoritedFolderIds.has(folderId),
358-
click: this.onFavoriteTo.bind(this, folderId)
391+
click: () => options.onSelect(folderId)
359392
};
360393
})
361394
}
@@ -636,23 +669,27 @@ export class ElementAssetTreeComponent implements OnInit {
636669
favoriteFolderRealId: folderId
637670
});
638671
});
639-
// Asset leaf nodes (one asset belongs to one folder; leaf id still uses folder+asset)
672+
// Asset leaf nodes: under folder when folder is set, otherwise under favorite root
640673
(favorites || []).forEach(fav => {
641-
const folderId = this.resolveFolderId(fav.folder ?? fav.folder_id);
642-
if (!folderId || !fav.asset_info) {
674+
if (!fav.asset_info) {
643675
return;
644676
}
677+
const folderId = this.resolveFolderId(fav.folder ?? fav.folder_id);
645678
const info = fav.asset_info;
646679
const assetId = this.resolveAssetId({ id: info.id, assetId: info.id, meta: info.meta });
680+
if (!assetId) {
681+
return;
682+
}
647683
nodes.push({
648-
id: this.buildFavoriteLeafId(folderId, assetId),
649-
pId: 'folder-' + folderId,
684+
id: this.buildFavoriteLeafId(folderId || 'root', assetId),
685+
pId: folderId ? 'folder-' + folderId : 'favorite-root',
650686
name: info.name,
651687
isParent: false,
652688
iconSkin: info.iconSkin,
653689
chkDisabled: info.chkDisabled,
654690
assetId,
655-
favoriteFolderId: folderId,
691+
favoriteFolderId: folderId || null,
692+
isFavoriteLeaf: true,
656693
meta: info.meta
657694
});
658695
});
@@ -1088,7 +1125,7 @@ export class ElementAssetTreeComponent implements OnInit {
10881125
this.refreshFavoriteTree();
10891126
return;
10901127
}
1091-
return this.favoriteAssetToFolder(createdFolderId, favoriteNode, {
1128+
return this.favoriteAssetToFolder(createdFolderId, favoriteNode, 'Favorite', {
10921129
refreshTreeOnSuccess: true
10931130
}).catch(() => {
10941131
this.refreshFavoriteTree();
@@ -1208,19 +1245,30 @@ export class ElementAssetTreeComponent implements OnInit {
12081245
* @param folderId target folder id
12091246
*/
12101247
onFavoriteTo(folderId: string) {
1211-
this.favoriteAssetToFolder(folderId, this.rightClickSelectNode).catch(() => {});
1248+
this.favoriteAssetToFolder(folderId, this.rightClickSelectNode, 'Favorite').catch(() => {});
1249+
}
1250+
1251+
/** Move a favorite-tree asset leaf into another folder. */
1252+
onMoveTo(folderId: string) {
1253+
this.favoriteAssetToFolder(folderId, this.rightClickSelectNode, 'Move').catch(() => {});
12121254
}
12131255

12141256
private favoriteAssetToFolder(
12151257
folderId: string,
12161258
srcNode: any,
1259+
actionKey: string = 'Favorite',
12171260
options: { refreshTreeOnSuccess?: boolean } = {}
12181261
): Promise<void> {
12191262
const normalizedFolderId = this.resolveFolderId(folderId);
12201263
const assetId = this.resolveAssetId(srcNode);
12211264
if (!normalizedFolderId || !assetId) {
12221265
return Promise.resolve();
12231266
}
1267+
const currentFolderId = this.resolveFolderId(srcNode.favoriteFolderId);
1268+
if (currentFolderId && currentFolderId === normalizedFolderId) {
1269+
this._message.warning(this._i18n.instant('Already in this folder'));
1270+
return Promise.resolve();
1271+
}
12241272
const favoritingKey = `${assetId}-${normalizedFolderId}`;
12251273
if (this.favoritingInFlight.has(favoritingKey)) {
12261274
return Promise.resolve();
@@ -1230,7 +1278,7 @@ export class ElementAssetTreeComponent implements OnInit {
12301278
.favoriteAssetToFolder(assetId, normalizedFolderId)
12311279
.toPromise()
12321280
.then(() => {
1233-
const msg = this._i18n.instant('Favorite') + ' ' + this._i18n.instant('success');
1281+
const msg = this._i18n.instant(actionKey) + ' ' + this._i18n.instant('success');
12341282
this._toastr.success(msg, '', { nzClass: 'custom-success-notification' });
12351283
this.setFavoriteAssetRecord(normalizedFolderId, assetId, srcNode);
12361284
if (options.refreshTreeOnSuccess) {
@@ -1291,22 +1339,26 @@ export class ElementAssetTreeComponent implements OnInit {
12911339
chkDisabled: srcNode.chkDisabled,
12921340
assetId: normalizedAssetId,
12931341
favoriteFolderId: normalizedFolderId,
1342+
isFavoriteLeaf: true,
12941343
meta: srcNode.meta
12951344
}
12961345
]);
12971346
}
12981347

12991348
/**
1300-
* Remove an asset from its folder.
1349+
* Remove an asset from favorites (from a folder, or from root when folder is empty).
13011350
* On success, only remove this single leaf node (instantly disappears),
13021351
* without rebuilding the whole tree, keeping other folders' expand state.
13031352
*/
13041353
onRemoveFromFolder() {
13051354
const node = this.rightClickSelectNode;
13061355
const assetId = node.assetId;
1307-
const folderId = node.favoriteFolderId;
1356+
const folderId = this.resolveFolderId(node.favoriteFolderId);
13081357
const ztree = node.ztree;
1309-
this._http.removeFavoriteFromFolder(assetId, folderId).subscribe(() => {
1358+
const remove$ = folderId
1359+
? this._http.removeFavoriteFromFolder(assetId, folderId)
1360+
: this._http.favoriteAsset(assetId, false);
1361+
remove$.subscribe(() => {
13101362
this.removeFavoriteAssetRecord(folderId, assetId);
13111363
const msg = this._i18n.instant('Remove favorite') + ' ' + this._i18n.instant('success');
13121364
this._toastr.success(msg, '', { nzClass: 'custom-success-notification' });

src/app/elements/chat/chat.component.html

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,46 @@
1-
<div id="chatContainer" class="chat-container">
2-
<nz-float-button-group [hidden]="chatAIShown">
3-
@if(isShowSetting && subViews.length === 1) {
4-
<nz-float-button (click)="handleShowDrawer()" [nzIcon]="setting"></nz-float-button>
5-
}
6-
<nz-float-button (click)="showChatAI()" [hidden]="!chatAiApiEnabled" [nzIcon]="customer"> </nz-float-button>
7-
</nz-float-button-group>
8-
<ng-template #setting>
9-
<nz-icon nzTheme="outline" nzType="setting" />
10-
</ng-template>
11-
<ng-template #customer>
12-
<img alt="" class="chat-img" src="assets/icons/chat-ai.png" />
13-
</ng-template>
1+
<div class="chat-overlay-root">
2+
<div #launcher [hidden]="chatAIShown" [ngStyle]="launcherStyle" class="chat-launcher">
3+
<button
4+
(keydown)="onLauncherKeydown($event)"
5+
(lostpointercapture)="onLauncherLostPointerCapture($event)"
6+
(pointerdown)="onLauncherPointerDown($event)"
7+
[class.dragging]="isDragging"
8+
aria-label="移动浮动工具栏"
9+
class="chat-drag-handle"
10+
type="button"
11+
>
12+
<nz-icon nzTheme="outline" nzType="holder" />
13+
</button>
1414

15-
<div *ngIf="chatAiApiEnabled" [style.display]="chatAIShown ? 'block' : 'none'" class="drawer-panel">
15+
<div class="chat-action-group">
16+
@if (isShowSetting && subViews.length === 1) {
17+
<button
18+
(click)="handleShowDrawer()"
19+
aria-label="打开设置"
20+
class="chat-action-button"
21+
type="button"
22+
>
23+
<nz-icon nzTheme="outline" nzType="setting" />
24+
</button>
25+
}
26+
<button
27+
(click)="showChatAI()"
28+
[hidden]="!chatAiApiEnabled"
29+
aria-label="打开智能问答"
30+
class="chat-action-button chat-ai-button"
31+
type="button"
32+
>
33+
<img alt="" class="chat-img" src="assets/icons/chat-ai.png" />
34+
</button>
35+
</div>
36+
</div>
37+
38+
<div
39+
*ngIf="chatAiApiEnabled"
40+
[class.chat-panel-expanded]="chatPanelExpanded"
41+
[style.display]="chatAIShown ? 'block' : 'none'"
42+
class="chat-panel"
43+
>
1644
<div class="content">
1745
<iframe
1846
#contentWindow
@@ -25,16 +53,3 @@
2553
</div>
2654
</div>
2755
</div>
28-
29-
<!-- <div [hidden]="!showBtn || chatAIShown || !isShowSetting" id="dragBox"> -->
30-
<!-- <div -->
31-
<!-- (click)="onSettingOpenDrawer()" -->
32-
<!-- [hidden]="!isShowSetting || subViews.length > 1" -->
33-
<!-- class="drag-setting" -->
34-
<!-- > -->
35-
<!-- <i class="fa fa-cog"></i> -->
36-
<!-- </div> -->
37-
<!-- <div (click)="showChatAI()" [hidden]="!chatAiEnabled" class="robot-button"> -->
38-
<!-- <img alt="" class="chat-img" src="assets/icons/chat-ai.png"/> -->
39-
<!-- </div> -->
40-
<!-- </div> -->

0 commit comments

Comments
 (0)