fontastic 0.2.0 → 1.0.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.
- package/.github/workflows/macos.yml +0 -7
- package/.github/workflows/ubuntu.yml +0 -7
- package/.github/workflows/windows.yml +0 -7
- package/README.md +1 -0
- package/app/core/ConnectionManager.js +7 -1
- package/app/core/ConnectionManager.ts +11 -3
- package/app/core/MessageHandler.js +24 -0
- package/app/core/MessageHandler.ts +29 -0
- package/app/core/menu/templates/DarwinTemplate.js +15 -0
- package/app/core/menu/templates/DarwinTemplate.ts +15 -0
- package/app/core/menu/templates/SystemTemplate.js +15 -0
- package/app/core/menu/templates/SystemTemplate.ts +15 -0
- package/app/database/entity/SmartCollection.schema.js +66 -0
- package/app/database/entity/SmartCollection.schema.ts +39 -0
- package/app/database/entity/index.js +1 -0
- package/app/database/entity/index.ts +2 -1
- package/app/database/repository/SmartCollection.repository.js +47 -0
- package/app/database/repository/SmartCollection.repository.ts +30 -0
- package/app/database/repository/Store.repository.js +107 -0
- package/app/database/repository/Store.repository.ts +106 -0
- package/app/database/repository/index.js +1 -0
- package/app/database/repository/index.ts +2 -1
- package/app/enums/ChannelType.js +5 -0
- package/app/enums/ChannelType.ts +6 -0
- package/app/enums/StorageType.js +1 -0
- package/app/enums/StorageType.ts +1 -0
- package/app/package.json +1 -1
- package/app/types/FontMetrics.js +3 -0
- package/app/types/SmartCollection.js +3 -0
- package/app/types/SmartCollection.ts +5 -0
- package/app/types/index.js +2 -0
- package/app/types/index.ts +1 -0
- package/package.json +1 -1
- package/src/app/core/services/database/database.service.ts +70 -1
- package/src/app/core/services/message/message.service.ts +23 -0
- package/src/app/core/services/presentation/presentation.service.ts +47 -0
- package/src/app/layout/header/header.component.html +1 -1
- package/src/app/layout/layout.component.html +1 -1
- package/src/app/layout/navigation/navigation.component.html +70 -4
- package/src/app/layout/navigation/navigation.component.ts +129 -25
- package/src/app/shared/components/datagrid/datagrid.component.html +82 -2
- package/src/app/shared/components/index.ts +1 -0
- package/src/app/shared/components/rule-builder/rule-builder.component.html +94 -0
- package/src/app/shared/components/rule-builder/rule-builder.component.ts +136 -0
- package/src/app/shared/components/toolbar/toolbar.component.html +0 -81
- package/src/app/shared/components/toolbar/toolbar.component.ts +1 -2
- package/src/styles/base/variables.css +16 -0
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' }, {
|
|
@@ -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) {
|
|
@@ -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' }, {
|
|
@@ -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) {
|
|
@@ -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
|
|
@@ -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();
|