fontastic 1.2.0 → 1.3.1

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 (75) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +29 -0
  3. package/README.md +6 -0
  4. package/app/Application.js +4 -4
  5. package/app/Application.ts +13 -13
  6. package/app/config/database.js +1 -1
  7. package/app/config/database.ts +1 -1
  8. package/app/config/mimes.js +23 -23
  9. package/app/config/mimes.ts +35 -29
  10. package/app/core/ConfigManager.js +27 -0
  11. package/app/core/ConfigManager.ts +28 -0
  12. package/app/core/FontFinder.js +66 -15
  13. package/app/core/FontFinder.ts +81 -22
  14. package/app/core/FontManager.js +20 -18
  15. package/app/core/FontManager.ts +21 -19
  16. package/app/core/FontObject.js +44 -24
  17. package/app/core/FontObject.ts +47 -27
  18. package/app/core/MessageHandler.js +70 -19
  19. package/app/core/MessageHandler.ts +82 -21
  20. package/app/core/SystemManager.js +5 -1
  21. package/app/core/SystemManager.ts +5 -1
  22. package/app/database/entity/Collection.schema.js +20 -18
  23. package/app/database/entity/Collection.schema.ts +22 -21
  24. package/app/database/repository/Collection.repository.js +17 -18
  25. package/app/database/repository/Collection.repository.ts +27 -18
  26. package/app/database/repository/Store.repository.js +13 -18
  27. package/app/database/repository/Store.repository.ts +13 -21
  28. package/app/enums/ChannelType.js +18 -0
  29. package/app/enums/ChannelType.ts +24 -0
  30. package/app/main.js +79 -2
  31. package/app/main.ts +100 -3
  32. package/app/package.json +1 -1
  33. package/app/types/NativeThemeState.js +3 -0
  34. package/app/types/NativeThemeState.ts +4 -0
  35. package/app/types/ScanProgress.js +3 -0
  36. package/app/types/ScanProgress.ts +6 -0
  37. package/app/types/SystemPreferencesState.js +3 -0
  38. package/app/types/SystemPreferencesState.ts +4 -0
  39. package/app/types/index.js +3 -0
  40. package/app/types/index.ts +3 -0
  41. package/package.json +1 -1
  42. package/src/app/core/services/database/database.service.ts +6 -0
  43. package/src/app/core/services/message/message.service.ts +33 -1
  44. package/src/app/core/services/presentation/presentation.service.ts +93 -1
  45. package/src/app/layout/footer/footer.component.html +13 -2
  46. package/src/app/layout/footer/footer.component.ts +18 -2
  47. package/src/app/layout/navigation/navigation.component.html +11 -9
  48. package/src/app/layout/navigation/navigation.component.ts +35 -0
  49. package/src/app/settings/ai-keys/ai-keys.component.ts +13 -18
  50. package/src/app/settings/danger-zone/danger-zone.component.html +8 -0
  51. package/src/app/settings/danger-zone/danger-zone.component.ts +12 -0
  52. package/src/app/settings/news-api/news-api.component.ts +6 -8
  53. package/src/app/settings/theme/theme.component.html +15 -2
  54. package/src/app/settings/theme/theme.component.ts +4 -0
  55. package/src/app/shared/components/datagrid/datagrid.component.html +8 -17
  56. package/src/app/shared/components/datagrid/datagrid.component.ts +6 -10
  57. package/src/app/shared/components/glyphs/glyphs.component.html +5 -15
  58. package/src/app/shared/components/glyphs/glyphs.component.ts +3 -0
  59. package/src/app/shared/components/preview/preview.component.html +1 -1
  60. package/src/app/shared/components/preview/preview.component.ts +3 -8
  61. package/src/app/shared/components/prompt-dialog/prompt-dialog.component.html +2 -2
  62. package/src/app/shared/components/prompt-dialog/prompt-dialog.component.ts +2 -1
  63. package/src/app/shared/components/rule-builder/rule-builder.component.html +18 -6
  64. package/src/app/shared/components/rule-builder/rule-builder.component.ts +34 -2
  65. package/src/app/shared/components/search/search.component.html +9 -36
  66. package/src/app/shared/components/search/search.component.ts +2 -1
  67. package/src/app/shared/components/waterfall/waterfall.component.html +1 -3
  68. package/src/app/shared/components/waterfall/waterfall.component.ts +2 -1
  69. package/src/app/shared/directives/disabled-opacity/disabled-opacity.directive.ts +18 -0
  70. package/src/app/shared/directives/hover-highlight/hover-highlight.directive.ts +38 -0
  71. package/src/app/shared/directives/index.ts +5 -0
  72. package/src/app/shared/directives/modal-backdrop/modal-backdrop.directive.ts +18 -0
  73. package/src/app/shared/directives/scroll-reset/scroll-reset.directive.ts +15 -0
  74. package/src/app/shared/directives/stop-propagation/stop-propagation.directive.ts +12 -0
  75. package/src/index.html +1 -1
