fontastic 1.0.0 → 1.0.2

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 (55) hide show
  1. package/.github/workflows/macos.yml +0 -7
  2. package/.github/workflows/ubuntu.yml +0 -7
  3. package/.github/workflows/windows.yml +0 -7
  4. package/README.md +1 -0
  5. package/app/core/ConnectionManager.js +7 -1
  6. package/app/core/ConnectionManager.ts +11 -3
  7. package/app/core/MessageHandler.js +24 -0
  8. package/app/core/MessageHandler.ts +29 -0
  9. package/app/core/menu/templates/DarwinTemplate.js +16 -1
  10. package/app/core/menu/templates/DarwinTemplate.ts +16 -1
  11. package/app/core/menu/templates/SystemTemplate.js +16 -1
  12. package/app/core/menu/templates/SystemTemplate.ts +16 -1
  13. package/app/database/entity/SmartCollection.schema.js +66 -0
  14. package/app/database/entity/SmartCollection.schema.ts +39 -0
  15. package/app/database/entity/index.js +1 -0
  16. package/app/database/entity/index.ts +2 -1
  17. package/app/database/repository/SmartCollection.repository.js +47 -0
  18. package/app/database/repository/SmartCollection.repository.ts +30 -0
  19. package/app/database/repository/Store.repository.js +107 -0
  20. package/app/database/repository/Store.repository.ts +106 -0
  21. package/app/database/repository/index.js +1 -0
  22. package/app/database/repository/index.ts +2 -1
  23. package/app/enums/ChannelType.js +5 -0
  24. package/app/enums/ChannelType.ts +6 -0
  25. package/app/enums/StorageType.js +1 -0
  26. package/app/enums/StorageType.ts +1 -0
  27. package/app/package.json +1 -1
  28. package/app/types/FontMetrics.js +3 -0
  29. package/app/types/SmartCollection.js +3 -0
  30. package/app/types/SmartCollection.ts +5 -0
  31. package/app/types/SystemConfig.ts +2 -1
  32. package/app/types/index.js +2 -0
  33. package/app/types/index.ts +1 -0
  34. package/package.json +1 -1
  35. package/src/app/core/services/database/database.service.ts +70 -1
  36. package/src/app/core/services/message/message.service.ts +23 -0
  37. package/src/app/core/services/presentation/presentation.service.ts +62 -9
  38. package/src/app/layout/header/header.component.html +5 -5
  39. package/src/app/layout/layout.component.html +1 -1
  40. package/src/app/layout/main/main.component.html +3 -3
  41. package/src/app/layout/main/main.component.ts +2 -2
  42. package/src/app/layout/navigation/navigation.component.html +70 -4
  43. package/src/app/layout/navigation/navigation.component.ts +131 -27
  44. package/src/app/shared/components/context-menu/context-menu.component.ts +70 -21
  45. package/src/app/shared/components/datagrid/datagrid.component.html +82 -2
  46. package/src/app/shared/components/{inspector/inspector.component.html → glyphs/glyphs.component.html} +1 -1
  47. package/src/app/shared/components/glyphs/glyphs.component.ts +60 -0
  48. package/src/app/shared/components/index.ts +2 -1
  49. package/src/app/shared/components/rule-builder/rule-builder.component.html +94 -0
  50. package/src/app/shared/components/rule-builder/rule-builder.component.ts +136 -0
  51. package/src/app/shared/components/toolbar/toolbar.component.html +0 -81
  52. package/src/app/shared/components/toolbar/toolbar.component.ts +1 -2
  53. package/src/styles/base/variables.css +16 -0
  54. package/src/styles/components/spinner.css +4 -3
  55. package/src/app/shared/components/inspector/inspector.component.ts +0 -41
@@ -68,10 +68,3 @@ jobs:
68
68
 
69
69
  - name: Run headless e2e test
70
70
  run: npm run e2e
71
-
72
- - name: Build the app
73
- uses: nick-fields/retry@v3
74
- with:
75
- timeout_minutes: 15
76
- max_attempts: 3
77
- command: npm run electron:build
@@ -78,10 +78,3 @@ jobs:
78
78
  uses: GabrielBB/xvfb-action@v1
79
79
  with:
80
80
  run: npm run e2e
