@ai-table/grid 0.0.4 → 0.0.5

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.
Files changed (72) hide show
  1. package/components/cell-editors/cell-editor.scss +20 -0
  2. package/components/cell-editors/number/number-editor.component.d.ts.map +1 -1
  3. package/components/cell-editors/progress/progress-editor.component.d.ts +22 -0
  4. package/components/cell-editors/progress/progress-editor.component.d.ts.map +1 -0
  5. package/components/cell-editors/progress/progress-editor.component.scss +21 -0
  6. package/components/cell-editors/rating/rating-editor.component.d.ts.map +1 -1
  7. package/components/cell-editors/text/text-editor.component.d.ts +9 -1
  8. package/components/cell-editors/text/text-editor.component.d.ts.map +1 -1
  9. package/components/field-property-editor/field-property-editor.component.d.ts.map +1 -1
  10. package/components/index.d.ts +6 -0
  11. package/components/index.d.ts.map +1 -1
  12. package/constants/editor.d.ts.map +1 -1
  13. package/constants/field.d.ts +3 -3
  14. package/constants/grid.d.ts +1 -0
  15. package/constants/grid.d.ts.map +1 -1
  16. package/core/constants/field.d.ts.map +1 -1
  17. package/core/types/core.d.ts +14 -8
  18. package/core/types/core.d.ts.map +1 -1
  19. package/core/utils/field.d.ts +1 -1
  20. package/esm2022/components/cell-editors/abstract-cell-editor.component.mjs +2 -2
  21. package/esm2022/components/cell-editors/number/number-editor.component.mjs +7 -6
  22. package/esm2022/components/cell-editors/progress/progress-editor.component.mjs +75 -0
  23. package/esm2022/components/cell-editors/rating/rating-editor.component.mjs +7 -6
  24. package/esm2022/components/cell-editors/select/select-editor.component.mjs +3 -3
  25. package/esm2022/components/cell-editors/text/text-editor.component.mjs +54 -21
  26. package/esm2022/components/field-menu/field-menu.component.mjs +3 -3
  27. package/esm2022/components/field-property-editor/field-property-editor.component.mjs +5 -5
  28. package/esm2022/components/index.mjs +7 -1
  29. package/esm2022/constants/editor.mjs +6 -8
  30. package/esm2022/constants/field.mjs +4 -4
  31. package/esm2022/constants/grid.mjs +4 -2
  32. package/esm2022/core/action/general.mjs +4 -4
  33. package/esm2022/core/constants/field.mjs +43 -3
  34. package/esm2022/core/types/core.mjs +6 -2
  35. package/esm2022/core/utils/field.mjs +2 -2
  36. package/esm2022/core/utils/queries.mjs +2 -2
  37. package/esm2022/core/utils/record.mjs +3 -3
  38. package/esm2022/grid.component.mjs +94 -50
  39. package/esm2022/pipes/grid.pipe.mjs +31 -0
  40. package/esm2022/pipes/index.mjs +2 -2
  41. package/esm2022/services/event.service.mjs +37 -24
  42. package/esm2022/services/selection.service.mjs +72 -0
  43. package/esm2022/types/field.mjs +1 -1
  44. package/esm2022/types/grid.mjs +2 -8
  45. package/esm2022/utils/build.mjs +40 -13
  46. package/esm2022/utils/cell.mjs +3 -3
  47. package/fesm2022/ai-table-grid.mjs +650 -396
  48. package/fesm2022/ai-table-grid.mjs.map +1 -1
  49. package/grid.component.d.ts +19 -16
  50. package/grid.component.d.ts.map +1 -1
  51. package/package.json +1 -1
  52. package/pipes/grid.pipe.d.ts +15 -0
  53. package/pipes/grid.pipe.d.ts.map +1 -0
  54. package/pipes/index.d.ts +1 -1
  55. package/pipes/index.d.ts.map +1 -1
  56. package/services/event.service.d.ts +7 -6
  57. package/services/event.service.d.ts.map +1 -1
  58. package/services/{selection.servive.d.ts → selection.service.d.ts} +1 -1
  59. package/services/{selection.servive.d.ts.map → selection.service.d.ts.map} +1 -1
  60. package/styles/styles.scss +6 -10
  61. package/types/field.d.ts +1 -1
  62. package/types/field.d.ts.map +1 -1
  63. package/types/grid.d.ts +8 -6
  64. package/types/grid.d.ts.map +1 -1
  65. package/utils/build.d.ts +3 -2
  66. package/utils/build.d.ts.map +1 -1
  67. package/utils/cell.d.ts +1 -1
  68. package/utils/cell.d.ts.map +1 -1
  69. package/esm2022/pipes/grid.mjs +0 -17
  70. package/esm2022/services/selection.servive.mjs +0 -64
  71. package/pipes/grid.d.ts +0 -9
  72. package/pipes/grid.d.ts.map +0 -1
@@ -1,50 +1,39 @@
1
- import * as i0 from '@angular/core';
2
- import { Pipe, signal, computed, model, inject, booleanAttribute, Component, ChangeDetectionStrategy, Input, Injectable, input, output } from '@angular/core';
3
- import * as i4 from '@angular/common';
1
+ import * as i1$2 from '@angular/common';
4
2
  import { NgIf, NgTemplateOutlet, NgForOf, NgClass, CommonModule, NgComponentOutlet } from '@angular/common';
5
- import { ThyTag } from 'ngx-tethys/tag';
6
- import * as i1$1 from 'ngx-tethys/popover';
7
- import { ThyPopoverRef, ThyPopoverModule } from 'ngx-tethys/popover';
3
+ import * as i0 from '@angular/core';
4
+ import { signal, input, inject, computed, Component, ChangeDetectionStrategy, Input, HostListener, ElementRef, Renderer2, model, booleanAttribute, Injectable, Pipe, DestroyRef, output, NgZone } from '@angular/core';
8
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
- import { helpers, isUndefinedOrNull } from 'ngx-tethys/util';
10
- import { createDraft, finishDraft } from 'immer';
11
- import { ThyIcon } from 'ngx-tethys/icon';
12
- import { of, Subject, fromEvent } from 'rxjs';
13
6
  import * as i1 from '@angular/forms';
14
7
  import { FormsModule } from '@angular/forms';
15
- import { ThyInputGroup, ThyInputCount, ThyInputDirective, ThyInput } from 'ngx-tethys/input';
8
+ import { ThyAction } from 'ngx-tethys/action';
9
+ import * as i3 from 'ngx-tethys/checkbox';
10
+ import { ThyCheckboxModule } from 'ngx-tethys/checkbox';
11
+ import { ThyDatePicker, ThyDatePickerFormatPipe } from 'ngx-tethys/date-picker';
12
+ import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
13
+ import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
14
+ import { ThyIcon } from 'ngx-tethys/icon';
15
+ import * as i1$1 from 'ngx-tethys/popover';
16
+ import { ThyPopoverRef, ThyPopover, ThyPopoverModule } from 'ngx-tethys/popover';
17
+ import { ThyProgress } from 'ngx-tethys/progress';
18
+ import { ThyRate } from 'ngx-tethys/rate';
19
+ import { ThyAutofocusDirective, ThyEnterDirective, ThyOption, ThyStopPropagationDirective } from 'ngx-tethys/shared';
20
+ import { ThyTag } from 'ngx-tethys/tag';
21
+ import { mergeWith } from 'rxjs/operators';
22
+ import { helpers, isUndefinedOrNull } from 'ngx-tethys/util';
23
+ import { createDraft, finishDraft } from 'immer';
24
+ import { ThyTimePickerModule } from 'ngx-tethys/time-picker';
25
+ import { ThyInputNumber } from 'ngx-tethys/input-number';
26
+ import { ThySlider } from 'ngx-tethys/slider';
27
+ import { ThyInputDirective, ThyInputGroup, ThyInputCount, ThyInput } from 'ngx-tethys/input';
16
28
  import * as i2 from 'ngx-tethys/form';
17
29
  import { ThyUniqueCheckValidator, ThyFormModule, ThyConfirmValidatorDirective } from 'ngx-tethys/form';
18
- import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
19
30
  import { ThyButton } from 'ngx-tethys/button';
20
31
  import { ThyListItem } from 'ngx-tethys/list';
21
- import { ThyAutofocusDirective, ThyEnterDirective, ThyOption, ThyStopPropagationDirective } from 'ngx-tethys/shared';
22
- import { ThyInputNumber } from 'ngx-tethys/input-number';
23
- import { ThyDatePicker, ThyDatePickerFormatPipe } from 'ngx-tethys/date-picker';
24
- import { ThyTimePickerModule } from 'ngx-tethys/time-picker';
25
- import { ThyRate } from 'ngx-tethys/rate';
26
- import { ThyTooltipModule, ThyTooltipService } from 'ngx-tethys/tooltip';
27
- import { ThySelect } from 'ngx-tethys/select';
28
- import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
29
- import * as i6 from 'ngx-tethys/checkbox';
30
- import { ThyCheckboxModule } from 'ngx-tethys/checkbox';
32
+ import { of, Subject, fromEvent, debounceTime } from 'rxjs';
31
33
  import { ThyDivider } from 'ngx-tethys/divider';
32
- import { ThyAction } from 'ngx-tethys/action';
33
-
34
- class SelectOptionPipe {
35
- transform(id, options) {
36
- return options.find((item) => item.id === id);
37
- }
38
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
39
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, isStandalone: true, name: "selectOption" }); }
40
- }
41
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, decorators: [{
42
- type: Pipe,
43
- args: [{
44
- name: 'selectOption',
45
- standalone: true
46
- }]
47
- }] });
34
+ import { ThySelect } from 'ngx-tethys/select';
35
+ import * as i4 from 'ngx-tethys/avatar';
36
+ import { ThyAvatarModule } from 'ngx-tethys/avatar';
48
37
 
49
38
  var AITableFieldType;