@@ -1,4 +1,4 @@
1
- import { ipcMain, IpcMainEvent } from 'electron';
1
+ import { ipcMain, IpcMainEvent, BrowserWindow, MessageChannelMain, session } from 'electron';
2
2
 
3
3
  import SystemManager from './SystemManager';
4
4
  import ConfigManager from './ConfigManager';
@@ -8,8 +8,6 @@ import FontObject from './FontObject';
8
8
  import AppLogger from './AppLogger';
9
9
 
10
10
  import { Collection } from '../database/entity/Collection.schema';
11
- // import { Logger } from '../database/entity/Logger.schema';
12
- // import { Store, StoreManyAndCountType } from '../database/entity/Store.schema';
13
11
 
14
12
  import { ChannelType } from '../enums/ChannelType';
15
13
  import { StorageType } from '../enums/StorageType';
@@ -19,12 +17,20 @@ export default class MessageHandler {
19
17
  configManager: ConfigManager;
20
18
  connectionManager: ConnectionManager;
21
19
  fontManager: FontManager;
22
-
23
- constructor(systemManager: SystemManager, configManager: ConfigManager, connectionManager: ConnectionManager, fontManager: FontManager) {
20
+ mainWindow: BrowserWindow;
21
+
22
+ constructor(
23
+ systemManager: SystemManager,
24
+ configManager: ConfigManager,
25
+ connectionManager: ConnectionManager,
26
+ fontManager: FontManager,
27
+ mainWindow: BrowserWindow,
28
+ ) {
24
29
  this.systemManager = systemManager;
25
30
  this.configManager = configManager;
26
31
  this.connectionManager = connectionManager;
27
32
  this.fontManager = fontManager;
33
+ this.mainWindow = mainWindow;
28
34
  }
29
35
 
30
36
  on(channel: string, done: any) {
@@ -57,6 +63,22 @@ export default class MessageHandler {
57
63
  this.handle(ChannelType.IPC_GET_CONFIG, async (_event: IpcMainEvent, args: any) => this.configManager.get(args.key));
58
64
  this.handle(ChannelType.IPC_ZAP_CONFIG, async (_event: IpcMainEvent) => this.configManager.clear());
59
65
 
66
+ // Safe Storage
67
+
68
+ this.handle(ChannelType.IPC_SAFE_STORE, async (_event: IpcMainEvent, args: { key: string; value: string }) => {
69
+ this.configManager.setSecure(args.key, args.value);
70
+ });
71
+
72
+ this.handle(ChannelType.IPC_SAFE_RETRIEVE, async (_event: IpcMainEvent, key: string) => {
73
+ return this.configManager.getSecure(key);
74
+ });
75
+
76
+ // Session: Clear Cache
77
+
78
+ this.handle(ChannelType.IPC_CLEAR_CACHE, async () => {
79
+ await session.defaultSession.clearCache();
80
+ });
81
+
60
82
  // Connection Manager
61
83
 
62
84
  this.handle(ChannelType.IPC_DBCONNECTION_CREATE, async (_event: IpcMainEvent, args: any) =>
@@ -93,22 +115,46 @@ export default class MessageHandler {
93
115
  this.handle(ChannelType.IPC_AUTH_USER, async (_event: IpcMainEvent, args: any) => this.fontManager.systemAuthenticate(args));
94
116
 
95
117
  this.handle(ChannelType.IPC_SCAN_FILES, async (_event: IpcMainEvent, args: any) => {
96
- console.log('[IPC_SCAN_FILES] args:', JSON.stringify(args));
97
- const catalogFiles = await this.fontManager.copyFiles(args.files, args.collectionId);
98
- console.log('[IPC_SCAN_FILES] copied to catalog:', catalogFiles);
99
- await this.fontManager.scanFiles(catalogFiles, { collection_id: args.collectionId });
100
- console.log('[IPC_SCAN_FILES] scan complete');
118
+ const { port1, port2 } = new MessageChannelMain();
119
+ this.mainWindow.webContents.postMessage(ChannelType.IPC_SCAN_PROGRESS_PORT, null, [port2]);
120
+
121
+ const onProgress = (progress: any) => {
122
+ try {
123
+ port1.postMessage(progress);
124
+ } catch {
125
+ // Port may be closed if renderer navigated away
126
+ }
127
+ };
128
+
129
+ try {
130
+ const catalogFiles = await this.fontManager.copyFiles(args.files, args.collectionId);
131
+ await this.fontManager.scanFiles(catalogFiles, { collection_id: args.collectionId }, onProgress);
132
+ } finally {
133
+ port1.close();
134
+ }
101
135
  });
102
136
 
103
137
  this.handle(ChannelType.IPC_SCAN_FOLDERS, async (_event: IpcMainEvent, args: any) => {
104
- console.log('[IPC_SCAN_FOLDERS] args:', JSON.stringify(args));
105
- const promises = args.folders.map(async (sourceFolder: string) => {
106
- const dest = await this.fontManager.copyFolder(sourceFolder, args.collectionId);
107
- console.log('[IPC_SCAN_FOLDERS] copied to:', dest);
108
- await this.fontManager.scanFolder(dest, { collection_id: args.collectionId });
109
- console.log('[IPC_SCAN_FOLDERS] scan complete for:', dest);
110
- });
111
- await Promise.allSettled(promises);
138
+ const { port1, port2 } = new MessageChannelMain();
139
+ this.mainWindow.webContents.postMessage(ChannelType.IPC_SCAN_PROGRESS_PORT, null, [port2]);
140
+
141
+ const onProgress = (progress: any) => {
142
+ try {
143
+ port1.postMessage(progress);
144
+ } catch {
145
+ // Port may be closed if renderer navigated away
146
+ }
147
+ };
148
+
149
+ try {
150
+ const promises = args.folders.map(async (sourceFolder: string) => {
151
+ const dest = await this.fontManager.copyFolder(sourceFolder, args.collectionId);
152
+ await this.fontManager.scanFolder(dest, { collection_id: args.collectionId }, onProgress);
153
+ });
154
+ await Promise.allSettled(promises);
155
+ } finally {
156
+ port1.close();
157
+ }
112
158
  });
113
159
 
114
160
  this.handle(ChannelType.IPC_FETCH_NEWS, async (_event: IpcMainEvent, args: any) => this.fontManager.fetchLatestNews(args));
@@ -205,7 +251,12 @@ export default class MessageHandler {
205
251
  this.handle(ChannelType.IPC_SMART_COLLECTION_EVALUATE, async (_event: IpcMainEvent, args: any) => {
206
252
  const sc = await this.connectionManager.getSmartCollectionRepository().findOneBy({ id: args.id });
207
253
  if (!sc) return [[], 0];
208
- const rules = JSON.parse(sc.rules);
254
+ let rules;
255
+ try {
256
+ rules = JSON.parse(sc.rules);
257
+ } catch {
258
+ return [[], 0];
259
+ }
209
260
  return await this.connectionManager.getStoreRepository().evaluateSmartRules(rules, sc.match_type, {
210
261
  skip: args.skip,
211
262
  take: args.take,
@@ -213,6 +264,16 @@ export default class MessageHandler {
213
264
  });
214
265
  });
215
266
 
267
+ this.handle(ChannelType.IPC_SMART_COLLECTION_PREVIEW, async (_event: IpcMainEvent, args: any) => {
268
+ let rules;
269
+ try {
270
+ rules = typeof args.rules === 'string' ? JSON.parse(args.rules) : args.rules;
271
+ } catch {
272
+ return [[], 0];
273
+ }
274
+ return await this.connectionManager.getStoreRepository().evaluateSmartRules(rules, args.match_type ?? 'AND', {});
275
+ });
276
+
216
277
  // Store
217
278
 
218
279
  this.handle(ChannelType.IPC_STORE_FIND, async (_event: IpcMainEvent, args: any) => {
@@ -278,7 +339,7 @@ export default class MessageHandler {
278
339
  });
279
340
 
280
341
  this.handle(ChannelType.IPC_FONT_METRICS, async (_event: IpcMainEvent, filePath: string) => {
281
- const fontObject = new FontObject(filePath);
342
+ const fontObject = FontObject.fromCache(filePath);
282
343
  if (fontObject.hasError()) {
283
344
  return null;
284
345
  }
@@ -293,7 +354,7 @@ export default class MessageHandler {
293
354
  });
294
355
 
295
356
  this.handle(ChannelType.IPC_FONT_GLYPHS, async (_event: IpcMainEvent, filePath: string) => {
296
- const fontObject = new FontObject(filePath);
357
+ const fontObject = FontObject.fromCache(filePath);
297
358
  if (fontObject.hasError()) {
298
359
  return [];
299
360
  }
@@ -7,6 +7,7 @@ const system_1 = require("../config/system");
7
7
  const root = process.cwd();
8
8
  class ConfigManager {
9
9
  constructor(machineId, isProduction) {
10
+ this.cachedFontPaths = null;
10
11
  this.machineId = machineId;
11
12
  this.isProduction = isProduction;
12
13
  }
@@ -68,9 +69,12 @@ class ConfigManager {
68
69
  return path.join(os.tmpdir(), file);
69
70
  }
70
71
  getPlatformFontPaths() {
72
+ if (this.cachedFontPaths)
73
+ return this.cachedFontPaths;
71
74
  const paths = system_1.systemFontPaths.get(this.getPlatform()) || [];
72
75
  const home = os.homedir();
73
- return paths.map((p) => (p.startsWith('~') ? path.join(home, p.slice(1)) : p));
76
+ this.cachedFontPaths = paths.map((p) => (p.startsWith('~') ? path.join(home, p.slice(1)) : p));
77
+ return this.cachedFontPaths;
74
78
  }
75
79
  getUpTime() {
76
80
  let sec = os.uptime();
@@ -90,10 +90,14 @@ export default class ConfigManager {
90
90
  return path.join(os.tmpdir(), file);
91
91
  }
92
92
 
93
+ private cachedFontPaths: string[] | null = null;
94
+
93
95
  getPlatformFontPaths() {
96
+ if (this.cachedFontPaths) return this.cachedFontPaths;
94
97
  const paths = systemFontPaths.get(this.getPlatform()) || [];
95
98
  const home = os.homedir();
96
- return paths.map((p: string) => (p.startsWith('~') ? path.join(home, p.slice(1)) : p));
99
+ this.cachedFontPaths = paths.map((p: string) => (p.startsWith('~') ? path.join(home, p.slice(1)) : p));
100
+ return this.cachedFontPaths;
97
101
  }
98
102
 
99
103
  getUpTime() {
@@ -21,63 +21,63 @@ __decorate([
21
21
  ], Collection.prototype, "id", void 0);
22
22
  __decorate([
23
23
  (0, typeorm_1.Column)({
24
- length: 100
24
+ length: 100,
25
25
  }),
26
26
  __metadata("design:type", String)
27
27
  ], Collection.prototype, "title", void 0);
28
28
  __decorate([
29
29
  (0, typeorm_1.Column)({
30
- type: "int",
31
- default: 0
30
+ type: 'int',
31
+ default: 0,
32
32
  }),
33
33
  __metadata("design:type", Number)
34
34
  ], Collection.prototype, "parent_id", void 0);
35
35
  __decorate([
36
36
  (0, typeorm_1.Column)({
37
- type: "smallint",
38
- default: 0
37
+ type: 'smallint',
38
+ default: 0,
39
39
  }),
40
40
  __metadata("design:type", Number)
41
41
  ], Collection.prototype, "left_id", void 0);
42
42
  __decorate([
43
43
  (0, typeorm_1.Column)({
44
- type: "smallint",
45
- default: 0
44
+ type: 'smallint',
45
+ default: 0,
46
46
  }),
47
47
  __metadata("design:type", Number)
48
48
  ], Collection.prototype, "right_id", void 0);
49
49
  __decorate([
50
50
  (0, typeorm_1.Column)({
51
- type: "smallint",
52
- default: 0
51
+ type: 'smallint',
52
+ default: 0,
53
53
  }),
54
54
  __metadata("design:type", Number)
55
55
  ], Collection.prototype, "count", void 0);
56
56
  __decorate([
57
57
  (0, typeorm_1.Column)({
58
- type: "smallint",
59
- default: 0
58
+ type: 'smallint',
59
+ default: 0,
60
60
  }),
61
61
  __metadata("design:type", Number)
62
62
  ], Collection.prototype, "is_system", void 0);
63
63
  __decorate([
64
64
  (0, typeorm_1.Column)({
65
- type: "smallint",
66
- default: 0
65
+ type: 'smallint',
66
+ default: 0,
67
67
  }),
68
68
  __metadata("design:type", Number)
69
69
  ], Collection.prototype, "orderby", void 0);
70
70
  __decorate([
71
71
  (0, typeorm_1.Column)({
72
- type: "smallint",
73
- default: 0
72
+ type: 'smallint',
73
+ default: 0,
74
74
  }),
75
75
  __metadata("design:type", Boolean)
76
76
  ], Collection.prototype, "enabled", void 0);
77
77
  __decorate([
78
78
  (0, typeorm_1.Column)({
79
- type: "smallint",
80
- default: 0
79
+ type: 'smallint',
80
+ default: 0,
81
81
  }),
82
82
  __metadata("design:type", Boolean)
83
83
  ], Collection.prototype, "collapsed", void 0);
@@ -94,6 +94,8 @@ __decorate([
94
94
  __metadata("design:type", Array)
95
95
  ], Collection.prototype, "stores", void 0);
96
96
  exports.Collection = Collection = __decorate([
97
- (0, typeorm_1.Entity)()
97
+ (0, typeorm_1.Entity)(),
98
+ (0, typeorm_1.Index)(['left_id', 'right_id']),
99
+ (0, typeorm_1.Index)(['parent_id'])
98
100
  ], Collection);
99
101
  //# sourceMappingURL=Collection.schema.js.map
@@ -1,62 +1,63 @@
1
- import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, OneToMany } from "typeorm";
2
- import { Store } from "./Store.schema"
1
+ import { Entity, Column, Index, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
2
+ import { Store } from './Store.schema';
3
3
 
4
4
  @Entity()
5
+ @Index(['left_id', 'right_id'])
6
+ @Index(['parent_id'])
5
7
  export class Collection {
6
-
7
8
  @PrimaryGeneratedColumn()
8
9
  id: number;
9
10
 
10
11
  @Column({
11
- length: 100
12
+ length: 100,
12
13
  })
13
14
  title: string;
14
15
 
15
16
  @Column({
16
- type: "int",
17
- default: 0
17
+ type: 'int',
18
+ default: 0,
18
19
  })
19
20
  parent_id: number;
20
21
 
21
22
  @Column({
22
- type: "smallint",
23
- default: 0
23
+ type: 'smallint',
24
+ default: 0,
24
25
  })
25
26
  left_id: number;
26
27
 
27
28
  @Column({
28
- type: "smallint",
29
- default: 0
29
+ type: 'smallint',
30
+ default: 0,
30
31
  })
31
32
  right_id: number;
32
33
 
33
34
  @Column({
34
- type: "smallint",
35
- default: 0
35
+ type: 'smallint',
36
+ default: 0,
36
37
  })
37
38
  count: number;
38
39
 
39
40
  @Column({
40
- type: "smallint",
41
- default: 0
41
+ type: 'smallint',
42
+ default: 0,
42
43
  })
43
44
  is_system: number;
44
45
 
45
46
  @Column({
46
- type: "smallint",
47
- default: 0
47
+ type: 'smallint',
48
+ default: 0,
48
49
  })
49
50
  orderby: number;
50
51
 
51
52
  @Column({
52
- type: "smallint",
53
- default: 0
53
+ type: 'smallint',
54
+ default: 0,
54
55
  })
55
56
  enabled: boolean;
56
57
 
57
58
  @Column({
58
- type: "smallint",
59
- default: 0
59
+ type: 'smallint',
60
+ default: 0,
60
61
  })
61
62
  collapsed: boolean;
62
63
 
@@ -64,5 +65,5 @@ export class Collection {
64
65
  @UpdateDateColumn() public updated: Date;
65
66
 
66
67
  @OneToMany(() => Store, (store) => store.collection, { cascade: true })
67
- stores: Store[]
68
+ stores: Store[];
68
69
  }
@@ -68,13 +68,7 @@ exports.CollectionRepository = {
68
68
  },
69
69
  updateCollectionCounts(items) {
70
70
  return __awaiter(this, void 0, void 0, function* () {
71
- return items.forEach((item) => __awaiter(this, void 0, void 0, function* () {
72
- return yield this.createQueryBuilder()
73
- .update(entity_1.Collection)
74
- .set({ count: item.total })
75
- .where('id = :id', { id: item.collection_id })
76
- .execute();
77
- }));
71
+ yield Promise.all(items.map((item) => this.createQueryBuilder().update(entity_1.Collection).set({ count: item.total }).where('id = :id', { id: item.collection_id }).execute()));
78
72
  });
79
73
  },
80
74
  updateCollection(collectionId, data) {
@@ -109,10 +103,12 @@ exports.CollectionRepository = {
109
103
  },
110
104
  createParent(title) {
111
105
  return __awaiter(this, void 0, void 0, function* () {
112
- const data = yield this.createQueryBuilder()
113
- .select('MAX(collection.right_id)', 'right_id')
114
- .addSelect('MAX(collection.orderby)', 'orderby')
115
- .getRawOne();
106
+ const data = yield this.createQueryBuilder().select('MAX(collection.right_id)', 'right_id').getRawOne();
107
+ yield this.createQueryBuilder()
108
+ .update(entity_1.Collection)
109
+ .set({ orderby: () => 'orderby + 1' })
110
+ .where({ parent_id: 0 })
111
+ .execute();
116
112
  return yield this.createQueryBuilder()
117
113
  .insert()
118
114
  .into(entity_1.Collection)
@@ -121,7 +117,7 @@ exports.CollectionRepository = {
121
117
  parent_id: 0,
122
118
  left_id: data.right_id + 1,
123
119
  right_id: data.right_id + 2,
124
- orderby: data.orderby + 1,
120
+ orderby: 0,
125
121
  })
126
122
  .execute();
127
123
  });
@@ -129,16 +125,21 @@ exports.CollectionRepository = {
129
125
  createChild(parentId, title) {
130
126
  return __awaiter(this, void 0, void 0, function* () {
131
127
  const row = yield this.findOne({ where: { id: parentId } });
132
- this.createQueryBuilder()
128
+ yield this.createQueryBuilder()
133
129
  .update(entity_1.Collection)
134
130
  .set({ left_id: () => 'left_id + 2', right_id: () => 'right_id + 2' })
135
131
  .where({ left_id: (0, typeorm_1.MoreThan)(row.right_id) })
136
132
  .execute();
137
- this.createQueryBuilder()
133
+ yield this.createQueryBuilder()
138
134
  .update(entity_1.Collection)
139
135
  .set({ right_id: () => 'right_id + 2' })
140
136
  .where({ left_id: (0, typeorm_1.LessThanOrEqual)(row.left_id), right_id: (0, typeorm_1.MoreThanOrEqual)(row.left_id) })
141
137
  .execute();
138
+ yield this.createQueryBuilder()
139
+ .update(entity_1.Collection)
140
+ .set({ orderby: () => 'orderby + 1' })
141
+ .where({ parent_id: parentId })
142
+ .execute();
142
143
  return yield this.createQueryBuilder()
143
144
  .insert()
144
145
  .into(entity_1.Collection)
@@ -147,7 +148,7 @@ exports.CollectionRepository = {
147
148
  parent_id: parentId,
148
149
  left_id: row.right_id,
149
150
  right_id: row.right_id + 1,
150
- orderby: row.orderby + 1,
151
+ orderby: 0,
151
152
  })
152
153
  .execute();
153
154
  });
@@ -249,9 +250,7 @@ exports.CollectionRepository = {
249
250
  .where('collection.parent_id = :parentId', { parentId: newParentId })
250
251
  .orderBy('collection.left_id', 'ASC')
251
252
  .getMany();
252
- for (let i = 0; i < newSiblings.length; i++) {
253
- yield this.createQueryBuilder().update(entity_1.Collection).set({ orderby: i }).where('id = :id', { id: newSiblings[i].id }).execute();
254
- }
253
+ yield Promise.all(newSiblings.map((sibling, i) => this.createQueryBuilder().update(entity_1.Collection).set({ orderby: i }).where('id = :id', { id: sibling.id }).execute()));
255
254
  });
256
255
  },
257
256
  createSystemCollection() {
@@ -72,13 +72,11 @@ export const CollectionRepository = {
72
72
  },
73
73
 
74
74
  async updateCollectionCounts(items: any[]) {
75
- return items.forEach(async (item) => {
76
- return await this.createQueryBuilder()
77
- .update(Collection)
78
- .set({ count: item.total })
79
- .where('id = :id', { id: item.collection_id })
80
- .execute();
81
- });
75
+ await Promise.all(
76
+ items.map((item) =>
77
+ this.createQueryBuilder().update(Collection).set({ count: item.total }).where('id = :id', { id: item.collection_id }).execute(),
78
+ ),
79
+ );
82
80
  },
83
81
 
84
82
  updateCollection(collectionId: number, data: any) {
@@ -112,10 +110,13 @@ export const CollectionRepository = {
112
110
  },
113
111
 
114
112
  async createParent(title: string) {
115
- const data = await this.createQueryBuilder()
116
- .select('MAX(collection.right_id)', 'right_id')
117
- .addSelect('MAX(collection.orderby)', 'orderby')
118
- .getRawOne();
113
+ const data = await this.createQueryBuilder().select('MAX(collection.right_id)', 'right_id').getRawOne();
114
+
115
+ await this.createQueryBuilder()
116
+ .update(Collection)
117
+ .set({ orderby: () => 'orderby + 1' })
118
+ .where({ parent_id: 0 })
119
+ .execute();
119
120
 
120
121
  return await this.createQueryBuilder()
121
122
  .insert()
@@ -125,7 +126,7 @@ export const CollectionRepository = {
125
126
  parent_id: 0,
126
127
  left_id: data.right_id + 1,
127
128
  right_id: data.right_id + 2,
128
- orderby: data.orderby + 1,
129
+ orderby: 0,
129
130
  })
130
131
  .execute();
131
132
  },
@@ -133,18 +134,24 @@ export const CollectionRepository = {
133
134
  async createChild(parentId: number, title: string) {
134
135
  const row = await this.findOne({ where: { id: parentId } });
135
136
 
136
- this.createQueryBuilder()
137
+ await this.createQueryBuilder()
137
138
  .update(Collection)
138
139
  .set({ left_id: () => 'left_id + 2', right_id: () => 'right_id + 2' })
139
140
  .where({ left_id: MoreThan(row.right_id) })
140
141
  .execute();
141
142
 
142
- this.createQueryBuilder()
143
+ await this.createQueryBuilder()
143
144
  .update(Collection)
144
145
  .set({ right_id: () => 'right_id + 2' })
145
146
  .where({ left_id: LessThanOrEqual(row.left_id), right_id: MoreThanOrEqual(row.left_id) })
146
147
  .execute();
147
148
 
149
+ await this.createQueryBuilder()
150
+ .update(Collection)
151
+ .set({ orderby: () => 'orderby + 1' })
152
+ .where({ parent_id: parentId })
153
+ .execute();
154
+
148
155
  return await this.createQueryBuilder()
149
156
  .insert()
150
157
  .into(Collection)
@@ -153,7 +160,7 @@ export const CollectionRepository = {
153
160
  parent_id: parentId,
154
161
  left_id: row.right_id,
155
162
  right_id: row.right_id + 1,
156
- orderby: row.orderby + 1,
163
+ orderby: 0,
157
164
  })
158
165
  .execute();
159
166
  },
@@ -264,9 +271,11 @@ export const CollectionRepository = {
264
271
  .orderBy('collection.left_id', 'ASC')
265
272
  .getMany();
266
273
 
267
- for (let i = 0; i < newSiblings.length; i++) {
268
- await this.createQueryBuilder().update(Collection).set({ orderby: i }).where('id = :id', { id: newSiblings[i].id }).execute();
269
- }
274
+ await Promise.all(
275
+ newSiblings.map((sibling: Collection, i: number) =>
276
+ this.createQueryBuilder().update(Collection).set({ orderby: i }).where('id = :id', { id: sibling.id }).execute(),
277
+ ),
278
+ );
270
279
  },
271
280
 
272
281
  async createSystemCollection() {
@@ -131,9 +131,8 @@ exports.StoreRepository = {
131
131
  }
132
132
  });
133
133
  }
134
- if (options.take) {
135
- db.limit(options.take);
136
- }
134
+ const MAX_SEARCH_LIMIT = 5000;
135
+ db.limit(Math.min(options.take || 500, MAX_SEARCH_LIMIT));
137
136
  if (options.skip) {
138
137
  db.offset(options.skip);
139
138
  }
@@ -298,13 +297,7 @@ exports.StoreRepository = {
298
297
  if (item.version && item.version !== '') {
299
298
  data.version = item.version;
300
299
  }
301
- //@todo Log errors in log table.
302
- return yield this.createQueryBuilder()
303
- .insert()
304
- .into(entity_1.Store)
305
- .values(data)
306
- .execute()
307
- .catch((err) => console.log('insert-error', err));
300
+ return yield this.createQueryBuilder().insert().into(entity_1.Store).values(data).execute();
308
301
  });
309
302
  },
310
303
  evaluateSmartRules(rules_1, matchType_1) {
@@ -416,15 +409,17 @@ exports.StoreRepository = {
416
409
  },
417
410
  fetchSystemStats() {
418
411
  return __awaiter(this, void 0, void 0, function* () {
419
- const rowCount = yield this.createQueryBuilder().select('COUNT(*)', 'total').getRawOne();
420
- const favoriteCount = yield this.createQueryBuilder().select('COUNT(*)', 'total').where('store.favorite = 1').getRawOne();
421
- const systemCount = yield this.createQueryBuilder().select('COUNT(*)', 'total').where('store.system = 1').getRawOne();
422
- const temporaryCount = yield this.createQueryBuilder().select('COUNT(*)', 'total').where('store.temporary = 1').getRawOne();
412
+ const stats = yield this.createQueryBuilder()
413
+ .select('COUNT(*)', 'rowCount')
414
+ .addSelect('SUM(CASE WHEN store.favorite = 1 THEN 1 ELSE 0 END)', 'favoriteCount')
415
+ .addSelect('SUM(CASE WHEN store.system = 1 THEN 1 ELSE 0 END)', 'systemCount')
416
+ .addSelect('SUM(CASE WHEN store.temporary = 1 THEN 1 ELSE 0 END)', 'temporaryCount')
417
+ .getRawOne();
423
418
  return {
424
- rowCount: rowCount.total,
425
- favoriteCount: favoriteCount.total,
426
- systemCount: systemCount.total,
427
- temporaryCount: temporaryCount.total,
419
+ rowCount: Number(stats.rowCount) || 0,
420
+ favoriteCount: Number(stats.favoriteCount) || 0,
421
+ systemCount: Number(stats.systemCount) || 0,
422
+ temporaryCount: Number(stats.temporaryCount) || 0,
428
423
  };
429
424
  });
430
425
  },