81
-
82
- - name: Build the app
83
- uses: nick-fields/retry@v3
84
- with:
85
- timeout_minutes: 15
86
- max_attempts: 3
87
- command: npm run electron:build
@@ -72,10 +72,3 @@ jobs:
72
72
 
73
73
  - name: Run headless e2e test
74
74
  run: npm run e2e
75
-
76
- - name: Build the app
77
- uses: nick-fields/retry@v3
78
- with:
79
- timeout_minutes: 15
80
- max_attempts: 3
81
- command: npm run electron:build
package/README.md CHANGED
@@ -17,6 +17,7 @@ Fontastic is a cross-platform font management and cataloging application built w
17
17
  ## Features
18
18
 
19
19
  - Nested collections — organize fonts into hierarchical groups with drag-and-drop
20
+ - Smart collections — auto-populate collections using rule-based filters on font metadata
20
21
  - Advanced search — quickly find fonts with powerful search and filtering
21
22
  - Glyph inspector — browse and examine individual characters and Unicode points
22
23
  - Waterfall preview — compare text rendering across multiple sizes at a glance
@@ -15,7 +15,7 @@ const repository_1 = require("../database/repository");
15
15
  const StorageType_1 = require("../enums/StorageType");
16
16
  class ConnectionManager {
17
17
  constructor(configManager) {
18
- this.schemas = [entity_1.Collection, entity_1.Store, entity_1.Logger];
18
+ this.schemas = [entity_1.Collection, entity_1.Store, entity_1.Logger, entity_1.SmartCollection];
19
19
  this.subscribers = [];
20
20
  this.migrations = [];
21
21
  this.omitables = ['title', 'description', 'enabled'];
@@ -89,6 +89,12 @@ class ConnectionManager {
89
89
  getStoreRepository() {
90
90
  return this.getStore().extend(repository_1.StoreRepository);
91
91
  }
92
+ getSmartCollection() {
93
+ return this.dataSource.getRepository(entity_1.SmartCollection);
94
+ }
95
+ getSmartCollectionRepository() {
96
+ return this.getSmartCollection().extend(repository_1.SmartCollectionRepository);
97
+ }
92
98
  }
93
99
  exports.default = ConnectionManager;
94
100
  //# sourceMappingURL=ConnectionManager.js.map
@@ -1,6 +1,6 @@
1
1
  import { DataSource, DataSourceOptions } from 'typeorm';
2
- import { Collection, Store, Logger } from '../database/entity';
3
- import { CollectionRepository, LoggerRepository, StoreRepository } from '../database/repository';
2
+ import { Collection, Store, Logger, SmartCollection } from '../database/entity';
3
+ import { CollectionRepository, LoggerRepository, SmartCollectionRepository, StoreRepository } from '../database/repository';
4
4
  import ConfigManager from './ConfigManager';
5
5
  import { StorageType } from '../enums/StorageType';
6
6
 
@@ -10,7 +10,7 @@ export default class ConnectionManager {
10
10
 
11
11
  dataSource: DataSource;
12
12
 
13
- schemas: any[] = [Collection, Store, Logger];
13
+ schemas: any[] = [Collection, Store, Logger, SmartCollection];
14
14
  subscribers: any[] = [];
15
15
  migrations: any[] = [];
16
16
 
@@ -104,4 +104,12 @@ export default class ConnectionManager {
104
104
  getStoreRepository() {
105
105
  return this.getStore().extend(StoreRepository);
106
106
  }
107
+
108
+ getSmartCollection() {
109
+ return this.dataSource.getRepository(SmartCollection);
110
+ }
111
+
112
+ getSmartCollectionRepository() {
113
+ return this.getSmartCollection().extend(SmartCollectionRepository);
114
+ }
107
115
  }
@@ -141,6 +141,30 @@ class MessageHandler {
141
141
  yield this.connectionManager.getCollectionRepository().updateCollectionCounts(items);
142
142
  return yield this.fetchCollectionsWithCounts({});
143
143
  }));
144
+ // Smart Collection
145
+ this.handle(ChannelType_1.ChannelType.IPC_SMART_COLLECTION_FIND, (_event) => __awaiter(this, void 0, void 0, function* () {
146
+ return yield this.connectionManager.getSmartCollectionRepository().fetchAll();
147
+ }));
148
+ this.handle(ChannelType_1.ChannelType.IPC_SMART_COLLECTION_CREATE, (_event, args) => __awaiter(this, void 0, void 0, function* () {
149
+ return yield this.connectionManager.getSmartCollectionRepository().createSmartCollection(args);
150
+ }));
151
+ this.handle(ChannelType_1.ChannelType.IPC_SMART_COLLECTION_UPDATE, (_event, args) => __awaiter(this, void 0, void 0, function* () {
152
+ return yield this.connectionManager.getSmartCollectionRepository().updateSmartCollection(args.id, args.data);
153
+ }));
154
+ this.handle(ChannelType_1.ChannelType.IPC_SMART_COLLECTION_DELETE, (_event, args) => __awaiter(this, void 0, void 0, function* () {
155
+ return yield this.connectionManager.getSmartCollectionRepository().deleteSmartCollection(args.id);
156
+ }));
157
+ this.handle(ChannelType_1.ChannelType.IPC_SMART_COLLECTION_EVALUATE, (_event, args) => __awaiter(this, void 0, void 0, function* () {
158
+ const sc = yield this.connectionManager.getSmartCollectionRepository().findOneBy({ id: args.id });
159
+ if (!sc)
160
+ return [[], 0];
161
+ const rules = JSON.parse(sc.rules);
162
+ return yield this.connectionManager.getStoreRepository().evaluateSmartRules(rules, sc.match_type, {
163
+ skip: args.skip,
164
+ take: args.take,
165
+ order: args.order,
166
+ });
167
+ }));
144
168
  // Store
145
169
  this.handle(ChannelType_1.ChannelType.IPC_STORE_FIND, (_event, args) => __awaiter(this, void 0, void 0, function* () {
146
170
  return yield this.connectionManager.getStore().find(args);
@@ -184,6 +184,35 @@ export default class MessageHandler {
184
184
  return await this.fetchCollectionsWithCounts({});
185
185
  });
186
186
 
187
+ // Smart Collection
188
+
189
+ this.handle(ChannelType.IPC_SMART_COLLECTION_FIND, async (_event: IpcMainEvent) => {
190
+ return await this.connectionManager.getSmartCollectionRepository().fetchAll();
191
+ });
192
+
193
+ this.handle(ChannelType.IPC_SMART_COLLECTION_CREATE, async (_event: IpcMainEvent, args: any) => {
194
+ return await this.connectionManager.getSmartCollectionRepository().createSmartCollection(args);
195
+ });
196
+
197
+ this.handle(ChannelType.IPC_SMART_COLLECTION_UPDATE, async (_event: IpcMainEvent, args: any) => {
198
+ return await this.connectionManager.getSmartCollectionRepository().updateSmartCollection(args.id, args.data);
199
+ });
200
+
201
+ this.handle(ChannelType.IPC_SMART_COLLECTION_DELETE, async (_event: IpcMainEvent, args: any) => {
202
+ return await this.connectionManager.getSmartCollectionRepository().deleteSmartCollection(args.id);
203
+ });
204
+
205
+ this.handle(ChannelType.IPC_SMART_COLLECTION_EVALUATE, async (_event: IpcMainEvent, args: any) => {
206
+ const sc = await this.connectionManager.getSmartCollectionRepository().findOneBy({ id: args.id });
207
+ if (!sc) return [[], 0];
208
+ const rules = JSON.parse(sc.rules);
209
+ return await this.connectionManager.getStoreRepository().evaluateSmartRules(rules, sc.match_type, {
210
+ skip: args.skip,
211
+ take: args.take,
212
+ order: args.order,
213
+ });
214
+ });
215
+
187
216
  // Store
188
217
 
189
218
  this.handle(ChannelType.IPC_STORE_FIND, async (_event: IpcMainEvent, args: any) => {
@@ -68,6 +68,21 @@ class DarwinTemplate {
68
68
  this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
69
69
  },
70
70
  },
71
+ { type: 'separator' },
72
+ {
73
+ label: 'Expand Collections',
74
+ accelerator: 'Alt+Command+E',
75
+ click: () => {
76
+ this.mainWindow.webContents.send(enums_1.ChannelType.IPC_TOGGLE_PANEL, 'expand-collections');
77
+ },
78
+ },
79
+ {
80
+ label: 'Collapse Collections',
81
+ accelerator: 'Alt+Command+Shift+E',
82
+ click: () => {
83
+ this.mainWindow.webContents.send(enums_1.ChannelType.IPC_TOGGLE_PANEL, 'collapse-collections');
84
+ },
85
+ },
71
86
  ];
72
87
  if (!this.isProduction) {
73
88
  items.push({ type: 'separator' }, {
@@ -107,7 +122,7 @@ class DarwinTemplate {
107
122
  { label: 'Toggle Navigation', panel: 'navigation', accelerator: 'Alt+Command+1' },
108
123
  { label: 'Toggle Aside', panel: 'aside', accelerator: 'Alt+Command+2' },
109
124
  { label: 'Toggle Preview', panel: 'preview', accelerator: 'Alt+Command+3' },
110
- { label: 'Toggle Inspect', panel: 'inspect', accelerator: 'Alt+Command+4' },
125
+ { label: 'Toggle Glyphs', panel: 'glyphs', accelerator: 'Alt+Command+4' },
111
126
  { label: 'Toggle Toolbar', panel: 'toolbar', accelerator: 'Alt+Command+5' },
112
127
  { label: 'Toggle Grid', panel: 'grid', accelerator: 'Alt+Command+6' },
113
128
  { label: 'Toggle Waterfall', panel: 'waterfall', accelerator: 'Alt+Command+7' },
@@ -80,6 +80,21 @@ export default class DarwinTemplate {
80
80
  this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
81
81
  },
82
82
  },
83
+ { type: 'separator' },
84
+ {
85
+ label: 'Expand Collections',
86
+ accelerator: 'Alt+Command+E',
87
+ click: () => {
88
+ this.mainWindow.webContents.send(ChannelType.IPC_TOGGLE_PANEL, 'expand-collections');
89
+ },
90
+ },
91
+ {
92
+ label: 'Collapse Collections',
93
+ accelerator: 'Alt+Command+Shift+E',
94
+ click: () => {
95
+ this.mainWindow.webContents.send(ChannelType.IPC_TOGGLE_PANEL, 'collapse-collections');
96
+ },
97
+ },
83
98
  ];
84
99
 
85
100
  if (!this.isProduction) {
@@ -127,7 +142,7 @@ export default class DarwinTemplate {
127
142
  { label: 'Toggle Navigation', panel: 'navigation', accelerator: 'Alt+Command+1' },
128
143
  { label: 'Toggle Aside', panel: 'aside', accelerator: 'Alt+Command+2' },
129
144
  { label: 'Toggle Preview', panel: 'preview', accelerator: 'Alt+Command+3' },
130
- { label: 'Toggle Inspect', panel: 'inspect', accelerator: 'Alt+Command+4' },
145
+ { label: 'Toggle Glyphs', panel: 'glyphs', accelerator: 'Alt+Command+4' },
131
146
  { label: 'Toggle Toolbar', panel: 'toolbar', accelerator: 'Alt+Command+5' },
132
147
  { label: 'Toggle Grid', panel: 'grid', accelerator: 'Alt+Command+6' },
133
148
  { label: 'Toggle Waterfall', panel: 'waterfall', accelerator: 'Alt+Command+7' },
@@ -65,6 +65,21 @@ class SystemTemplate {
65
65
  this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
66
66
  },
67
67
  },
68
+ { type: 'separator' },
69
+ {
70
+ label: 'Expand Collections',
71
+ accelerator: 'Alt+Ctrl+E',
72
+ click: () => {
73
+ this.mainWindow.webContents.send(enums_1.ChannelType.IPC_TOGGLE_PANEL, 'expand-collections');
74
+ },
75
+ },
76
+ {
77
+ label: 'Collapse Collections',
78
+ accelerator: 'Alt+Ctrl+Shift+E',
79
+ click: () => {
80
+ this.mainWindow.webContents.send(enums_1.ChannelType.IPC_TOGGLE_PANEL, 'collapse-collections');
81
+ },
82
+ },
68
83
  ];
69
84
  if (!this.isProduction) {
70
85
  items.push({ type: 'separator' }, {
@@ -104,7 +119,7 @@ class SystemTemplate {
104
119
  { label: 'Toggle Navigation', panel: 'navigation', accelerator: 'Alt+Ctrl+1' },
105
120
  { label: 'Toggle Aside', panel: 'aside', accelerator: 'Alt+Ctrl+2' },
106
121
  { label: 'Toggle Preview', panel: 'preview', accelerator: 'Alt+Ctrl+3' },
107
- { label: 'Toggle Inspect', panel: 'inspect', accelerator: 'Alt+Ctrl+4' },
122
+ { label: 'Toggle Glyphs', panel: 'glyphs', accelerator: 'Alt+Ctrl+4' },
108
123
  { label: 'Toggle Toolbar', panel: 'toolbar', accelerator: 'Alt+Ctrl+5' },
109
124
  { label: 'Toggle Grid', panel: 'grid', accelerator: 'Alt+Ctrl+6' },
110
125
  { label: 'Toggle Waterfall', panel: 'waterfall', accelerator: 'Alt+Ctrl+7' },
@@ -72,6 +72,21 @@ export default class SystemTemplate {
72
72
  this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
73
73
  },
74
74
  },
75
+ { type: 'separator' },
76
+ {
77
+ label: 'Expand Collections',
78
+ accelerator: 'Alt+Ctrl+E',
79
+ click: () => {
80
+ this.mainWindow.webContents.send(ChannelType.IPC_TOGGLE_PANEL, 'expand-collections');
81
+ },
82
+ },
83
+ {
84
+ label: 'Collapse Collections',
85
+ accelerator: 'Alt+Ctrl+Shift+E',
86
+ click: () => {
87
+ this.mainWindow.webContents.send(ChannelType.IPC_TOGGLE_PANEL, 'collapse-collections');
88
+ },
89
+ },
75
90
  ];
76
91
 
77
92
  if (!this.isProduction) {
@@ -119,7 +134,7 @@ export default class SystemTemplate {
119
134
  { label: 'Toggle Navigation', panel: 'navigation', accelerator: 'Alt+Ctrl+1' },
120
135
  { label: 'Toggle Aside', panel: 'aside', accelerator: 'Alt+Ctrl+2' },
121
136
  { label: 'Toggle Preview', panel: 'preview', accelerator: 'Alt+Ctrl+3' },
122
- { label: 'Toggle Inspect', panel: 'inspect', accelerator: 'Alt+Ctrl+4' },
137
+ { label: 'Toggle Glyphs', panel: 'glyphs', accelerator: 'Alt+Ctrl+4' },
123
138
  { label: 'Toggle Toolbar', panel: 'toolbar', accelerator: 'Alt+Ctrl+5' },
124
139
  { label: 'Toggle Grid', panel: 'grid', accelerator: 'Alt+Ctrl+6' },
125
140
  { label: 'Toggle Waterfall', panel: 'waterfall', accelerator: 'Alt+Ctrl+7' },
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SmartCollection = void 0;
13
+ const typeorm_1 = require("typeorm");
14
+ let SmartCollection = class SmartCollection {
15
+ };
16
+ exports.SmartCollection = SmartCollection;
17
+ __decorate([
18
+ (0, typeorm_1.PrimaryGeneratedColumn)(),
19
+ __metadata("design:type", Number)
20
+ ], SmartCollection.prototype, "id", void 0);
21
+ __decorate([
22
+ (0, typeorm_1.Column)({
23
+ length: 100,
24
+ }),
25
+ __metadata("design:type", String)
26
+ ], SmartCollection.prototype, "title", void 0);
27
+ __decorate([
28
+ (0, typeorm_1.Column)({
29
+ type: 'text',
30
+ }),
31
+ __metadata("design:type", String)
32
+ ], SmartCollection.prototype, "rules", void 0);
33
+ __decorate([
34
+ (0, typeorm_1.Column)({
35
+ type: 'varchar',
36
+ length: 3,
37
+ default: 'AND',
38
+ }),
39
+ __metadata("design:type", String)
40
+ ], SmartCollection.prototype, "match_type", void 0);
41
+ __decorate([
42
+ (0, typeorm_1.Column)({
43
+ type: 'smallint',
44
+ default: 0,
45
+ }),
46
+ __metadata("design:type", Number)
47
+ ], SmartCollection.prototype, "orderby", void 0);
48
+ __decorate([
49
+ (0, typeorm_1.Column)({
50
+ type: 'smallint',
51
+ default: 0,
52
+ }),
53
+ __metadata("design:type", Number)
54
+ ], SmartCollection.prototype, "enabled", void 0);
55
+ __decorate([
56
+ (0, typeorm_1.CreateDateColumn)(),
57
+ __metadata("design:type", Date)
58
+ ], SmartCollection.prototype, "created", void 0);
59
+ __decorate([
60
+ (0, typeorm_1.UpdateDateColumn)(),
61
+ __metadata("design:type", Date)
62
+ ], SmartCollection.prototype, "updated", void 0);
63
+ exports.SmartCollection = SmartCollection = __decorate([
64
+ (0, typeorm_1.Entity)()
65
+ ], SmartCollection);
66
+ //# sourceMappingURL=SmartCollection.schema.js.map
@@ -0,0 +1,39 @@
1
+ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
2
+
3
+ @Entity()
4
+ export class SmartCollection {
5
+ @PrimaryGeneratedColumn()
6
+ id: number;
7
+
8
+ @Column({
9
+ length: 100,
10
+ })
11
+ title: string;
12
+
13
+ @Column({
14
+ type: 'text',
15
+ })
16
+ rules: string;
17
+
18
+ @Column({
19
+ type: 'varchar',
20
+ length: 3,
21
+ default: 'AND',
22
+ })
23
+ match_type: string;
24
+
25
+ @Column({
26
+ type: 'smallint',
27
+ default: 0,
28
+ })
29
+ orderby: number;
30
+
31
+ @Column({
32
+ type: 'smallint',
33
+ default: 0,
34
+ })
35
+ enabled: number;
36
+
37
+ @CreateDateColumn() public created: Date;
38
+ @UpdateDateColumn() public updated: Date;
39
+ }
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./Collection.schema"), exports);
18
18
  __exportStar(require("./Logger.schema"), exports);
19
+ __exportStar(require("./SmartCollection.schema"), exports);
19
20
  __exportStar(require("./Store.schema"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,4 @@
1
1
  export * from './Collection.schema';
2
2
  export * from './Logger.schema';
3
- export * from './Store.schema';
3
+ export * from './SmartCollection.schema';
4
+ export * from './Store.schema';
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SmartCollectionRepository = void 0;
13
+ const entity_1 = require("../entity");
14
+ exports.SmartCollectionRepository = {
15
+ fetchAll() {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ return this.createQueryBuilder('sc').orderBy('sc.orderby', 'ASC').addOrderBy('LOWER(sc.title)', 'ASC').getMany();
18
+ });
19
+ },
20
+ createSmartCollection(args) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ yield this.createQueryBuilder()
23
+ .insert()
24
+ .into(entity_1.SmartCollection)
25
+ .values({
26
+ title: args.title,
27
+ rules: args.rules,
28
+ match_type: args.match_type,
29
+ })
30
+ .execute();
31
+ return this.fetchAll();
32
+ });
33
+ },
34
+ updateSmartCollection(id, data) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ yield this.createQueryBuilder().update(entity_1.SmartCollection).set(data).where('id = :id', { id }).execute();
37
+ return this.fetchAll();
38
+ });
39
+ },
40
+ deleteSmartCollection(id) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ yield this.createQueryBuilder().delete().from(entity_1.SmartCollection).where('id = :id', { id }).execute();
43
+ return this.fetchAll();
44
+ });
45
+ },
46
+ };
47
+ //# sourceMappingURL=SmartCollection.repository.js.map
@@ -0,0 +1,30 @@
1
+ import { SmartCollection } from '../entity';
2
+
3
+ export const SmartCollectionRepository = {
4
+ async fetchAll(): Promise<SmartCollection[]> {
5
+ return this.createQueryBuilder('sc').orderBy('sc.orderby', 'ASC').addOrderBy('LOWER(sc.title)', 'ASC').getMany();
6
+ },
7
+
8
+ async createSmartCollection(args: { title: string; rules: string; match_type: string }) {
9
+ await this.createQueryBuilder()
10
+ .insert()
11
+ .into(SmartCollection)
12
+ .values({
13
+ title: args.title,
14
+ rules: args.rules,
15
+ match_type: args.match_type,
16
+ })
17
+ .execute();
18
+ return this.fetchAll();
19
+ },
20
+
21
+ async updateSmartCollection(id: number, data: Partial<SmartCollection>) {
22
+ await this.createQueryBuilder().update(SmartCollection).set(data).where('id = :id', { id }).execute();
23
+ return this.fetchAll();
24
+ },
25
+
26
+ async deleteSmartCollection(id: number) {
27
+ await this.createQueryBuilder().delete().from(SmartCollection).where('id = :id', { id }).execute();
28
+ return this.fetchAll();
29
+ },
30
+ };
@@ -307,6 +307,113 @@ exports.StoreRepository = {
307
307
  .catch((err) => console.log('insert-error', err));
308
308
  });