50
39
  (function (AITableFieldType) {
@@ -54,10 +43,14 @@ var AITableFieldType;
54
43
  AITableFieldType["number"] = "number";
55
44
  AITableFieldType["date"] = "date";
56
45
  AITableFieldType["member"] = "member";
57
- // cascadeSelect = "cascade_select", // 包含单选和多选,参数复杂后续再进行设计
46
+ // cascadeSelect = 'cascade_select', // 包含单选和多选,参数复杂后续再进行设计
58
47
  AITableFieldType["progress"] = "progress";
59
48
  AITableFieldType["rate"] = "rate";
60
49
  AITableFieldType["link"] = "link";
50
+ AITableFieldType["createdAt"] = "created_at";
51
+ AITableFieldType["updatedAt"] = "updated_at";
52
+ AITableFieldType["createdBy"] = "created_by";
53
+ AITableFieldType["updatedBy"] = "updated_by";
61
54
  })(AITableFieldType || (AITableFieldType = {}));
62
55
  var AITableStatType;
63
56
  (function (AITableStatType) {
@@ -113,16 +106,18 @@ function idCreator(length = 5) {
113
106
  const BasicFields = [
114
107
  {
115
108
  type: AITableFieldType.text,
116
- name: '文本',
109
+ name: '单行文本',
117
110
  icon: 'font',
118
111
  width: 300
119
112
  },
113
+ // 多行文本
120
114
  {
121
115
  type: AITableFieldType.select,
122
116
  name: '单选',
123
117
  icon: 'check-circle',
124
118
  width: 200
125
119
  },
120
+ // 多选
126
121
  {
127
122
  type: AITableFieldType.number,
128
123
  name: '数字',
@@ -135,6 +130,20 @@ const BasicFields = [
135
130
  icon: 'calendar',
136
131
  width: 200
137
132
  },
133
+ {
134
+ type: AITableFieldType.member,
135
+ name: '成员',
136
+ icon: 'user',
137
+ width: 200
138
+ },
139
+ // 级联单选
140
+ // 级联多选
141
+ {
142
+ type: AITableFieldType.progress,
143
+ name: '进度',
144
+ icon: 'progress',
145
+ width: 200
146
+ },
138
147
  {
139
148
  type: AITableFieldType.rate,
140
149
  name: '评分',
@@ -146,6 +155,30 @@ const BasicFields = [
146
155
  name: '链接',
147
156
  icon: 'link-insert',
148
157
  width: 300
158
+ },
159
+ {
160
+ type: AITableFieldType.createdBy,
161
+ name: '创建人',
162
+ icon: 'user',
163
+ width: 200
164
+ },
165
+ {
166
+ type: AITableFieldType.createdAt,
167
+ name: '创建时间',
168
+ icon: 'calendar',
169
+ width: 200
170
+ },
171
+ {
172
+ type: AITableFieldType.updatedBy,
173
+ name: '更新人',
174
+ icon: 'user',
175
+ width: 200
176
+ },
177
+ {
178
+ type: AITableFieldType.updatedAt,
179
+ name: '更新时间',
180
+ icon: 'calendar',
181
+ width: 200
149
182
  }
150
183
  ];
151
184
  const Fields = [...BasicFields];
@@ -160,7 +193,7 @@ function createDefaultFieldName(aiTable, type = AITableFieldType.text) {
160
193
  return count === 0 ? FieldsMap[type].name : FieldsMap[type].name + count;
161
194
  }
162
195
  function createDefaultField(aiTable, type = AITableFieldType.text) {
163
- return { id: idCreator(), type, name: createDefaultFieldName(aiTable, type) };
196
+ return { _id: idCreator(), type, name: createDefaultFieldName(aiTable, type) };
164
197
  }
165
198
 
166
199
  const FLUSHING = new WeakMap();
@@ -197,11 +230,11 @@ function isPathEqual(path, another) {
197
230
 
198
231
  function getDefaultRecord(fields) {
199
232
  const newRow = {
200
- id: idCreator(),
233
+ _id: idCreator(),
201
234
  values: {}
202
235
  };
203
236
  fields.map((item) => {
204
- newRow.values[item.id] = getDefaultFieldValue(item.type);
237
+ newRow.values[item._id] = getDefaultFieldValue(item.type);
205
238
  });
206
239
  return newRow;
207
240
  }
@@ -238,7 +271,7 @@ const AITableQueries = {
238
271
  if (!field) {
239
272
  throw new Error(`can not find field at path [${path}]`);
240
273
  }
241
- return aiTable.records()[path[0]].values[field.id];
274
+ return aiTable.records()[path[0]].values[field._id];
242
275
  },
243
276
  getField(aiTable, path) {
244
277
  if (!aiTable) {
@@ -317,7 +350,7 @@ const apply = (aiTable, records, fields, options) => {
317
350
  case ActionName.UpdateFieldValue: {
318
351
  const [recordIndex, fieldIndex] = options.path;
319
352
  if (fieldIndex > -1 && recordIndex > -1) {
320
- const fieldId = aiTable.fields()[fieldIndex].id;
353
+ const fieldId = aiTable.fields()[fieldIndex]._id;
321
354
  records[recordIndex].values[fieldId] = options.newFieldValue;
322
355
  }
323
356
  break;
@@ -335,7 +368,7 @@ const apply = (aiTable, records, fields, options) => {
335
368
  const newField = options.field;
336
369
  fields.splice(fieldIndex, 0, newField);
337
370
  const newRecord = {
338
- [newField.id]: ''
371
+ [newField._id]: ''
339
372
  };
340
373
  records.forEach((item) => {
341
374
  item.values = {
@@ -367,7 +400,7 @@ const apply = (aiTable, records, fields, options) => {
367
400
  case ActionName.RemoveField: {
368
401
  const [fieldIndex] = options.path;
369
402
  if (fieldIndex > -1) {
370
- const fieldId = aiTable.fields()[fieldIndex].id;
403
+ const fieldId = aiTable.fields()[fieldIndex]._id;
371
404
  fields.splice(fieldIndex, 1);
372
405
  records.forEach((item) => {
373
406
  delete item.values[fieldId];
@@ -460,173 +493,6 @@ const Actions = {
460
493
  ...FieldActions
461
494
  };
462
495
 
463
- const buildGridData = (recordValue, fieldsValue, selection) => {
464
- return {
465
- type: 'grid',
466
- fields: fieldsValue.map(item => {
467
- return {
468
- ...item,
469
- icon: item.icon || FieldsMap[item.type].icon,
470
- width: item.width || FieldsMap[item.type].width
471
- };
472
- }),
473
- records: recordValue.map((item) => {
474
- return { ...item, checked: selection.selectedRecords.has(item.id) };
475
- })
476
- };
477
- };
478
-
479
- function getRecordOrField(value, id) {
480
- return computed(() => {
481
- return value().find((item) => item.id === id);
482
- });
483
- }
484
-
485
- const DEFAULT_COLUMN_WIDTH = 200;
486
- const MIN_COLUMN_WIDTH = 80;
487
- const DBL_CLICK_EDIT_TYPE = [
488
- AITableFieldType.text,
489
- AITableFieldType.number,
490
- AITableFieldType.select,
491
- AITableFieldType.date
492
- ];
493
- const RowHeight = {
494
- Short: 32,
495
- Medium: 57,
496
- Tall: 104,
497
- ExtraTall: 152
498
- };
499
-
500
- class AITableFieldPropertyEditor {
501
- constructor() {
502
- this.aiField = model.required();
503
- this.aiExternalTemplate = null;
504
- this.fieldType = computed(() => {
505
- return FieldsMap[this.aiField().type];
506
- });
507
- this.fieldMaxLength = 32;
508
- this.validatorConfig = {
509
- validationMessages: {
510
- fieldName: {
511
- required: '列名不能为空',
512
- thyUniqueCheck: '列名已存在'
513
- }
514
- }
515
- };
516
- this.selectableFields = Fields;
517
- this.thyPopoverRef = inject((ThyPopoverRef));
518
- this.checkUniqueName = (fieldName) => {
519
- fieldName = fieldName?.trim();
520
- return of(!!this.aiTable.fields()?.find((field) => field.name === fieldName && this.aiField()?.id !== field.id));
521
- };
522
- }
523
- selectFieldType(fieldType) {
524
- this.aiField.update((item) => ({ ...item, type: fieldType, name: createDefaultFieldName(this.aiTable, fieldType) }));
525
- }
526
- editFieldProperty() {
527
- if (this.isUpdate) {
528
- const path = this.aiTable.fields().findIndex((item) => item.id === this.aiField().id);
529
- Actions.setField(this.aiTable, this.aiField(), [path]);
530
- }
531
- else {
532
- Actions.addField(this.aiTable, this.aiField(), [this.aiTable.fields().length]);
533
- }
534
- this.thyPopoverRef.close();
535
- }
536
- cancel() {
537
- this.thyPopoverRef.close();
538
- }
539
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
540
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableFieldPropertyEditor, isStandalone: true, selector: "ai-table-field-property-editor", inputs: { aiField: { classPropertyName: "aiField", publicName: "aiField", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null }, aiExternalTemplate: { classPropertyName: "aiExternalTemplate", publicName: "aiExternalTemplate", isSignal: false, isRequired: false, transformFunction: null }, isUpdate: { classPropertyName: "isUpdate", publicName: "isUpdate", isSignal: false, isRequired: false, transformFunction: booleanAttribute } }, outputs: { aiField: "aiFieldChange" }, host: { classAttribute: "field-property-editor d-block pl-5 pr-5 pb-5 pt-4" }, ngImport: i0, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track item.type) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyInputGroup, selector: "thy-input-group", inputs: ["thyAppendText", "thyAppendTextTranslateKey", "thyPrependText", "thyPrependTextTranslateKey", "thySize"] }, { kind: "component", type: ThyInputCount, selector: "thy-input-count", inputs: ["thyInput"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyUniqueCheckValidator, selector: "[thyUniqueCheck]", inputs: ["thyUniqueCheck"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }, { kind: "directive", type: ThyDropdownMenuItemNameDirective, selector: "[thyDropdownMenuItemName]" }, { kind: "component", type: ThyButton, selector: "thy-button,[thy-button],[thyButton]", inputs: ["thyButton", "thyType", "thyLoading", "thyLoadingText", "thySize", "thyIcon", "thyBlock"] }, { kind: "ngmodule", type: ThyFormModule }, { kind: "directive", type: i2.ThyFormDirective, selector: "[thyForm],[thy-form]", inputs: ["thyLayout", "thyEnterKeyMode", "thyFormValidatorConfig"], exportAs: ["thyForm"] }, { kind: "component", type: i2.ThyFormGroup, selector: "thy-form-group", inputs: ["thyLabelText", "thyLabelTextTranslateKey", "thyLabelRequired", "thyLabelPaddingTopClear", "thyFeedbackIcon", "thyTipsMode", "thyTips", "thyTipsTranslateKey", "thyRowFill"] }, { kind: "directive", type: i2.ThyFormSubmitDirective, selector: "[thyFormSubmit],[thy-form-submit]", outputs: ["thyFormSubmit"] }, { kind: "component", type: i2.ThyFormGroupFooter, selector: "thy-form-group-footer", inputs: ["thyAlign"] }, { kind: "component", type: ThyListItem, selector: "thy-list-item,[thy-list-item]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
541
- }
542
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, decorators: [{
543
- type: Component,
544
- args: [{ selector: 'ai-table-field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
545
- NgIf,
546
- NgForOf,
547
- FormsModule,
548
- ThyIcon,
549
- ThyInput,
550
- ThyInputGroup,
551
- ThyInputCount,
552
- ThyInputDirective,
553
- ThyConfirmValidatorDirective,
554
- ThyUniqueCheckValidator,
555
- ThyDropdownDirective,
556
- ThyDropdownMenuComponent,
557
- ThyDropdownMenuItemDirective,
558
- ThyDropdownMenuItemNameDirective,
559
- ThyDropdownMenuItemIconDirective,
560
- ThyButton,
561
- ThyFormModule,
562
- ThyListItem,
563
- NgTemplateOutlet,
564
- ThyAutofocusDirective
565
- ], host: {
566
- class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
567
- }, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track item.type) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"] }]
568
- }], ctorParameters: () => [], propDecorators: { aiTable: [{
569
- type: Input,
570
- args: [{ required: true }]
571
- }], aiExternalTemplate: [{
572
- type: Input
573
- }], isUpdate: [{
574
- type: Input,
575
- args: [{ transform: booleanAttribute }]
576
- }] } });
577
-
578
- const AI_TABLE_GRID_FIELD_SERVICE_MAP = new WeakMap();
579
- class AITableGridFieldService {
580
- constructor(thyPopover) {
581
- this.thyPopover = thyPopover;
582
- }
583
- initAIFieldConfig(aiFieldConfig) {
584
- this.aiFieldConfig = aiFieldConfig;
585
- }
586
- editFieldProperty(origin, aiTable, aiField, isUpdate) {
587
- const component = this.aiFieldConfig?.fieldPropertyEditor ?? AITableFieldPropertyEditor;
588
- this.thyPopover.open(component, {
589
- origin: origin,
590
- manualClosure: true,
591
- placement: 'bottomLeft',
592
- initialState: {
593
- aiTable,
594
- aiField,
595
- isUpdate
596
- }
597
- });
598
- }
599
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
600
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService }); }
601
- }
602
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, decorators: [{
603
- type: Injectable
604
- }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
605
-
606
- const DividerMenuItem = {
607
- id: 'divider'
608
- };
609
- const EditFieldPropertyItem = {
610
- id: 'editFieldProperty',
611
- name: '编辑列',
612
- icon: 'edit',
613
- exec: (aiTable, field, origin) => {
614
- const fieldService = AI_TABLE_GRID_FIELD_SERVICE_MAP.get(aiTable);
615
- const copyField = signal(JSON.parse(JSON.stringify(field())));
616
- origin && fieldService?.editFieldProperty(origin, aiTable, copyField, true);
617
- }
618
- };
619
- const RemoveFieldItem = {
620
- id: 'removeField',
621
- name: '删除列',
622
- icon: 'trash',
623
- exec: (aiTable, field) => {
624
- const path = AITableQueries.findPath(aiTable, field());
625
- Actions.removeField(aiTable, path);
626
- }
627
- };
628
- const DefaultFieldMenus = [EditFieldPropertyItem, RemoveFieldItem];
629
-
630
496
  class AbstractEditCellEditor {
631
497
  constructor() {
632
498
  this.field = input.required();
@@ -644,7 +510,7 @@ class AbstractEditCellEditor {
644
510
  Actions.updateFieldValue(this.aiTable, this.modelValue, path);
645
511
  }
646
512
  closePopover() {
647
- this.thyPopoverRef.close();
513
+ this.thyPopoverRef?.close();
648
514
  }
649
515
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AbstractEditCellEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
650
516
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.0.2", type: AbstractEditCellEditor, isStandalone: true, selector: "abstract-edit-cell", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, record: { classPropertyName: "record", publicName: "record", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null } }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -662,88 +528,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
662
528
  args: [{ required: true }]
663
529
  }] } });
664
530
 
665
- class TextCellEditorComponent extends AbstractEditCellEditor {
666
- updateValue() {
667
- this.updateFieldValue();
668
- this.closePopover();
669
- }
670
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
671
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: TextCellEditorComponent, isStandalone: true, selector: "text-cell-editor", usesInheritance: true, ngImport: i0, template: `<input
672
- thyInput
673
- [thyAutofocus]="true"
674
- [(ngModel)]="modelValue"
675
- (thyEnter)="updateValue()"
676
- (blur)="updateValue()"
677
- placeholder=""
678
- /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
679
- }
680
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, decorators: [{
681
- type: Component,
682
- args: [{
683
- selector: 'text-cell-editor',
684
- template: `<input
685
- thyInput
686
- [thyAutofocus]="true"
687
- [(ngModel)]="modelValue"
688
- (thyEnter)="updateValue()"
689
- (blur)="updateValue()"
690
- placeholder=""
691
- /> `,
692
- standalone: true,
693
- changeDetection: ChangeDetectionStrategy.OnPush,
694
- imports: [NgIf, FormsModule, ThyAutofocusDirective, ThyInputDirective, ThyEnterDirective]
695
- }]
696
- }] });
697
-
698
- class NumberCellEditorComponent extends AbstractEditCellEditor {
699
- updateValue() {
700
- this.updateFieldValue();
701
- this.closePopover();
702
- }
703
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
704
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: NumberCellEditorComponent, isStandalone: true, selector: "number-cell-editor", usesInheritance: true, ngImport: i0, template: `<thy-input-number
705
- class="h-100"
706
- [thyAutoFocus]="true"
707
- [(ngModel)]="modelValue"
708
- (thyEnter)="updateValue()"
709
- (thyBlur)="updateValue()"
710
- placeholder=""
711
- /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }, { kind: "component", type: ThyInputNumber, selector: "thy-input-number", inputs: ["thyAutoFocus", "thyPlaceholder", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyStepDelay", "thySize", "thyPrecision", "thySuffix"], outputs: ["thyBlur", "thyFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
712
- }
713
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, decorators: [{
714
- type: Component,
715
- args: [{
716
- selector: 'number-cell-editor',
717
- template: `<thy-input-number
718
- class="h-100"
719
- [thyAutoFocus]="true"
720
- [(ngModel)]="modelValue"
721
- (thyEnter)="updateValue()"
722
- (thyBlur)="updateValue()"
723
- placeholder=""
724
- /> `,
725
- standalone: true,
726
- changeDetection: ChangeDetectionStrategy.OnPush,
727
- imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
728
- }]
729
- }] });
730
-
731
- class DateTimeCellEditorComponent extends AbstractEditCellEditor {
732
- constructor() {
733
- super(...arguments);
734
- this.dateShowTime = input(false);
735
- this.dateFormat = computed(() => {
736
- return this.dateShowTime() ? 'yyyy-MM-dd HH:mm' : 'yyyy-MM-dd';
737
- })();
738
- }
739
- ngOnInit() {
740
- super.ngOnInit();
741
- if (!this.modelValue && this.dateShowTime()) {
742
- this.modelValue = {
743
- date: 0,
744
- with_time: 1
745
- };
746
- }
531
+ class DateTimeCellEditorComponent extends AbstractEditCellEditor {
532
+ constructor() {
533
+ super(...arguments);
534
+ this.dateShowTime = input(false);
535
+ this.dateFormat = computed(() => {
536
+ return this.dateShowTime() ? 'yyyy-MM-dd HH:mm' : 'yyyy-MM-dd';
537
+ })();
538
+ }
539
+ ngOnInit() {
540
+ super.ngOnInit();
541
+ if (!this.modelValue && this.dateShowTime()) {
542
+ this.modelValue = {
543
+ date: 0,
544
+ with_time: 1
545
+ };
546
+ }
747
547
  }
748
548
  updateValue() {
749
549
  this.updateFieldValue();
@@ -803,13 +603,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
803
603
  }]
804
604
  }] });
805
605
 
806
- class RatingCellEditorComponent extends AbstractEditCellEditor {
606
+ class LinkCellEditorComponent extends AbstractEditCellEditor {
807
607
  updateValue() {
808
608
  this.updateFieldValue();
809
609
  this.closePopover();
810
610
  }
611
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
612
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: LinkCellEditorComponent, isStandalone: true, selector: "link-cell-editor", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
613
+ }
614
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, decorators: [{
615
+ type: Component,
616
+ args: [{
617
+ selector: 'link-cell-editor',
618
+ template: ``,
619
+ standalone: true,
620
+ changeDetection: ChangeDetectionStrategy.OnPush,
621
+ imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
622
+ }]
623
+ }] });
624
+
625
+ class NumberCellEditorComponent extends AbstractEditCellEditor {
626
+ updateValue() {
627
+ this.updateFieldValue();
628
+ this.closePopover();
629
+ }
630
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
631
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: NumberCellEditorComponent, isStandalone: true, selector: "number-cell-editor", host: { classAttribute: "number-cell-editor" }, usesInheritance: true, ngImport: i0, template: `<thy-input-number
632
+ class="h-100"
633
+ [thyAutoFocus]="true"
634
+ [(ngModel)]="modelValue"
635
+ (thyEnter)="updateValue()"
636
+ (thyBlur)="updateValue()"
637
+ /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }, { kind: "component", type: ThyInputNumber, selector: "thy-input-number", inputs: ["thyAutoFocus", "thyPlaceholder", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyStepDelay", "thySize", "thyPrecision", "thySuffix"], outputs: ["thyBlur", "thyFocus", "thyStepChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
638
+ }
639
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, decorators: [{
640
+ type: Component,
641
+ args: [{
642
+ selector: 'number-cell-editor',
643
+ template: `<thy-input-number
644
+ class="h-100"
645
+ [thyAutoFocus]="true"
646
+ [(ngModel)]="modelValue"
647
+ (thyEnter)="updateValue()"
648
+ (thyBlur)="updateValue()"
649
+ /> `,
650
+ standalone: true,
651
+ changeDetection: ChangeDetectionStrategy.OnPush,
652
+ imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber],
653
+ host: {
654
+ class: 'number-cell-editor'
655
+ }
656
+ }]
657
+ }] });
658
+
659
+ class ProgressEditorComponent extends AbstractEditCellEditor {
660
+ mousedownHandler(event) {
661
+ event.preventDefault();
662
+ }
663
+ constructor() {
664
+ super();
665
+ this.config = {
666
+ max: 100,
667
+ min: 0,
668
+ step: 1,
669
+ progressType: 'success',
670
+ suffix: '%',
671
+ size: 'md'
672
+ };
673
+ }
674
+ sliderMousedownHandler(event) {
675
+ event.preventDefault();
676
+ event.stopPropagation();
677
+ }
678
+ updateValue(value) {
679
+ this.updateFieldValue();
680
+ }
681
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ProgressEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
682
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: ProgressEditorComponent, isStandalone: true, selector: "progress-editor", host: { listeners: { "mousedown": "mousedownHandler($event)" }, properties: { "attr.type": "field().type", "attr.fieldId": "field()._id", "attr.recordId": "record()._id" }, classAttribute: "grid-cell progress-editor" }, usesInheritance: true, ngImport: i0, template: `
683
+ <thy-slider
684
+ [(ngModel)]="modelValue"
685
+ [thyMax]="config?.max || 100"
686
+ [thyMin]="config?.min || 0"
687
+ [thyStep]="config?.step || 1"
688
+ [thyType]="config?.progressType || 'success'"
689
+ [thySize]="config?.size || 'md'"
690
+ (ngModelChange)="updateValue($event)"
691
+ (mousedown)="sliderMousedownHandler($event)"
692
+ ></thy-slider>
693
+ <span class="progress-text">{{ modelValue }}{{ config?.suffix || '%' }}</span>
694
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThySlider, selector: "thy-slider", inputs: ["thyVertical", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyType", "thyColor", "thySize"], outputs: ["thyAfterChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
695
+ }
696
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ProgressEditorComponent, decorators: [{
697
+ type: Component,
698
+ args: [{
699
+ selector: 'progress-editor',
700
+ template: `
701
+ <thy-slider
702
+ [(ngModel)]="modelValue"
703
+ [thyMax]="config?.max || 100"
704
+ [thyMin]="config?.min || 0"
705
+ [thyStep]="config?.step || 1"
706
+ [thyType]="config?.progressType || 'success'"
707
+ [thySize]="config?.size || 'md'"
708
+ (ngModelChange)="updateValue($event)"
709
+ (mousedown)="sliderMousedownHandler($event)"
710
+ ></thy-slider>
711
+ <span class="progress-text">{{ modelValue }}{{ config?.suffix || '%' }}</span>
712
+ `,
713
+ standalone: true,
714
+ changeDetection: ChangeDetectionStrategy.OnPush,
715
+ imports: [FormsModule, ThySlider],
716
+ host: {
717
+ class: 'grid-cell progress-editor',
718
+ '[attr.type]': 'field().type',
719
+ '[attr.fieldId]': 'field()._id',
720
+ '[attr.recordId]': 'record()._id'
721
+ }
722
+ }]
723
+ }], ctorParameters: () => [], propDecorators: { mousedownHandler: [{
724
+ type: HostListener,
725
+ args: ['mousedown', ['$event']]
726
+ }] } });
727
+
728
+ class RatingCellEditorComponent extends AbstractEditCellEditor {
729
+ updateValue() {
730
+ this.updateFieldValue();
731
+ }
811
732
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: RatingCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
812
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: RatingCellEditorComponent, isStandalone: true, selector: "rating-cell-editor", usesInheritance: true, ngImport: i0, template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "ngmodule", type: ThyTooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
733
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: RatingCellEditorComponent, isStandalone: true, selector: "rating-cell-editor", host: { classAttribute: "d-flex align-items-center h-100 px-3" }, usesInheritance: true, ngImport: i0, template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
813
734
  }
814
735
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: RatingCellEditorComponent, decorators: [{
815
736
  type: Component,
@@ -818,26 +739,331 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
818
739
  template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `,
819
740
  standalone: true,
820
741
  changeDetection: ChangeDetectionStrategy.OnPush,
821
- imports: [FormsModule, ThyRate, ThyTooltipModule]
742
+ imports: [FormsModule, ThyRate],
743
+ host: {
744
+ class: 'd-flex align-items-center h-100 px-3'
745
+ }
822
746
  }]
823
747
  }] });
824
748
 
825
- class LinkCellEditorComponent extends AbstractEditCellEditor {
749
+ class TextCellEditorComponent extends AbstractEditCellEditor {
750
+ constructor() {
751
+ super();
752
+ this.elementRef = inject(ElementRef);
753
+ this.render2 = inject(Renderer2);
754
+ this.maxHeight = 148;
755
+ }
756
+ ngAfterViewInit() {
757
+ setTimeout(() => {
758
+ this.updateStyle();
759
+ });
760
+ }
761
+ updateStyle() {
762
+ const textarea = this.elementRef.nativeElement.querySelector('textarea');
763
+ const height = textarea.scrollHeight < this.maxHeight ? textarea.scrollHeight : this.maxHeight;
764
+ this.render2.setStyle(textarea, 'height', `${height}px`);
765
+ this.render2.setStyle(textarea, 'min-height', `44px`);
766
+ this.render2.setStyle(textarea, 'max-height', `${this.maxHeight}px`);
767
+ this.render2.setStyle(textarea, 'resize', 'none');
768
+ }
769
+ valueChange() {
770
+ this.updateStyle();
771
+ }
826
772
  updateValue() {
827
773
  this.updateFieldValue();
828
774
  this.closePopover();
829
775
  }
830
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
831
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: LinkCellEditorComponent, isStandalone: true, selector: "link-cell-editor", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
776
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
777
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: TextCellEditorComponent, isStandalone: true, selector: "text-cell-editor", host: { classAttribute: "text-cell-editor" }, usesInheritance: true, ngImport: i0, template: `
778
+ <textarea
779
+ placeholder=""
780
+ rows="1"
781
+ thyInput
782
+ [thyAutofocus]="true"
783
+ [(ngModel)]="modelValue"
784
+ (ngModelChange)="valueChange()"
785
+ (thyEnter)="updateValue()"
786
+ (blur)="updateValue()"
787
+ ></textarea>
788
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
832
789
  }
833
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, decorators: [{
790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, decorators: [{
834
791
  type: Component,
835
792
  args: [{
836
- selector: 'link-cell-editor',
837
- template: ``,
793
+ selector: 'text-cell-editor',
794
+ template: `
795
+ <textarea
796
+ placeholder=""
797
+ rows="1"
798
+ thyInput
799
+ [thyAutofocus]="true"
800
+ [(ngModel)]="modelValue"
801
+ (ngModelChange)="valueChange()"
802
+ (thyEnter)="updateValue()"
803
+ (blur)="updateValue()"
804
+ ></textarea>
805
+ `,
838
806
  standalone: true,
839
807
  changeDetection: ChangeDetectionStrategy.OnPush,
840
- imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
808
+ imports: [NgIf, FormsModule, ThyAutofocusDirective, ThyInputDirective, ThyEnterDirective],
809
+ host: {
810
+ class: 'text-cell-editor'
811
+ }
812
+ }]
813
+ }], ctorParameters: () => [] });
814
+
815
+ class AITableFieldPropertyEditor {
816
+ constructor() {
817
+ this.aiField = model.required();
818
+ this.aiExternalTemplate = null;
819
+ this.fieldType = computed(() => {
820
+ return FieldsMap[this.aiField().type];
821
+ });
822
+ this.fieldMaxLength = 32;
823
+ this.validatorConfig = {
824
+ validationMessages: {
825
+ fieldName: {
826
+ required: '列名不能为空',
827
+ thyUniqueCheck: '列名已存在'
828
+ }
829
+ }
830
+ };
831
+ this.selectableFields = Fields;
832
+ this.thyPopoverRef = inject((ThyPopoverRef));
833
+ this.checkUniqueName = (fieldName) => {
834
+ fieldName = fieldName?.trim();
835
+ return of(!!this.aiTable.fields()?.find((field) => field.name === fieldName && this.aiField()?._id !== field._id));
836
+ };
837
+ }
838
+ selectFieldType(fieldType) {
839
+ this.aiField.update((item) => ({ ...item, type: fieldType, name: createDefaultFieldName(this.aiTable, fieldType) }));
840
+ }
841
+ editFieldProperty() {
842
+ if (this.isUpdate) {
843
+ const path = this.aiTable.fields().findIndex((item) => item._id === this.aiField()._id);
844
+ Actions.setField(this.aiTable, this.aiField(), [path]);
845
+ }
846
+ else {
847
+ Actions.addField(this.aiTable, this.aiField(), [this.aiTable.fields().length]);
848
+ }
849
+ this.thyPopoverRef.close();
850
+ }
851
+ cancel() {
852
+ this.thyPopoverRef.close();
853
+ }
854
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
855
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableFieldPropertyEditor, isStandalone: true, selector: "ai-table-field-property-editor", inputs: { aiField: { classPropertyName: "aiField", publicName: "aiField", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null }, aiExternalTemplate: { classPropertyName: "aiExternalTemplate", publicName: "aiExternalTemplate", isSignal: false, isRequired: false, transformFunction: null }, isUpdate: { classPropertyName: "isUpdate", publicName: "isUpdate", isSignal: false, isRequired: false, transformFunction: booleanAttribute } }, outputs: { aiField: "aiFieldChange" }, host: { classAttribute: "field-property-editor d-block pl-5 pr-5 pb-5 pt-4" }, ngImport: i0, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track $index) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyInputGroup, selector: "thy-input-group", inputs: ["thyAppendText", "thyAppendTextTranslateKey", "thyPrependText", "thyPrependTextTranslateKey", "thySize"] }, { kind: "component", type: ThyInputCount, selector: "thy-input-count", inputs: ["thyInput"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyUniqueCheckValidator, selector: "[thyUniqueCheck]", inputs: ["thyUniqueCheck"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }, { kind: "directive", type: ThyDropdownMenuItemNameDirective, selector: "[thyDropdownMenuItemName]" }, { kind: "component", type: ThyButton, selector: "thy-button,[thy-button],[thyButton]", inputs: ["thyButton", "thyType", "thyLoading", "thyLoadingText", "thySize", "thyIcon", "thyBlock"] }, { kind: "ngmodule", type: ThyFormModule }, { kind: "directive", type: i2.ThyFormDirective, selector: "[thyForm],[thy-form]", inputs: ["thyLayout", "thyEnterKeyMode", "thyFormValidatorConfig"], exportAs: ["thyForm"] }, { kind: "component", type: i2.ThyFormGroup, selector: "thy-form-group", inputs: ["thyLabelText", "thyLabelTextTranslateKey", "thyLabelRequired", "thyLabelPaddingTopClear", "thyFeedbackIcon", "thyTipsMode", "thyTips", "thyTipsTranslateKey", "thyRowFill"] }, { kind: "directive", type: i2.ThyFormSubmitDirective, selector: "[thyFormSubmit],[thy-form-submit]", outputs: ["thyFormSubmit"] }, { kind: "component", type: i2.ThyFormGroupFooter, selector: "thy-form-group-footer", inputs: ["thyAlign"] }, { kind: "component", type: ThyListItem, selector: "thy-list-item,[thy-list-item]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
856
+ }
857
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, decorators: [{
858
+ type: Component,
859
+ args: [{ selector: 'ai-table-field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
860
+ NgIf,
861
+ NgForOf,
862
+ FormsModule,
863
+ ThyIcon,
864
+ ThyInput,
865
+ ThyInputGroup,
866
+ ThyInputCount,
867
+ ThyInputDirective,
868
+ ThyConfirmValidatorDirective,
869
+ ThyUniqueCheckValidator,
870
+ ThyDropdownDirective,
871
+ ThyDropdownMenuComponent,
872
+ ThyDropdownMenuItemDirective,
873
+ ThyDropdownMenuItemNameDirective,
874
+ ThyDropdownMenuItemIconDirective,
875
+ ThyButton,
876
+ ThyFormModule,
877
+ ThyListItem,
878
+ NgTemplateOutlet,
879
+ ThyAutofocusDirective
880
+ ], host: {
881
+ class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
882
+ }, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track $index) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"] }]
883
+ }], ctorParameters: () => [], propDecorators: { aiTable: [{
884
+ type: Input,
885
+ args: [{ required: true }]
886
+ }], aiExternalTemplate: [{
887
+ type: Input
888
+ }], isUpdate: [{
889
+ type: Input,
890
+ args: [{ transform: booleanAttribute }]
891
+ }] } });
892
+
893
+ const buildGridData = (recordValue, fieldsValue, references) => {
894
+ const fields = fieldsValue.map((item) => {
895
+ return {
896
+ ...item,
897
+ icon: item.icon || FieldsMap[item.type].icon,
898
+ width: item.width || FieldsMap[item.type].width
899
+ };
900
+ });
901
+ let records = buildRecordsByReferences(recordValue, fieldsValue, references);
902
+ return {
903
+ type: 'grid',
904
+ fields,
905
+ records
906
+ };
907
+ };
908
+ function buildRecordsByReferences(records, fields, references) {
909
+ if (!references) {
910
+ return records;
911
+ }
912
+ const memberFields = fields.filter((field) => [AITableFieldType.createdBy, AITableFieldType.updatedBy, AITableFieldType.member].includes(field.type));
913
+ if (memberFields.length) {
914
+ const uidToMember = references.members.reduce((map, member) => {
915
+ map[member.uid] = member;
916
+ return map;
917
+ }, {});
918
+ const draftRecords = createDraft(records);
919
+ draftRecords.forEach((record) => {
920
+ memberFields.forEach((field) => {
921
+ const value = record.values[field._id];
922
+ if (field.isMultiple) {
923
+ record.values[field._id] = value.map((uid) => uidToMember[uid]).filter(Boolean);
924
+ }
925
+ else {
926
+ record.values[field._id] = uidToMember[value] || {};
927
+ }
928
+ });
929
+ });
930
+ records = finishDraft(draftRecords);
931
+ }
932
+ return records;
933
+ }
934
+
935
+ function getRecordOrField(value, _id) {
936
+ return computed(() => {
937
+ return value().find((item) => item._id === _id);
938
+ });
939
+ }
940
+
941
+ class FieldMenu {
942
+ execute(menu) {
943
+ const field = getRecordOrField(this.aiTable.fields, this.fieldId);
944
+ menu.exec && menu.exec(this.aiTable, field, this.origin);
945
+ }
946
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
947
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldMenu, isStandalone: true, selector: "field-menu", inputs: { fieldId: "fieldId", aiTable: "aiTable", fieldMenus: "fieldMenus", origin: "origin" }, ngImport: i0, template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.type === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n", dependencies: [{ kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyDivider, selector: "thy-divider", inputs: ["thyVertical", "thyStyle", "thyColor", "thyText", "thyTextDirection", "thyDeeper"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
948
+ }
949
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, decorators: [{
950
+ type: Component,
951
+ args: [{ selector: 'field-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
952
+ ThyIcon,
953
+ ThyDivider,
954
+ ThyDropdownMenuComponent,
955
+ ThyDropdownMenuItemDirective,
956
+ ThyDropdownMenuItemNameDirective,
957
+ ThyDropdownMenuItemIconDirective
958
+ ], template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.type === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n" }]
959
+ }], propDecorators: { fieldId: [{
960
+ type: Input,
961
+ args: [{ required: true }]
962
+ }], aiTable: [{
963
+ type: Input,
964
+ args: [{ required: true }]
965
+ }], fieldMenus: [{
966
+ type: Input,
967
+ args: [{ required: true }]
968
+ }], origin: [{
969
+ type: Input
970
+ }] } });
971
+
972
+ const DEFAULT_COLUMN_WIDTH = 200;
973
+ const MIN_COLUMN_WIDTH = 80;
974
+ const DBL_CLICK_EDIT_TYPE = [
975
+ AITableFieldType.text,
976
+ AITableFieldType.number,
977
+ AITableFieldType.select,
978
+ AITableFieldType.date,
979
+ AITableFieldType.member
980
+ ];
981
+ const MOUSEOVER_EDIT_TYPE = [AITableFieldType.progress];
982
+ const RowHeight = {
983
+ Short: 32,
984
+ Medium: 57,
985
+ Tall: 104,
986
+ ExtraTall: 152
987
+ };
988
+
989
+ const AI_TABLE_GRID_FIELD_SERVICE_MAP = new WeakMap();
990
+ class AITableGridFieldService {
991
+ constructor(thyPopover) {
992
+ this.thyPopover = thyPopover;
993
+ }
994
+ initAIFieldConfig(aiFieldConfig) {
995
+ this.aiFieldConfig = aiFieldConfig;
996
+ }
997
+ editFieldProperty(origin, aiTable, aiField, isUpdate) {
998
+ const component = this.aiFieldConfig?.fieldPropertyEditor ?? AITableFieldPropertyEditor;
999
+ this.thyPopover.open(component, {
1000
+ origin: origin,
1001
+ manualClosure: true,
1002
+ placement: 'bottomLeft',
1003
+ initialState: {
1004
+ aiTable,
1005
+ aiField,
1006
+ isUpdate
1007
+ }
1008
+ });
1009
+ }
1010
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
1011
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService }); }
1012
+ }
1013
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, decorators: [{
1014
+ type: Injectable
1015
+ }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
1016
+
1017
+ const DividerMenuItem = {
1018
+ type: 'divider'
1019
+ };
1020
+ const EditFieldPropertyItem = {
1021
+ type: 'editFieldProperty',
1022
+ name: '编辑列',
1023
+ icon: 'edit',
1024
+ exec: (aiTable, field, origin) => {
1025
+ const fieldService = AI_TABLE_GRID_FIELD_SERVICE_MAP.get(aiTable);
1026
+ const copyField = signal(JSON.parse(JSON.stringify(field())));
1027
+ origin && fieldService?.editFieldProperty(origin, aiTable, copyField, true);
1028
+ }
1029
+ };
1030
+ const RemoveFieldItem = {
1031
+ type: 'removeField',
1032
+ name: '删除列',
1033
+ icon: 'trash',
1034
+ exec: (aiTable, field) => {
1035
+ const path = AITableQueries.findPath(aiTable, field());
1036
+ Actions.removeField(aiTable, path);
1037
+ }
1038
+ };
1039
+ const DefaultFieldMenus = [EditFieldPropertyItem, RemoveFieldItem];
1040
+
1041
+ class SelectOptionPipe {
1042
+ transform(_id, options) {
1043
+ return options.find((item) => item._id === _id);
1044
+ }
1045
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1046
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, isStandalone: true, name: "selectOption" }); }
1047
+ }
1048
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, decorators: [{
1049
+ type: Pipe,
1050
+ args: [{
1051
+ name: 'selectOption',
1052
+ standalone: true
1053
+ }]
1054
+ }] });
1055
+ class IsSelectRecordPipe {
1056
+ transform(recordId, selection) {
1057
+ return selection.selectedRecords.has(recordId);
1058
+ }
1059
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1060
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, isStandalone: true, name: "isSelectRecord" }); }
1061
+ }
1062
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, decorators: [{
1063
+ type: Pipe,
1064
+ args: [{
1065
+ name: 'isSelectRecord',
1066
+ standalone: true
841
1067
  }]
842
1068
  }] });