309
309
  },
310
+ evaluateSmartRules(rules_1, matchType_1) {
311
+ return __awaiter(this, arguments, void 0, function* (rules, matchType, options = {}) {
312
+ const db = this.createQueryBuilder();
313
+ const textFields = [
314
+ 'file_name',
315
+ 'file_path',
316
+ 'compatible_full_name',
317
+ 'copyright',
318
+ 'description',
319
+ 'designer',
320
+ 'designer_url',
321
+ 'font_family',
322
+ 'font_subfamily',
323
+ 'full_name',
324
+ 'license',
325
+ 'license_url',
326
+ 'manufacturer',
327
+ 'manufacturer_url',
328
+ 'post_script_name',
329
+ 'preferred_family',
330
+ 'preferred_sub_family',
331
+ 'sample_text',
332
+ 'trademark',
333
+ 'unique_id',
334
+ 'version',
335
+ ];
336
+ const booleanFields = ['favorite', 'system', 'installable', 'temporary'];
337
+ const numericFields = ['file_size'];
338
+ const dateFields = ['created'];
339
+ if (rules.length > 0) {
340
+ const conditions = rules.map((rule, idx) => {
341
+ const field = `store.${rule.field}`;
342
+ const paramName = `p${idx}`;
343
+ return (qb) => {
344
+ if (textFields.includes(rule.field)) {
345
+ const val = String(rule.value).toLowerCase();
346
+ switch (rule.operator) {
347
+ case 'contains':
348
+ qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}%` });
349
+ break;
350
+ case 'equals':
351
+ qb.where(`LOWER(${field}) = :${paramName}`, { [paramName]: val });
352
+ break;
353
+ case 'starts_with':
354
+ qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `${val}%` });
355
+ break;
356
+ case 'ends_with':
357
+ qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}` });
358
+ break;
359
+ default:
360
+ qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}%` });
361
+ }
362
+ }
363
+ else if (rule.field === 'file_type') {
364
+ qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
365
+ }
366
+ else if (booleanFields.includes(rule.field)) {
367
+ const boolVal = rule.operator === 'is_not' ? 0 : 1;
368
+ qb.where(`${field} = :${paramName}`, { [paramName]: boolVal });
369
+ }
370
+ else if (numericFields.includes(rule.field)) {
371
+ if (rule.operator === 'greater_than') {
372
+ qb.where(`${field} > :${paramName}`, { [paramName]: rule.value });
373
+ }
374
+ else if (rule.operator === 'less_than') {
375
+ qb.where(`${field} < :${paramName}`, { [paramName]: rule.value });
376
+ }
377
+ else {
378
+ qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
379
+ }
380
+ }
381
+ else if (dateFields.includes(rule.field)) {
382
+ if (rule.operator === 'greater_than') {
383
+ qb.where(`${field} >= :${paramName}`, { [paramName]: rule.value });
384
+ }
385
+ else if (rule.operator === 'less_than') {
386
+ qb.where(`${field} <= :${paramName}`, { [paramName]: rule.value });
387
+ }
388
+ else {
389
+ qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
390
+ }
391
+ }
392
+ };
393
+ });
394
+ const joiner = matchType === 'OR' ? 'orWhere' : 'andWhere';
395
+ conditions.forEach((condition, i) => {
396
+ if (i === 0) {
397
+ db.where(new typeorm_1.Brackets(condition));
398
+ }
399
+ else {
400
+ db[joiner](new typeorm_1.Brackets(condition));
401
+ }
402
+ });
403
+ }
404
+ if (options.take) {
405
+ db.limit(options.take);
406
+ }
407
+ if (options.skip) {
408
+ db.offset(options.skip);
409
+ }
410
+ if (options.order && options.order.column) {
411
+ const direction = options.order.direction === 'DESC' ? 'DESC' : 'ASC';
412
+ db.orderBy(`store.${options.order.column}`, direction);
413
+ }
414
+ return yield db.getManyAndCount();
415
+ });
416
+ },
310
417
  fetchSystemStats() {
311
418
  return __awaiter(this, void 0, void 0, function* () {
312
419
  const rowCount = yield this.createQueryBuilder().select('COUNT(*)', 'total').getRawOne();