843
1069
 
@@ -856,7 +1082,7 @@ class SelectCellEditorComponent extends AbstractEditCellEditor {
856
1082
  }
857
1083
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
858
1084
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: SelectCellEditorComponent, isStandalone: true, selector: "single-select-cell-editor", inputs: { isMultiple: "isMultiple" }, host: { classAttribute: "d-block h-100" }, usesInheritance: true, ngImport: i0, template: `<thy-select [(ngModel)]="modelValue" [thyAutoExpand]="true" (thyOnExpandStatusChange)="updateValue($event)">
859
- <thy-option *ngFor="let option of selectOptions()" [thyValue]="option.id" [thyLabelText]="option.name"> </thy-option>
1085
+ <thy-option *ngFor="let option of selectOptions()" [thyValue]="option._id" [thyLabelText]="option.text"> </thy-option>
860
1086
  </thy-select> `, isInline: true, dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThySelect, selector: "thy-select,thy-custom-select", inputs: ["thyDropdownWidthMode", "thyShowSearch", "thyPlaceHolder", "thyServerSearch", "thyLoadState", "thyAutoActiveFirstItem", "thyMode", "thySize", "thyEmptyStateText", "thyEmptySearchMessageText", "thyEnableScrollLoad", "thyAllowClear", "thyDisabled", "thySortComparator", "thyFooterTemplate", "thyPlacement", "thyOrigin", "thyFooterClass", "thyAutoExpand", "thyHasBackdrop", "thyMaxTagCount", "thyBorderless", "thyOptions", "thyPreset"], outputs: ["thyOnSearch", "thyOnScrollToBottom", "thyOnExpandStatusChange"], exportAs: ["thySelect"] }, { kind: "component", type: ThyOption, selector: "thy-option", inputs: ["thyValue", "thyRawValue", "thyLabelText", "thyShowOptionCustom", "thySearchKey", "thyDisabled"], outputs: ["selectionChange", "visibleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
861
1087
  }
862
1088
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectCellEditorComponent, decorators: [{
@@ -864,7 +1090,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
864
1090
  args: [{
865
1091
  selector: 'single-select-cell-editor',
866
1092
  template: `<thy-select [(ngModel)]="modelValue" [thyAutoExpand]="true" (thyOnExpandStatusChange)="updateValue($event)">
867
- <thy-option *ngFor="let option of selectOptions()" [thyValue]="option.id" [thyLabelText]="option.name"> </thy-option>
1093
+ <thy-option *ngFor="let option of selectOptions()" [thyValue]="option._id" [thyLabelText]="option.text"> </thy-option>
868
1094
  </thy-select> `,
869
1095
  standalone: true,
870
1096
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -879,18 +1105,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
879
1105
 
880
1106
  const GRID_CELL_EDITOR_MAP = {
881
1107
  [AITableFieldType.text]: TextCellEditorComponent,
1108
+ [AITableFieldType.richText]: TextCellEditorComponent,
882
1109
  [AITableFieldType.select]: SelectCellEditorComponent,
883
1110
  [AITableFieldType.number]: NumberCellEditorComponent,
884
1111
  [AITableFieldType.date]: DateTimeCellEditorComponent,
885
1112
  [AITableFieldType.rate]: RatingCellEditorComponent,
886
- [AITableFieldType.link]: LinkCellEditorComponent
1113
+ [AITableFieldType.link]: LinkCellEditorComponent,
1114
+ [AITableFieldType.progress]: ProgressEditorComponent
887
1115
  };
888
1116
 
889
1117
  class AITableGridEventService {
890
- constructor(thyPopover) {
891
- this.thyPopover = thyPopover;
892
- this.takeUntilDestroyed = takeUntilDestroyed();
1118
+ constructor() {
1119
+ this.dblClickEvent$ = new Subject();
893
1120
  this.mousedownEvent$ = new Subject();
1121
+ this.mouseoverEvent$ = new Subject();
1122
+ this.globalMouseoverEvent$ = new Subject();
1123
+ this.globalMousedownEvent$ = new Subject();
1124
+ this.destroyRef = inject(DestroyRef);
1125
+ this.thyPopover = inject(ThyPopover);
894
1126
  }
895
1127
  initialize(aiTable, aiFieldRenderers) {
896
1128
  this.aiTable = aiTable;
@@ -898,22 +1130,30 @@ class AITableGridEventService {
898
1130
  }
899
1131
  registerEvents(element) {
900
1132
  fromEvent(element, 'dblclick')
901
- .pipe(this.takeUntilDestroyed)
1133
+ .pipe(takeUntilDestroyed(this.destroyRef))
902
1134
  .subscribe((event) => {
903
- this.dblClick(event);
1135
+ this.dblClickEvent$.next(event);
1136
+ });
1137
+ fromEvent(element, 'mouseover')
1138
+ .pipe(debounceTime(80), takeUntilDestroyed(this.destroyRef))
1139
+ .subscribe((event) => {
1140
+ this.mouseoverEvent$.next(event);
1141
+ });
1142
+ fromEvent(document, 'mouseover')
1143
+ .pipe(takeUntilDestroyed(this.destroyRef))
1144
+ .subscribe((event) => {
1145
+ this.globalMouseoverEvent$.next(event);
904
1146
  });
905
1147
  fromEvent(element, 'mousedown')
906
- .pipe(this.takeUntilDestroyed)
1148
+ .pipe(takeUntilDestroyed(this.destroyRef))
907
1149
  .subscribe((event) => {
908
1150
  this.mousedownEvent$.next(event);
909
1151
  });
910
- }
911
- dblClick(event) {
912
- const cellDom = event.target.closest('.grid-cell');
913
- const type = cellDom && cellDom.getAttribute('type');
914
- if (type && DBL_CLICK_EDIT_TYPE.includes(type)) {
915
- this.openEdit(cellDom);
916
- }
1152
+ fromEvent(document, 'mousedown')
1153
+ .pipe(takeUntilDestroyed(this.destroyRef))
1154
+ .subscribe((event) => {
1155
+ this.globalMousedownEvent$.next(event);
1156
+ });
917
1157
  }
918
1158
  getEditorComponent(type) {
919
1159
  if (this.aiFieldRenderers && this.aiFieldRenderers[type]) {
@@ -928,7 +1168,7 @@ class AITableGridEventService {
928
1168
  const field = getRecordOrField(this.aiTable.fields, fieldId);
929
1169
  const record = getRecordOrField(this.aiTable.records, recordId);
930
1170
  const component = this.getEditorComponent(field().type);
931
- this.thyPopover.open(component, {
1171
+ const ref = this.thyPopover.open(component, {
932
1172
  origin: cellDom,
933
1173
  originPosition: {
934
1174
  x: x - 1,
@@ -936,7 +1176,7 @@ class AITableGridEventService {
936
1176
  width: width + 2,
937
1177
  height: height + 2
938
1178
  },
939
- width: width + 2 + 'px',
1179
+ width: width + 1 + 'px',
940
1180
  height: height + 2 + 'px',
941
1181
  placement: 'top',
942
1182
  offset: -(height + 4),
@@ -950,46 +1190,17 @@ class AITableGridEventService {
950
1190
  outsideClosable: false,
951
1191
  hasBackdrop: false,
952
1192
  manualClosure: true,
953
- animationDisabled: true
1193
+ animationDisabled: true,
1194
+ autoAdaptive: true
954
1195
  });
1196
+ return ref;
955
1197
  }
956
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
1198
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
957
1199
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService }); }
958
1200
  }
959
1201
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, decorators: [{
960
1202
  type: Injectable
961
- }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
962
-
963
- class FieldMenu {
964
- execute(menu) {
965
- const field = getRecordOrField(this.aiTable.fields, this.fieldId);
966
- menu.exec && menu.exec(this.aiTable, field, this.origin);
967
- }
968
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
969
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldMenu, isStandalone: true, selector: "field-menu", inputs: { fieldId: "fieldId", aiTable: "aiTable", fieldMenus: "fieldMenus", origin: "origin" }, ngImport: i0, template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.id === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n", dependencies: [{ kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyDivider, selector: "thy-divider", inputs: ["thyVertical", "thyStyle", "thyColor", "thyText", "thyTextDirection", "thyDeeper"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
970
- }
971
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, decorators: [{
972
- type: Component,
973
- args: [{ selector: 'field-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
974
- ThyIcon,
975
- ThyDivider,
976
- ThyDropdownMenuComponent,
977
- ThyDropdownMenuItemDirective,
978
- ThyDropdownMenuItemNameDirective,
979
- ThyDropdownMenuItemIconDirective
980
- ], template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.id === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n" }]
981
- }], propDecorators: { fieldId: [{
982
- type: Input,
983
- args: [{ required: true }]
984
- }], aiTable: [{
985
- type: Input,
986
- args: [{ required: true }]
987
- }], fieldMenus: [{
988
- type: Input,
989
- args: [{ required: true }]
990
- }], origin: [{
991
- type: Input
992
- }] } });
1203
+ }] });
993
1204
 
994
1205
  class AITableGridSelectionService {
995
1206
  constructor() { }
@@ -1028,23 +1239,31 @@ class AITableGridSelectionService {
1028
1239
  this.clearSelection();
1029
1240
  if (checked) {
1030
1241
  this.aiTable.records().forEach((item) => {
1031
- this.selectRecord(item.id);
1242
+ this.selectRecord(item._id);
1032
1243
  });
1033
1244
  }
1034
1245
  }
1035
1246
  updateSelect(event) {
1036
- const target = event.target;
1247
+ const target = event?.target;
1248
+ if (!target) {
1249
+ return;
1250
+ }
1037
1251
  const cellDom = target.closest('.grid-cell');
1038
1252
  const colDom = target.closest('.grid-field');
1253
+ const checkbox = target.tagName === 'INPUT' && target.type === 'checkbox' && target.closest('.grid-checkbox');
1254
+ const fieldAction = target.closest('.grid-field-action');
1039
1255
  if (cellDom) {
1040
1256
  const fieldId = cellDom.getAttribute('fieldId');
1041
1257
  const recordId = cellDom.getAttribute('recordId');
1042
1258
  fieldId && recordId && this.selectCell(recordId, fieldId);
1043
1259
  }
1044
- if (colDom) {
1260
+ if (colDom && !fieldAction) {
1045
1261
  const fieldId = colDom.getAttribute('fieldId');
1046
1262
  fieldId && this.selectField(fieldId);
1047
1263
  }
1264
+ if (!cellDom && !colDom && !checkbox) {
1265
+ this.clearSelection();
1266
+ }
1048
1267
  }
1049
1268
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridSelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1050
1269
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridSelectionService }); }
@@ -1054,40 +1273,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
1054
1273
  }], ctorParameters: () => [] });
1055
1274
 
1056
1275
  class AITableGrid {
1057
- get isSelectedAll() {
1058
- return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
1059
- }
1060
- constructor(elementRef, aiTableGridEventService, aiTableGridSelectionService, aiTableGridFieldService, ngZone) {
1061
- this.elementRef = elementRef;
1062
- this.aiTableGridEventService = aiTableGridEventService;
1063
- this.aiTableGridSelectionService = aiTableGridSelectionService;
1064
- this.aiTableGridFieldService = aiTableGridFieldService;
1065
- this.ngZone = ngZone;
1276
+ constructor() {
1066
1277
  this.aiRecords = model.required();
1067
1278
  this.aiFields = model.required();
1068
- this.aiRowHeight = input();
1069
1279
  this.aiFieldConfig = input();
1070
1280
  this.aiReadonly = input();
1071
1281
  this.aiPlugins = input();
1282
+ this.aiReferences = input();
1072
1283
  this.AITableFieldType = AITableFieldType;
1073
- this.takeUntilDestroyed = takeUntilDestroyed();
1284
+ this.isSelectedAll = computed(() => {
1285
+ return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
1286
+ });
1074
1287
  this.onChange = output();
1075
1288
  this.aiTableInitialized = output();
1076
1289
  this.gridData = computed(() => {
1077
- return buildGridData(this.aiRecords(), this.aiFields(), this.aiTable.selection());
1290
+ return buildGridData(this.aiRecords(), this.aiFields(), this.aiReferences());
1078
1291
  });
1292
+ this.ngZone = inject(NgZone);
1293
+ this.elementRef = inject(ElementRef);
1294
+ this.destroyRef = inject(DestroyRef);
1295
+ this.aiTableGridFieldService = inject(AITableGridFieldService);
1296
+ this.aiTableGridEventService = inject(AITableGridEventService);
1297
+ this.aiTableGridSelectionService = inject(AITableGridSelectionService);
1079
1298
  }
1080
1299
  ngOnInit() {
1081
1300
  this.initAITable();
1082
1301
  this.initService();
1083
1302
  this.buildFieldMenus();
1084
- this.ngZone.runOutsideAngular(() => {
1085
- this.aiTableGridEventService.mousedownEvent$.pipe(this.takeUntilDestroyed).subscribe((event) => {
1086
- if (event?.target) {
1087
- this.aiTableGridSelectionService.updateSelect(event);
1088
- }
1089
- });
1090
- });
1303
+ this.subscribeEvents();
1091
1304
  }
1092
1305
  initAITable() {
1093
1306
  this.aiTable = createAITable(this.aiRecords, this.aiFields);
@@ -1126,8 +1339,53 @@ class AITableGrid {
1126
1339
  const field = signal(createDefaultField(this.aiTable, AITableFieldType.text));
1127
1340
  this.aiTableGridFieldService.editFieldProperty(gridColumnBlank, this.aiTable, field, false);
1128
1341
  }
1129
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, deps: [{ token: i0.ElementRef }, { token: AITableGridEventService }, { token: AITableGridSelectionService }, { token: AITableGridFieldService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
1130
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableGrid, isStandalone: true, selector: "ai-table-grid", inputs: { aiRecords: { classPropertyName: "aiRecords", publicName: "aiRecords", isSignal: true, isRequired: true, transformFunction: null }, aiFields: { classPropertyName: "aiFields", publicName: "aiFields", isSignal: true, isRequired: true, transformFunction: null }, aiRowHeight: { classPropertyName: "aiRowHeight", publicName: "aiRowHeight", isSignal: true, isRequired: false, transformFunction: null }, aiFieldConfig: { classPropertyName: "aiFieldConfig", publicName: "aiFieldConfig", isSignal: true, isRequired: false, transformFunction: null }, aiReadonly: { classPropertyName: "aiReadonly", publicName: "aiReadonly", isSignal: true, isRequired: false, transformFunction: null }, aiPlugins: { classPropertyName: "aiPlugins", publicName: "aiPlugins", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange", aiTableInitialized: "aiTableInitialized" }, host: { classAttribute: "ai-table-grid" }, providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field.id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field.id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field.id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field.id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record.id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: aiTable.selection().selectedRecords.has(record.id) }\">\n <div class=\"grid-row-index\">\n <label\n [ngClass]=\"record.checked ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record.checked\"\n (ngModelChange)=\"selectRecord(record.id)\"\n ></label>\n <span [ngClass]=\"record.checked ? 'grid-row-no-number' : 'grid-row-number'\"> {{ index + 1 }} </span>\n </div>\n @for (field of gridData().fields; track $index) {\n <div\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record.id) || aiTable.selection().selectedFields.has(field.id),\n selected: aiTable.selection().selectedCells.get(record.id)?.hasOwnProperty(field.id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field.id]\"\n [attr.recordId]=\"[record.id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n #cell\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.rate) {\n <thy-rate [(ngModel)]=\"record.values[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field.id]?.text\"\n [href]=\"record.values[field.id]?.url\"\n target=\"_blank\"\n >{{ record.values[field.id]?.text }}</a\n >\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field.id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SelectOptionPipe, name: "selectOption" }, { kind: "component", type: ThyTag, selector: "thy-tag,[thyTag]", inputs: ["thyTag", "thyShape", "thyColor", "thyTheme", "thySize", "thyHoverable"] }, { kind: "ngmodule", type: ThyPopoverModule }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "pipe", type: ThyDatePickerFormatPipe, name: "thyDatePickerFormat" }, { kind: "ngmodule", type: ThyTooltipModule }, { kind: "component", type: ThyFlexibleText, selector: "thy-flexible-text,[thyFlexibleText]", inputs: ["thyTooltipTrigger", "thyContainerClass", "thyTooltipContent", "thyTooltipPlacement", "thyTooltipOffset"], exportAs: ["thyFlexibleText"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "component", type: FieldMenu, selector: "field-menu", inputs: ["fieldId", "aiTable", "fieldMenus", "origin"] }, { kind: "component", type: ThyAction, selector: "thy-action, [thyAction]", inputs: ["thyType", "thyIcon", "thyActionIcon", "thyActive", "thyActionActive", "thyTheme", "thyHoverIcon", "thyDisabled"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "ngmodule", type: ThyCheckboxModule }, { kind: "component", type: i6.ThyCheckbox, selector: "thy-checkbox,[thy-checkbox],[thyCheckbox]", inputs: ["thyIndeterminate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1342
+ subscribeEvents() {
1343
+ this.ngZone.runOutsideAngular(() => {
1344
+ this.aiTableGridEventService.dblClickEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1345
+ this.dblClick(event);
1346
+ });
1347
+ this.aiTableGridEventService.mousedownEvent$
1348
+ .pipe(mergeWith(this.aiTableGridEventService.globalMousedownEvent$), takeUntilDestroyed(this.destroyRef))
1349
+ .subscribe((event) => {
1350
+ this.aiTableGridSelectionService.updateSelect(event);
1351
+ });
1352
+ this.aiTableGridEventService.mouseoverEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1353
+ this.mouseoverHandle(event);
1354
+ });
1355
+ this.aiTableGridEventService.globalMouseoverEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1356
+ this.closeHoverCellEditor(event);
1357
+ });
1358
+ });
1359
+ }
1360
+ dblClick(event) {
1361
+ const cellDom = event.target.closest('.grid-cell');
1362
+ const type = cellDom && cellDom.getAttribute('type');
1363
+ const readonly = cellDom && cellDom.getAttribute('readonly');
1364
+ if (type && !readonly && DBL_CLICK_EDIT_TYPE.includes(type)) {
1365
+ this.aiTableGridEventService.openEdit(cellDom);
1366
+ }
1367
+ }
1368
+ mouseoverHandle(event) {
1369
+ if (this.mouseoverRef) {
1370
+ this.mouseoverRef?.close();
1371
+ }
1372
+ const cellDom = event.target.closest('.grid-cell');
1373
+ const type = cellDom && cellDom.getAttribute('type');
1374
+ if (type && MOUSEOVER_EDIT_TYPE.includes(type)) {
1375
+ this.mouseoverRef = this.aiTableGridEventService.openEdit(cellDom);
1376
+ }
1377
+ }
1378
+ closeHoverCellEditor(e) {
1379
+ if (this.mouseoverRef) {
1380
+ const hasGrid = e.target && e.target.closest('.ai-table-grid');
1381
+ const hasCellEditor = e.target && e.target.closest('.grid-cell-editor');
1382
+ if (!hasGrid && !hasCellEditor) {
1383
+ this.mouseoverRef.close();
1384
+ }
1385
+ }
1386
+ }
1387
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1388
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableGrid, isStandalone: true, selector: "ai-table-grid", inputs: { aiRecords: { classPropertyName: "aiRecords", publicName: "aiRecords", isSignal: true, isRequired: true, transformFunction: null }, aiFields: { classPropertyName: "aiFields", publicName: "aiFields", isSignal: true, isRequired: true, transformFunction: null }, aiFieldConfig: { classPropertyName: "aiFieldConfig", publicName: "aiFieldConfig", isSignal: true, isRequired: false, transformFunction: null }, aiReadonly: { classPropertyName: "aiReadonly", publicName: "aiReadonly", isSignal: true, isRequired: false, transformFunction: null }, aiPlugins: { classPropertyName: "aiPlugins", publicName: "aiPlugins", isSignal: true, isRequired: false, transformFunction: null }, aiReferences: { classPropertyName: "aiReferences", publicName: "aiReferences", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange", aiTableInitialized: "aiTableInitialized" }, host: { classAttribute: "ai-table-grid" }, providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell grid-checkbox\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll()\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field._id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field._id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field._id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record._id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: (record._id | isSelectRecord: aiTable.selection()) }\">\n <div class=\"grid-row-index grid-checkbox\">\n <label\n [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record._id | isSelectRecord: aiTable.selection()\"\n (ngModelChange)=\"selectRecord(record._id)\"\n ></label>\n <span [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'grid-row-no-number' : 'grid-row-number'\">\n {{ index + 1 }}\n </span>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n #cell\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record._id) || aiTable.selection().selectedFields.has(field._id),\n selected: aiTable.selection().selectedCells.get(record._id)?.hasOwnProperty(field._id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field._id]\"\n [attr.readonly]=\"[field?.readonly]\"\n [attr.recordId]=\"[record._id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field._id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.text }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field._id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.updatedAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.createdAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.rate) {\n <thy-rate [ngModel]=\"record.values[field._id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n target=\"_blank\"\n [href]=\"record.values[field._id]?.url\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field._id]?.text\"\n >\n {{ record.values[field._id]?.text }}\n </a>\n }\n @case (AITableFieldType.progress) {\n <thy-progress\n class=\"w-100\"\n [thyValue]=\"record.values[field._id]\"\n [thySize]=\"record.values[field._id]?.config?.size || 'md'\"\n [thyMax]=\"record.values[field._id]?.config?.max || 100\"\n [thyType]=\"record.values[field._id]?.config?.progressType || 'success'\"\n >\n <span> {{ record.values[field._id] }}{{ record.values[field._id]?.config?.suffix || '%' }} </span>\n </thy-progress>\n }\n @case (AITableFieldType.member) {\n @if (!field.isMultiple) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n } @else {\n <thy-avatar-list thyAvatarSize=\"xs\">\n @for (item of record.values[field._id]; track $index) {\n <thy-avatar [thyName]=\"item.display_name\" [thySrc]=\"item.avatar\"></thy-avatar>\n }\n </thy-avatar-list>\n }\n }\n @case (AITableFieldType.createdBy) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n @case (AITableFieldType.updatedBy) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field._id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SelectOptionPipe, name: "selectOption" }, { kind: "component", type: ThyTag, selector: "thy-tag,[thyTag]", inputs: ["thyTag", "thyShape", "thyColor", "thyTheme", "thySize", "thyHoverable"] }, { kind: "ngmodule", type: ThyPopoverModule }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "component", type: ThyProgress, selector: "thy-progress", inputs: ["thyType", "thySize", "thyValue", "thyMax", "thyTips", "thyShape", "thyGapDegree", "thyGapPosition", "thyStrokeWidth"] }, { kind: "pipe", type: ThyDatePickerFormatPipe, name: "thyDatePickerFormat" }, { kind: "component", type: ThyFlexibleText, selector: "thy-flexible-text,[thyFlexibleText]", inputs: ["thyTooltipTrigger", "thyContainerClass", "thyTooltipContent", "thyTooltipPlacement", "thyTooltipOffset"], exportAs: ["thyFlexibleText"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "component", type: FieldMenu, selector: "field-menu", inputs: ["fieldId", "aiTable", "fieldMenus", "origin"] }, { kind: "component", type: ThyAction, selector: "thy-action, [thyAction]", inputs: ["thyType", "thyIcon", "thyActionIcon", "thyActive", "thyActionActive", "thyTheme", "thyHoverIcon", "thyDisabled"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "ngmodule", type: ThyCheckboxModule }, { kind: "component", type: i3.ThyCheckbox, selector: "thy-checkbox,[thy-checkbox],[thyCheckbox]", inputs: ["thyIndeterminate"] }, { kind: "ngmodule", type: ThyAvatarModule }, { kind: "component", type: i4.ThyAvatar, selector: "thy-avatar", inputs: ["thyShowName", "thySrc", "thyName", "thySize", "thyShowRemove", "thyRemovable", "thyImgClass", "thyDisabled", "thyLoading", "thyFetchPriority"], outputs: ["thyOnRemove", "thyRemove", "thyError"] }, { kind: "component", type: i4.ThyAvatarList, selector: "thy-avatar-list", inputs: ["thyMode", "thyAvatarSize"] }, { kind: "pipe", type: IsSelectRecordPipe, name: "isSelectRecord" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1131
1389
  }
1132
1390
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, decorators: [{
1133
1391
  type: Component,
@@ -1144,30 +1402,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
1144
1402
  ThyPopoverModule,
1145
1403
  ThyIcon,
1146
1404
  ThyRate,
1405
+ ThyProgress,
1147
1406
  AITableFieldPropertyEditor,
1148
1407
  ThyDatePickerFormatPipe,
1149
- ThyTooltipModule,
1150
1408
  ThyFlexibleText,
1151
1409
  ThyStopPropagationDirective,
1152
1410
  FieldMenu,
1153
1411
  ThyAction,
1154
1412
  ThyDropdownDirective,
1155
1413
  ThyDropdownMenuComponent,
1156
- ThyCheckboxModule
1157
- ], providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field.id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field.id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field.id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field.id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record.id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: aiTable.selection().selectedRecords.has(record.id) }\">\n <div class=\"grid-row-index\">\n <label\n [ngClass]=\"record.checked ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record.checked\"\n (ngModelChange)=\"selectRecord(record.id)\"\n ></label>\n <span [ngClass]=\"record.checked ? 'grid-row-no-number' : 'grid-row-number'\"> {{ index + 1 }} </span>\n </div>\n @for (field of gridData().fields; track $index) {\n <div\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record.id) || aiTable.selection().selectedFields.has(field.id),\n selected: aiTable.selection().selectedCells.get(record.id)?.hasOwnProperty(field.id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field.id]\"\n [attr.recordId]=\"[record.id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n #cell\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.rate) {\n <thy-rate [(ngModel)]=\"record.values[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field.id]?.text\"\n [href]=\"record.values[field.id]?.url\"\n target=\"_blank\"\n >{{ record.values[field.id]?.text }}</a\n >\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field.id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n" }]
1158
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: AITableGridEventService }, { type: AITableGridSelectionService }, { type: AITableGridFieldService }, { type: i0.NgZone }] });
1159
-
1160
- var AITableRowHeight;
1161
- (function (AITableRowHeight) {
1162
- AITableRowHeight[AITableRowHeight["Short"] = 1] = "Short";
1163
- AITableRowHeight[AITableRowHeight["Medium"] = 2] = "Medium";
1164
- AITableRowHeight[AITableRowHeight["Tall"] = 3] = "Tall";
1165
- AITableRowHeight[AITableRowHeight["ExtraTall"] = 4] = "ExtraTall";
1166
- })(AITableRowHeight || (AITableRowHeight = {}));
1414
+ ThyCheckboxModule,
1415
+ ProgressEditorComponent,
1416
+ ThyAvatarModule,
1417
+ NgTemplateOutlet,
1418
+ IsSelectRecordPipe
1419
+ ], providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell grid-checkbox\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll()\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field._id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field._id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field._id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record._id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: (record._id | isSelectRecord: aiTable.selection()) }\">\n <div class=\"grid-row-index grid-checkbox\">\n <label\n [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record._id | isSelectRecord: aiTable.selection()\"\n (ngModelChange)=\"selectRecord(record._id)\"\n ></label>\n <span [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'grid-row-no-number' : 'grid-row-number'\">\n {{ index + 1 }}\n </span>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n #cell\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record._id) || aiTable.selection().selectedFields.has(field._id),\n selected: aiTable.selection().selectedCells.get(record._id)?.hasOwnProperty(field._id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field._id]\"\n [attr.readonly]=\"[field?.readonly]\"\n [attr.recordId]=\"[record._id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field._id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.text }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field._id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.updatedAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.createdAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.rate) {\n <thy-rate [ngModel]=\"record.values[field._id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n target=\"_blank\"\n [href]=\"record.values[field._id]?.url\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field._id]?.text\"\n >\n {{ record.values[field._id]?.text }}\n </a>\n }\n @case (AITableFieldType.progress) {\n <thy-progress\n class=\"w-100\"\n [thyValue]=\"record.values[field._id]\"\n [thySize]=\"record.values[field._id]?.config?.size || 'md'\"\n [thyMax]=\"record.values[field._id]?.config?.max || 100\"\n [thyType]=\"record.values[field._id]?.config?.progressType || 'success'\"\n >\n <span> {{ record.values[field._id] }}{{ record.values[field._id]?.config?.suffix || '%' }} </span>\n </thy-progress>\n }\n @case (AITableFieldType.member) {\n @if (!field.isMultiple) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n } @else {\n <thy-avatar-list thyAvatarSize=\"xs\">\n @for (item of record.values[field._id]; track $index) {\n <thy-avatar [thyName]=\"item.display_name\" [thySrc]=\"item.avatar\"></thy-avatar>\n }\n </thy-avatar-list>\n }\n }\n @case (AITableFieldType.createdBy) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n @case (AITableFieldType.updatedBy) {\n <thy-avatar\n [thyName]=\"record.values[field._id].display_name\"\n [thySrc]=\"record.values[field._id].avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field._id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>" }]
1420
+ }] });
1167
1421
 
1168
1422
  /**
1169
1423
  * Generated bundle index. Do not edit.
1170
1424
  */
1171
1425
 
1172
- export { AITableFieldPropertyEditor, AITableFieldType, AITableGrid, AITableQueries, AITableRowHeight, AITableStatType, ActionName, Actions, BasicFields, DBL_CLICK_EDIT_TYPE, DEFAULT_COLUMN_WIDTH, DefaultFieldMenus, DividerMenuItem, EditFieldPropertyItem, ExecuteType, FLUSHING, Fields, FieldsMap, MIN_COLUMN_WIDTH, RemoveFieldItem, RowHeight, SelectOptionPipe, buildGridData, createAITable, createDefaultField, createDefaultFieldName, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator, isPathEqual };
1426
+ export { AITableFieldPropertyEditor, AITableFieldType, AITableGrid, AITableQueries, AITableStatType, ActionName, Actions, BasicFields, DBL_CLICK_EDIT_TYPE, DEFAULT_COLUMN_WIDTH, DateTimeCellEditorComponent, DefaultFieldMenus, DividerMenuItem, EditFieldPropertyItem, ExecuteType, FLUSHING, Fields, FieldsMap, IsSelectRecordPipe, LinkCellEditorComponent, MIN_COLUMN_WIDTH, MOUSEOVER_EDIT_TYPE, NumberCellEditorComponent, ProgressEditorComponent, RatingCellEditorComponent, RemoveFieldItem, RowHeight, SelectOptionPipe, TextCellEditorComponent, buildGridData, buildRecordsByReferences, createAITable, createDefaultField, createDefaultFieldName, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator, isPathEqual };
1173
1427
  //# sourceMappingURL=ai-table-grid.mjs.map