@fabriktor/fx 0.0.105 → 0.0.106
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/dist/src/billable/billable.d.ts +41 -27
- package/dist/src/billable/billable.js +110 -54
- package/dist/src/core/search-controller.d.ts +30 -0
- package/dist/src/core/search-controller.js +111 -0
- package/dist/src/core/search.d.ts +5 -1
- package/dist/src/core/search.js +17 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/memos/memos.d.ts +3 -3
- package/dist/src/memos/memos.js +16 -3
- package/package.json +2 -2
|
@@ -26,7 +26,24 @@ type VendorInvoiceInsertOptions = Parameters<BillableOperator["insertOneVendorIn
|
|
|
26
26
|
type VendorInvoiceReplaceOptions = Parameters<BillableOperator["replaceOneVendorInvoice"]>[0];
|
|
27
27
|
type WarehouseInsertOptions = Parameters<BillableOperator["insertOneWarehouse"]>[0];
|
|
28
28
|
type WarehouseReplaceOptions = Parameters<BillableOperator["replaceOneWarehouse"]>[0];
|
|
29
|
-
export
|
|
29
|
+
export declare const BillFilter: {
|
|
30
|
+
readonly All: "all";
|
|
31
|
+
readonly NotCancelled: "not_cancelled";
|
|
32
|
+
readonly Fixed: "fixed";
|
|
33
|
+
readonly Dynamic: "dynamic";
|
|
34
|
+
readonly Cancelled: "cancelled";
|
|
35
|
+
};
|
|
36
|
+
export type BillFilter = (typeof BillFilter)[keyof typeof BillFilter];
|
|
37
|
+
export declare function billFilterFields(value: BillFilter): Partial<Pick<Bill, "is_canceled" | "type">>;
|
|
38
|
+
type ItemSearchFields = Partial<Pick<Item, "folder_id" | "is_archived" | "quantifier_id">> & {
|
|
39
|
+
warehouse_id?: Item["per_warehouse_quantity"][number]["warehouse_id"];
|
|
40
|
+
};
|
|
41
|
+
type EquipmentSearchFields = Partial<Pick<Equipment, "folder_id" | "is_archived" | "warehouse_id" | "rental_type">>;
|
|
42
|
+
type ChargeSearchFields = Partial<Pick<Charge, "location_id" | "entity_id" | "warehouse_id" | "type" | "is_estimate" | "is_billed">>;
|
|
43
|
+
type MeterReadingSearchFields = Partial<Pick<MeterReading, "location_id" | "equipment_id">>;
|
|
44
|
+
export type SearchBillsOptions = OwnerSearchOptions & Partial<Pick<Bill, "is_estimate" | "is_canceled" | "type">> & {
|
|
45
|
+
filter?: BillFilter;
|
|
46
|
+
};
|
|
30
47
|
export type SearchBillsPage = SearchPage<Bill>;
|
|
31
48
|
export type CreateBillableFolderOptions = BillableFolderInsertOptions;
|
|
32
49
|
export type ReplaceBillableFolderOptions = BillableFolderReplaceOptions;
|
|
@@ -34,31 +51,31 @@ export type SearchBillableFoldersOptions = OwnerSearchOptions;
|
|
|
34
51
|
export type SearchBillableFoldersPage = SearchPage<BillableFolder>;
|
|
35
52
|
export type CreateChargeOptions = ChargeInsertOptions;
|
|
36
53
|
export type ReplaceChargeOptions = ChargeReplaceOptions;
|
|
37
|
-
export type SearchChargesOptions = OwnerSearchOptions;
|
|
54
|
+
export type SearchChargesOptions = OwnerSearchOptions & ChargeSearchFields;
|
|
38
55
|
export type SearchChargesPage = SearchPage<Charge>;
|
|
39
56
|
export type CreateEquipmentOptions = EquipmentInsertOptions;
|
|
40
57
|
export type ReplaceEquipmentOptions = EquipmentReplaceOptions;
|
|
41
|
-
export type SearchEquipmentsOptions = OwnerSearchOptions;
|
|
58
|
+
export type SearchEquipmentsOptions = OwnerSearchOptions & EquipmentSearchFields;
|
|
42
59
|
export type SearchEquipmentsPage = SearchPage<Equipment>;
|
|
43
60
|
export type CreateItemOptions = ItemInsertOptions;
|
|
44
61
|
export type ReplaceItemOptions = ItemReplaceOptions;
|
|
45
|
-
export type SearchItemsOptions = OwnerSearchOptions;
|
|
62
|
+
export type SearchItemsOptions = OwnerSearchOptions & ItemSearchFields;
|
|
46
63
|
export type SearchItemsPage = SearchPage<Item>;
|
|
47
64
|
export type CreateLaborRateOptions = LaborRateInsertOptions;
|
|
48
65
|
export type ReplaceLaborRateOptions = LaborRateReplaceOptions;
|
|
49
|
-
export type SearchLaborRatesOptions = OwnerSearchOptions
|
|
66
|
+
export type SearchLaborRatesOptions = OwnerSearchOptions & Partial<Pick<LaborRate, "is_archived">>;
|
|
50
67
|
export type SearchLaborRatesPage = SearchPage<LaborRate>;
|
|
51
68
|
export type CreateMeterReadingOptions = MeterReadingInsertOptions;
|
|
52
69
|
export type ReplaceMeterReadingOptions = MeterReadingReplaceOptions;
|
|
53
|
-
export type SearchMeterReadingsOptions = OwnerSearchOptions;
|
|
70
|
+
export type SearchMeterReadingsOptions = OwnerSearchOptions & MeterReadingSearchFields;
|
|
54
71
|
export type SearchMeterReadingsPage = SearchPage<MeterReading>;
|
|
55
72
|
export type CreateQuantifierOptions = QuantifierInsertOptions;
|
|
56
73
|
export type ReplaceQuantifierOptions = QuantifierReplaceOptions;
|
|
57
|
-
export type SearchQuantifiersOptions = OwnerSearchOptions
|
|
74
|
+
export type SearchQuantifiersOptions = OwnerSearchOptions & Partial<Pick<Quantifier, "is_archived">>;
|
|
58
75
|
export type SearchQuantifiersPage = SearchPage<Quantifier>;
|
|
59
76
|
export type CreateTaxOptions = TaxInsertOptions;
|
|
60
77
|
export type ReplaceTaxOptions = TaxReplaceOptions;
|
|
61
|
-
export type SearchTaxesOptions = OwnerSearchOptions
|
|
78
|
+
export type SearchTaxesOptions = OwnerSearchOptions & Partial<Pick<Tax, "is_archived">>;
|
|
62
79
|
export type SearchTaxesPage = SearchPage<Tax>;
|
|
63
80
|
export type SearchAllTaxesOptions = Omit<SearchTaxesOptions, "page">;
|
|
64
81
|
export type CreateTmpBillNumberOptions = TmpBillNumberInsertOptions;
|
|
@@ -70,11 +87,11 @@ export type CreateVendorInvoiceOptions = VendorInvoiceInsertOptions & {
|
|
|
70
87
|
allow_duplicate?: boolean;
|
|
71
88
|
};
|
|
72
89
|
export type ReplaceVendorInvoiceOptions = VendorInvoiceReplaceOptions;
|
|
73
|
-
export type SearchVendorInvoicesOptions = OwnerSearchOptions
|
|
90
|
+
export type SearchVendorInvoicesOptions = OwnerSearchOptions & Partial<Pick<VendorInvoice, "is_archived">>;
|
|
74
91
|
export type SearchVendorInvoicesPage = SearchPage<VendorInvoice>;
|
|
75
92
|
export type CreateWarehouseOptions = WarehouseInsertOptions;
|
|
76
93
|
export type ReplaceWarehouseOptions = WarehouseReplaceOptions;
|
|
77
|
-
export type SearchWarehousesOptions = OwnerSearchOptions
|
|
94
|
+
export type SearchWarehousesOptions = OwnerSearchOptions & Partial<Pick<Warehouse, "is_archived">>;
|
|
78
95
|
export type SearchWarehousesPage = SearchPage<Warehouse>;
|
|
79
96
|
export type BillableFXOptions = {
|
|
80
97
|
billable: BillableOperator;
|
|
@@ -111,14 +128,12 @@ export type BillableReadSearchOptions = SearchOptions & {
|
|
|
111
128
|
employer_scope_ids?: Iterable<string>;
|
|
112
129
|
query?: SearchQuery;
|
|
113
130
|
};
|
|
114
|
-
export type BillableItemReadSearchOptions = BillableReadSearchOptions &
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
export type
|
|
119
|
-
|
|
120
|
-
rental_type?: string;
|
|
121
|
-
};
|
|
131
|
+
export type BillableItemReadSearchOptions = BillableReadSearchOptions & ItemSearchFields;
|
|
132
|
+
export type BillableEquipmentReadSearchOptions = BillableReadSearchOptions & EquipmentSearchFields;
|
|
133
|
+
export type BillableChargeReadSearchOptions = BillableReadSearchOptions & ChargeSearchFields;
|
|
134
|
+
export type BillableMeterReadingReadSearchOptions = BillableReadSearchOptions & MeterReadingSearchFields;
|
|
135
|
+
export type BillableQuantifierReadSearchOptions = BillableReadSearchOptions & Partial<Pick<Quantifier, "is_archived">>;
|
|
136
|
+
export type BillableWarehouseReadSearchOptions = BillableReadSearchOptions & Partial<Pick<Warehouse, "is_archived">>;
|
|
122
137
|
export type GenerateFixedEstimateOptions = {
|
|
123
138
|
in: GenerateBillPayload;
|
|
124
139
|
};
|
|
@@ -150,7 +165,7 @@ export interface BillableFXOperator {
|
|
|
150
165
|
createCharge(opts: CreateChargeOptions): Promise<Charge>;
|
|
151
166
|
replaceCharge(opts: ReplaceChargeOptions): Promise<Charge>;
|
|
152
167
|
searchCharges(opts: SearchChargesOptions): Promise<SearchChargesPage>;
|
|
153
|
-
searchReadableCharges(opts:
|
|
168
|
+
searchReadableCharges(opts: BillableChargeReadSearchOptions): Promise<SearchChargesPage>;
|
|
154
169
|
createEquipment(opts: CreateEquipmentOptions): Promise<Equipment>;
|
|
155
170
|
replaceEquipment(opts: ReplaceEquipmentOptions): Promise<Equipment>;
|
|
156
171
|
searchEquipments(opts: SearchEquipmentsOptions): Promise<SearchEquipmentsPage>;
|
|
@@ -165,11 +180,11 @@ export interface BillableFXOperator {
|
|
|
165
180
|
createMeterReading(opts: CreateMeterReadingOptions): Promise<MeterReading>;
|
|
166
181
|
replaceMeterReading(opts: ReplaceMeterReadingOptions): Promise<MeterReading>;
|
|
167
182
|
searchMeterReadings(opts: SearchMeterReadingsOptions): Promise<SearchMeterReadingsPage>;
|
|
168
|
-
searchReadableMeterReadings(opts:
|
|
183
|
+
searchReadableMeterReadings(opts: BillableMeterReadingReadSearchOptions): Promise<SearchMeterReadingsPage>;
|
|
169
184
|
createQuantifier(opts: CreateQuantifierOptions): Promise<Quantifier>;
|
|
170
185
|
replaceQuantifier(opts: ReplaceQuantifierOptions): Promise<Quantifier>;
|
|
171
186
|
searchQuantifiers(opts: SearchQuantifiersOptions): Promise<SearchQuantifiersPage>;
|
|
172
|
-
searchReadableQuantifiers(opts:
|
|
187
|
+
searchReadableQuantifiers(opts: BillableQuantifierReadSearchOptions): Promise<SearchQuantifiersPage>;
|
|
173
188
|
createTax(opts: CreateTaxOptions): Promise<Tax>;
|
|
174
189
|
replaceTax(opts: ReplaceTaxOptions): Promise<Tax>;
|
|
175
190
|
searchTaxes(opts: SearchTaxesOptions): Promise<SearchTaxesPage>;
|
|
@@ -183,7 +198,7 @@ export interface BillableFXOperator {
|
|
|
183
198
|
createWarehouse(opts: CreateWarehouseOptions): Promise<Warehouse>;
|
|
184
199
|
replaceWarehouse(opts: ReplaceWarehouseOptions): Promise<Warehouse>;
|
|
185
200
|
searchWarehouses(opts: SearchWarehousesOptions): Promise<SearchWarehousesPage>;
|
|
186
|
-
searchReadableWarehouses(opts:
|
|
201
|
+
searchReadableWarehouses(opts: BillableWarehouseReadSearchOptions): Promise<SearchWarehousesPage>;
|
|
187
202
|
generateFixedEstimate(opts: GenerateFixedEstimateOptions): Promise<Bill>;
|
|
188
203
|
acceptFixedEstimate(opts: AcceptFixedEstimateOptions): Promise<Bill>;
|
|
189
204
|
generateDynamicEstimate(opts: GenerateDynamicEstimateOptions): Promise<Bill>;
|
|
@@ -205,7 +220,7 @@ export declare class BillableFX implements BillableFXOperator {
|
|
|
205
220
|
createCharge(opts: CreateChargeOptions): Promise<Charge>;
|
|
206
221
|
replaceCharge(opts: ReplaceChargeOptions): Promise<Charge>;
|
|
207
222
|
searchCharges(opts: SearchChargesOptions): Promise<SearchChargesPage>;
|
|
208
|
-
searchReadableCharges(opts:
|
|
223
|
+
searchReadableCharges(opts: BillableChargeReadSearchOptions): Promise<SearchChargesPage>;
|
|
209
224
|
createEquipment(opts: CreateEquipmentOptions): Promise<Equipment>;
|
|
210
225
|
replaceEquipment(opts: ReplaceEquipmentOptions): Promise<Equipment>;
|
|
211
226
|
searchEquipments(opts: SearchEquipmentsOptions): Promise<SearchEquipmentsPage>;
|
|
@@ -220,11 +235,11 @@ export declare class BillableFX implements BillableFXOperator {
|
|
|
220
235
|
createMeterReading(opts: CreateMeterReadingOptions): Promise<MeterReading>;
|
|
221
236
|
replaceMeterReading(opts: ReplaceMeterReadingOptions): Promise<MeterReading>;
|
|
222
237
|
searchMeterReadings(opts: SearchMeterReadingsOptions): Promise<SearchMeterReadingsPage>;
|
|
223
|
-
searchReadableMeterReadings(opts:
|
|
238
|
+
searchReadableMeterReadings(opts: BillableMeterReadingReadSearchOptions): Promise<SearchMeterReadingsPage>;
|
|
224
239
|
createQuantifier(opts: CreateQuantifierOptions): Promise<Quantifier>;
|
|
225
240
|
replaceQuantifier(opts: ReplaceQuantifierOptions): Promise<Quantifier>;
|
|
226
241
|
searchQuantifiers(opts: SearchQuantifiersOptions): Promise<SearchQuantifiersPage>;
|
|
227
|
-
searchReadableQuantifiers(opts:
|
|
242
|
+
searchReadableQuantifiers(opts: BillableQuantifierReadSearchOptions): Promise<SearchQuantifiersPage>;
|
|
228
243
|
createTax(opts: CreateTaxOptions): Promise<Tax>;
|
|
229
244
|
replaceTax(opts: ReplaceTaxOptions): Promise<Tax>;
|
|
230
245
|
searchTaxes(opts: SearchTaxesOptions): Promise<SearchTaxesPage>;
|
|
@@ -238,7 +253,7 @@ export declare class BillableFX implements BillableFXOperator {
|
|
|
238
253
|
createWarehouse(opts: CreateWarehouseOptions): Promise<Warehouse>;
|
|
239
254
|
replaceWarehouse(opts: ReplaceWarehouseOptions): Promise<Warehouse>;
|
|
240
255
|
searchWarehouses(opts: SearchWarehousesOptions): Promise<SearchWarehousesPage>;
|
|
241
|
-
searchReadableWarehouses(opts:
|
|
256
|
+
searchReadableWarehouses(opts: BillableWarehouseReadSearchOptions): Promise<SearchWarehousesPage>;
|
|
242
257
|
generateFixedEstimate(opts: GenerateFixedEstimateOptions): Promise<Bill>;
|
|
243
258
|
acceptFixedEstimate(opts: AcceptFixedEstimateOptions): Promise<Bill>;
|
|
244
259
|
generateDynamicEstimate(opts: GenerateDynamicEstimateOptions): Promise<Bill>;
|
|
@@ -249,7 +264,6 @@ export declare class BillableFX implements BillableFXOperator {
|
|
|
249
264
|
vendorInvoiceFromBill(opts: VendorInvoiceFromBillOptions): Promise<VendorInvoice>;
|
|
250
265
|
private generateBill;
|
|
251
266
|
private checkVendorInvoiceNumber;
|
|
252
|
-
private searchReadableActivity;
|
|
253
267
|
private searchReadable;
|
|
254
268
|
private findBill;
|
|
255
269
|
private findBillableFolder;
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
4
4
|
// not use this file except in compliance with the License. You may obtain
|
|
5
5
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
import { queryParams } from "@fabriktor/client";
|
|
6
|
+
import { mergeQueryOptions, queryNestedParam, queryParams, } from "@fabriktor/client";
|
|
7
7
|
import { BillTypeDynamic, BillTypeFixed, UserTypeEmployee, UserTypeEmployer, } from "@fabriktor/schema";
|
|
8
8
|
import { isZeroDateTime } from "../core/date.js";
|
|
9
9
|
import { errRequired, errResolveFailed, errValidation } from "../core/err.js";
|
|
10
10
|
import { requiredOperationID, resolvedID } from "../core/id.js";
|
|
11
11
|
import { runPreActionCheck } from "../core/pre-action.js";
|
|
12
|
-
import { collectSearchResults,
|
|
12
|
+
import { collectSearchResults, runOwnerScopeSearch, runOwnerSearch, withOwnerQuery, } from "../core/search.js";
|
|
13
13
|
const resourceBill = "bill";
|
|
14
14
|
const msgCreatedBillIDMissing = "Created bill response did not contain an ID.";
|
|
15
15
|
const msgBillMissing = "Bill could not be resolved after the mutation.";
|
|
@@ -56,6 +56,26 @@ const msgBillIDRequired = "Bill ID is required.";
|
|
|
56
56
|
const msgBillIDMissing = "Bill response did not contain an ID.";
|
|
57
57
|
const msgCompletableBillRequired = "Only an uncanceled invoice can be completed.";
|
|
58
58
|
const msgAcceptedEstimateCancellation = "Cancel the accepted invoice instead of its estimate.";
|
|
59
|
+
// Composite sidebar states belong with their backend query mapping.
|
|
60
|
+
export const BillFilter = {
|
|
61
|
+
All: "all",
|
|
62
|
+
NotCancelled: "not_cancelled",
|
|
63
|
+
Fixed: BillTypeFixed,
|
|
64
|
+
Dynamic: BillTypeDynamic,
|
|
65
|
+
Cancelled: "cancelled",
|
|
66
|
+
};
|
|
67
|
+
export function billFilterFields(value) {
|
|
68
|
+
switch (value) {
|
|
69
|
+
case BillFilter.All:
|
|
70
|
+
return {};
|
|
71
|
+
case BillFilter.NotCancelled:
|
|
72
|
+
return { is_canceled: false };
|
|
73
|
+
case BillFilter.Cancelled:
|
|
74
|
+
return { is_canceled: true };
|
|
75
|
+
default:
|
|
76
|
+
return { is_canceled: false, type: value };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
59
79
|
export const BillableReadResource = {
|
|
60
80
|
Bill: "bill",
|
|
61
81
|
BillableFolder: "billable_folder",
|
|
@@ -114,6 +134,7 @@ export class BillableFX {
|
|
|
114
134
|
is_estimate: opts.is_estimate,
|
|
115
135
|
is_canceled: opts.is_canceled,
|
|
116
136
|
type: opts.type,
|
|
137
|
+
...(opts.filter === undefined ? {} : billFilterFields(opts.filter)),
|
|
117
138
|
}),
|
|
118
139
|
search: (searchOpts) => this.billable.searchManyBills(searchOpts),
|
|
119
140
|
});
|
|
@@ -145,12 +166,20 @@ export class BillableFX {
|
|
|
145
166
|
async searchCharges(opts) {
|
|
146
167
|
return await runOwnerSearch({
|
|
147
168
|
...opts,
|
|
169
|
+
query: chargeSearchQuery(opts),
|
|
148
170
|
search: (searchOpts) => this.billable.searchManyCharges(searchOpts),
|
|
149
171
|
});
|
|
150
172
|
}
|
|
151
173
|
async searchReadableCharges(opts) {
|
|
152
|
-
|
|
174
|
+
const employer_ids = activityEmployerScopeIDs(opts);
|
|
175
|
+
return await this.searchReadable({
|
|
153
176
|
...opts,
|
|
177
|
+
// owner_id identifies the creator; employer_id identifies their employer.
|
|
178
|
+
// An explicitly empty authorized employer set must not become All.
|
|
179
|
+
allowed_owner_ids: employer_ids?.size === 0 ? [] : activityOwnerIDs(opts.context),
|
|
180
|
+
query: mergeQueryOptions(opts.query, chargeSearchQuery(opts), employer_ids === undefined ? undefined : queryParams({
|
|
181
|
+
employer_id: [...employer_ids],
|
|
182
|
+
})),
|
|
154
183
|
search: (searchOpts) => this.billable.searchManyCharges(searchOpts),
|
|
155
184
|
});
|
|
156
185
|
}
|
|
@@ -166,18 +195,15 @@ export class BillableFX {
|
|
|
166
195
|
async searchEquipments(opts) {
|
|
167
196
|
return await runOwnerSearch({
|
|
168
197
|
...opts,
|
|
198
|
+
query: equipmentSearchQuery(opts),
|
|
169
199
|
search: (searchOpts) => this.billable.searchManyEquipments(searchOpts),
|
|
170
200
|
});
|
|
171
201
|
}
|
|
172
202
|
async searchReadableEquipments(opts) {
|
|
173
|
-
const { warehouse_id, rental_type, ...search_opts } = opts;
|
|
174
203
|
return await this.searchReadable({
|
|
175
|
-
...
|
|
204
|
+
...opts,
|
|
205
|
+
query: mergeQueryOptions(opts.query, equipmentSearchQuery(opts)),
|
|
176
206
|
allowed_owner_ids: catalogOwnerIDs(opts.context, opts.employer_scope_ids),
|
|
177
|
-
filter: warehouse_id === undefined && rental_type === undefined
|
|
178
|
-
? undefined
|
|
179
|
-
: (equipment) => (warehouse_id === undefined || equipment.warehouse_id === warehouse_id) &&
|
|
180
|
-
(rental_type === undefined || equipment.rental_type === rental_type),
|
|
181
207
|
search: (searchOpts) => this.billable.searchManyEquipments(searchOpts),
|
|
182
208
|
});
|
|
183
209
|
}
|
|
@@ -193,19 +219,15 @@ export class BillableFX {
|
|
|
193
219
|
async searchItems(opts) {
|
|
194
220
|
return await runOwnerSearch({
|
|
195
221
|
...opts,
|
|
222
|
+
query: itemSearchQuery(opts),
|
|
196
223
|
search: (searchOpts) => this.billable.searchManyItems(searchOpts),
|
|
197
224
|
});
|
|
198
225
|
}
|
|
199
226
|
async searchReadableItems(opts) {
|
|
200
|
-
const { warehouse_id, quantifier_id, ...search_opts } = opts;
|
|
201
227
|
return await this.searchReadable({
|
|
202
|
-
...
|
|
228
|
+
...opts,
|
|
229
|
+
query: mergeQueryOptions(opts.query, itemSearchQuery(opts)),
|
|
203
230
|
allowed_owner_ids: catalogOwnerIDs(opts.context, opts.employer_scope_ids),
|
|
204
|
-
filter: warehouse_id === undefined && quantifier_id === undefined
|
|
205
|
-
? undefined
|
|
206
|
-
: (item) => (warehouse_id === undefined ||
|
|
207
|
-
item.per_warehouse_quantity.some((quantity) => quantity.warehouse_id === warehouse_id)) &&
|
|
208
|
-
(quantifier_id === undefined || item.quantifier_id === quantifier_id),
|
|
209
231
|
search: (searchOpts) => this.billable.searchManyItems(searchOpts),
|
|
210
232
|
});
|
|
211
233
|
}
|
|
@@ -221,6 +243,7 @@ export class BillableFX {
|
|
|
221
243
|
async searchLaborRates(opts) {
|
|
222
244
|
return await runOwnerSearch({
|
|
223
245
|
...opts,
|
|
246
|
+
query: queryParams({ is_archived: opts.is_archived }),
|
|
224
247
|
search: (searchOpts) => this.billable.searchManyLaborRates(searchOpts),
|
|
225
248
|
});
|
|
226
249
|
}
|
|
@@ -236,12 +259,19 @@ export class BillableFX {
|
|
|
236
259
|
async searchMeterReadings(opts) {
|
|
237
260
|
return await runOwnerSearch({
|
|
238
261
|
...opts,
|
|
262
|
+
query: meterReadingSearchQuery(opts),
|
|
239
263
|
search: (searchOpts) => this.billable.searchManyMeterReadings(searchOpts),
|
|
240
264
|
});
|
|
241
265
|
}
|
|
242
266
|
async searchReadableMeterReadings(opts) {
|
|
243
|
-
|
|
267
|
+
const employer_ids = activityEmployerScopeIDs(opts);
|
|
268
|
+
return await this.searchReadable({
|
|
244
269
|
...opts,
|
|
270
|
+
// An explicitly empty authorized scope must stay empty, not become All.
|
|
271
|
+
allowed_owner_ids: employer_ids?.size === 0 ? [] : activityOwnerIDs(opts.context),
|
|
272
|
+
query: mergeQueryOptions(opts.query, meterReadingSearchQuery(opts), employer_ids === undefined ? undefined : queryParams({
|
|
273
|
+
employer_id: [...employer_ids],
|
|
274
|
+
})),
|
|
245
275
|
search: (searchOpts) => this.billable.searchManyMeterReadings(searchOpts),
|
|
246
276
|
});
|
|
247
277
|
}
|
|
@@ -257,12 +287,16 @@ export class BillableFX {
|
|
|
257
287
|
async searchQuantifiers(opts) {
|
|
258
288
|
return await runOwnerSearch({
|
|
259
289
|
...opts,
|
|
290
|
+
query: queryParams({ is_archived: opts.is_archived }),
|
|
260
291
|
search: (searchOpts) => this.billable.searchManyQuantifiers(searchOpts),
|
|
261
292
|
});
|
|
262
293
|
}
|
|
263
294
|
async searchReadableQuantifiers(opts) {
|
|
264
295
|
return await this.searchReadable({
|
|
265
296
|
...opts,
|
|
297
|
+
query: mergeQueryOptions(opts.query, queryParams({
|
|
298
|
+
...(opts.is_archived === undefined ? {} : { is_archived: opts.is_archived }),
|
|
299
|
+
})),
|
|
266
300
|
allowed_owner_ids: catalogOwnerIDs(opts.context, opts.employer_scope_ids),
|
|
267
301
|
search: (searchOpts) => this.billable.searchManyQuantifiers(searchOpts),
|
|
268
302
|
});
|
|
@@ -279,6 +313,7 @@ export class BillableFX {
|
|
|
279
313
|
async searchTaxes(opts) {
|
|
280
314
|
return await runOwnerSearch({
|
|
281
315
|
...opts,
|
|
316
|
+
query: queryParams({ is_archived: opts.is_archived }),
|
|
282
317
|
search: (searchOpts) => this.billable.searchManyTaxes(searchOpts),
|
|
283
318
|
});
|
|
284
319
|
}
|
|
@@ -329,6 +364,7 @@ export class BillableFX {
|
|
|
329
364
|
async searchVendorInvoices(opts) {
|
|
330
365
|
return await runOwnerSearch({
|
|
331
366
|
...opts,
|
|
367
|
+
query: queryParams({ is_archived: opts.is_archived }),
|
|
332
368
|
search: (searchOpts) => this.billable.searchManyVendorInvoices(searchOpts),
|
|
333
369
|
});
|
|
334
370
|
}
|
|
@@ -344,12 +380,16 @@ export class BillableFX {
|
|
|
344
380
|
async searchWarehouses(opts) {
|
|
345
381
|
return await runOwnerSearch({
|
|
346
382
|
...opts,
|
|
383
|
+
query: queryParams({ is_archived: opts.is_archived }),
|
|
347
384
|
search: (searchOpts) => this.billable.searchManyWarehouses(searchOpts),
|
|
348
385
|
});
|
|
349
386
|
}
|
|
350
387
|
async searchReadableWarehouses(opts) {
|
|
351
388
|
return await this.searchReadable({
|
|
352
389
|
...opts,
|
|
390
|
+
query: mergeQueryOptions(opts.query, queryParams({
|
|
391
|
+
...(opts.is_archived === undefined ? {} : { is_archived: opts.is_archived }),
|
|
392
|
+
})),
|
|
353
393
|
allowed_owner_ids: catalogOwnerIDs(opts.context, opts.employer_scope_ids),
|
|
354
394
|
search: (searchOpts) => this.billable.searchManyWarehouses(searchOpts),
|
|
355
395
|
});
|
|
@@ -424,38 +464,12 @@ export class BillableFX {
|
|
|
424
464
|
},
|
|
425
465
|
});
|
|
426
466
|
}
|
|
427
|
-
async searchReadableActivity(opts) {
|
|
428
|
-
const employer_scope_ids = activityEmployerScopeIDs(opts);
|
|
429
|
-
return await this.searchReadable({
|
|
430
|
-
...opts,
|
|
431
|
-
allowed_owner_ids: activityOwnerIDs(opts.context),
|
|
432
|
-
filter: employer_scope_ids === undefined
|
|
433
|
-
? undefined
|
|
434
|
-
: (value) => employer_scope_ids.has(value.employer_id),
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
467
|
async searchReadable(opts) {
|
|
438
|
-
const { context: _context, owner_ids: requested_owner_ids, employer_scope_ids: _employer_scope_ids, allowed_owner_ids, search,
|
|
468
|
+
const { context: _context, owner_ids: requested_owner_ids, employer_scope_ids: _employer_scope_ids, allowed_owner_ids, search, query, ...searchOpts } = opts;
|
|
439
469
|
const owner_ids = restrictOwnerIDs(allowed_owner_ids, requested_owner_ids);
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
owner_ids,
|
|
444
|
-
query,
|
|
445
|
-
search,
|
|
446
|
-
})
|
|
447
|
-
: await runOwnerScopeFilteredSearch({
|
|
448
|
-
...searchOpts,
|
|
449
|
-
owner_ids,
|
|
450
|
-
query,
|
|
451
|
-
search,
|
|
452
|
-
filter,
|
|
453
|
-
compare: compareCreatedAtDescending,
|
|
454
|
-
});
|
|
455
|
-
return {
|
|
456
|
-
...page,
|
|
457
|
-
results: [...page.results].sort(compareCreatedAtDescending),
|
|
458
|
-
};
|
|
470
|
+
// Keep each backend page in its returned order. The owner contract requires
|
|
471
|
+
// separate requests; do not manufacture a cross-owner sort in the frontend.
|
|
472
|
+
return await runOwnerScopeSearch({ ...searchOpts, owner_ids, query, search });
|
|
459
473
|
}
|
|
460
474
|
async findBill(id) {
|
|
461
475
|
const out = await this.billable.findOneBill({
|
|
@@ -712,6 +726,55 @@ function catalogOwnerIDs(context, employer_scope_ids) {
|
|
|
712
726
|
}
|
|
713
727
|
return uniqueIDs([context.owner_id]);
|
|
714
728
|
}
|
|
729
|
+
function itemSearchQuery(opts) {
|
|
730
|
+
return mergeQueryOptions(queryParams({
|
|
731
|
+
...(opts.folder_id === undefined
|
|
732
|
+
? {}
|
|
733
|
+
: { folder_id: resolvedID(opts.folder_id) }),
|
|
734
|
+
...(opts.is_archived === undefined ? {} : { is_archived: opts.is_archived }),
|
|
735
|
+
...(opts.quantifier_id === undefined
|
|
736
|
+
? {}
|
|
737
|
+
: { quantifier_id: resolvedID(opts.quantifier_id) }),
|
|
738
|
+
}), opts.warehouse_id === undefined ? undefined : queryNestedParam(["per_warehouse_quantity", "warehouse_id"], resolvedID(opts.warehouse_id)));
|
|
739
|
+
}
|
|
740
|
+
function equipmentSearchQuery(opts) {
|
|
741
|
+
return queryParams({
|
|
742
|
+
...(opts.folder_id === undefined
|
|
743
|
+
? {}
|
|
744
|
+
: { folder_id: resolvedID(opts.folder_id) }),
|
|
745
|
+
...(opts.is_archived === undefined ? {} : { is_archived: opts.is_archived }),
|
|
746
|
+
...(opts.warehouse_id === undefined
|
|
747
|
+
? {}
|
|
748
|
+
: { warehouse_id: resolvedID(opts.warehouse_id) }),
|
|
749
|
+
...(opts.rental_type === undefined ? {} : { rental_type: opts.rental_type }),
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
function chargeSearchQuery(opts) {
|
|
753
|
+
return queryParams({
|
|
754
|
+
...(opts.location_id === undefined
|
|
755
|
+
? {}
|
|
756
|
+
: { location_id: resolvedID(opts.location_id) }),
|
|
757
|
+
...(opts.entity_id === undefined
|
|
758
|
+
? {}
|
|
759
|
+
: { entity_id: resolvedID(opts.entity_id) }),
|
|
760
|
+
...(opts.warehouse_id === undefined
|
|
761
|
+
? {}
|
|
762
|
+
: { warehouse_id: resolvedID(opts.warehouse_id) }),
|
|
763
|
+
...(opts.type === undefined ? {} : { type: opts.type }),
|
|
764
|
+
...(opts.is_estimate === undefined ? {} : { is_estimate: opts.is_estimate }),
|
|
765
|
+
...(opts.is_billed === undefined ? {} : { is_billed: opts.is_billed }),
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
function meterReadingSearchQuery(opts) {
|
|
769
|
+
return queryParams({
|
|
770
|
+
...(opts.location_id === undefined
|
|
771
|
+
? {}
|
|
772
|
+
: { location_id: resolvedID(opts.location_id) }),
|
|
773
|
+
...(opts.equipment_id === undefined
|
|
774
|
+
? {}
|
|
775
|
+
: { equipment_id: resolvedID(opts.equipment_id) }),
|
|
776
|
+
});
|
|
777
|
+
}
|
|
715
778
|
function activityEmployerScopeIDs(opts) {
|
|
716
779
|
if (opts.context.active_mode === UserTypeEmployer) {
|
|
717
780
|
return new Set([opts.context.owner_id]);
|
|
@@ -739,13 +802,6 @@ function restrictOwnerIDs(allowed, requested) {
|
|
|
739
802
|
function uniqueIDs(ids) {
|
|
740
803
|
return [...new Set([...ids].map((id) => id.trim()).filter((id) => id !== ""))];
|
|
741
804
|
}
|
|
742
|
-
function compareCreatedAtDescending(left, right) {
|
|
743
|
-
return timestamp(right.created_at) - timestamp(left.created_at);
|
|
744
|
-
}
|
|
745
|
-
function timestamp(value) {
|
|
746
|
-
const out = globalThis.Date.parse(value);
|
|
747
|
-
return Number.isFinite(out) ? out : 0;
|
|
748
|
-
}
|
|
749
805
|
export function newBillableFX(opts) {
|
|
750
806
|
return new BillableFX(opts);
|
|
751
807
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type SearchOptions, type SearchPage, type SearchResultWithID } from "./search.js";
|
|
2
|
+
export type SearchState<T> = {
|
|
3
|
+
readonly results: readonly T[];
|
|
4
|
+
readonly ready: boolean;
|
|
5
|
+
readonly loading: boolean;
|
|
6
|
+
readonly loading_more: boolean;
|
|
7
|
+
readonly error: unknown;
|
|
8
|
+
readonly has_more: boolean;
|
|
9
|
+
readonly total_count?: number;
|
|
10
|
+
};
|
|
11
|
+
export type SearchControllerOptions<T, Options extends SearchOptions> = {
|
|
12
|
+
search: (opts: Options) => Promise<SearchPage<T>>;
|
|
13
|
+
on_change: (state: SearchState<T>) => void;
|
|
14
|
+
};
|
|
15
|
+
export declare class SearchController<T extends SearchResultWithID, Options extends SearchOptions> {
|
|
16
|
+
private readonly options;
|
|
17
|
+
private selection?;
|
|
18
|
+
private request?;
|
|
19
|
+
private next_page;
|
|
20
|
+
private current;
|
|
21
|
+
constructor(options: SearchControllerOptions<T, Options>);
|
|
22
|
+
get state(): SearchState<T>;
|
|
23
|
+
clear(): void;
|
|
24
|
+
replace(selection: Options): Promise<boolean>;
|
|
25
|
+
loadMore(): Promise<boolean>;
|
|
26
|
+
retry(): Promise<boolean>;
|
|
27
|
+
private load;
|
|
28
|
+
private emptyState;
|
|
29
|
+
private publish;
|
|
30
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Copyright (C) Fabriktor, Inc. 2025-present.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
4
|
+
// not use this file except in compliance with the License. You may obtain
|
|
5
|
+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
import { appendUniqueSearchResults, normalizeSearchPage, } from "./search.js";
|
|
7
|
+
import { errUnknown } from "./err.js";
|
|
8
|
+
// Holds only the current selection and its displayed pages. Previous queries
|
|
9
|
+
// are discarded, and revisiting a selection always makes a backend request.
|
|
10
|
+
export class SearchController {
|
|
11
|
+
options;
|
|
12
|
+
selection;
|
|
13
|
+
request;
|
|
14
|
+
next_page = normalizeSearchPage();
|
|
15
|
+
current = this.emptyState();
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
|
+
get state() {
|
|
20
|
+
return this.current;
|
|
21
|
+
}
|
|
22
|
+
// Invalidate immediately, including during text-search debounce or teardown.
|
|
23
|
+
clear() {
|
|
24
|
+
this.request?.abort();
|
|
25
|
+
this.request = undefined;
|
|
26
|
+
this.selection = undefined;
|
|
27
|
+
this.next_page = normalizeSearchPage();
|
|
28
|
+
this.publish(this.emptyState());
|
|
29
|
+
}
|
|
30
|
+
async replace(selection) {
|
|
31
|
+
this.clear();
|
|
32
|
+
this.selection = { ...selection };
|
|
33
|
+
return await this.load(false);
|
|
34
|
+
}
|
|
35
|
+
async loadMore() {
|
|
36
|
+
if (!this.current.has_more || this.current.error !== undefined) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return await this.load(true);
|
|
40
|
+
}
|
|
41
|
+
async retry() {
|
|
42
|
+
return await this.load(this.next_page > normalizeSearchPage());
|
|
43
|
+
}
|
|
44
|
+
async load(append) {
|
|
45
|
+
if (!this.selection || this.current.loading || this.current.loading_more) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const request = new AbortController();
|
|
49
|
+
this.request = request;
|
|
50
|
+
this.publish({
|
|
51
|
+
...this.current,
|
|
52
|
+
loading: !append,
|
|
53
|
+
loading_more: append,
|
|
54
|
+
error: undefined,
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
const page = await this.options.search({
|
|
58
|
+
...this.selection,
|
|
59
|
+
page: this.next_page,
|
|
60
|
+
signal: request.signal,
|
|
61
|
+
});
|
|
62
|
+
if (this.request !== request || request.signal.aborted) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
this.next_page = page.next_page;
|
|
66
|
+
this.publish({
|
|
67
|
+
results: append
|
|
68
|
+
? appendUniqueSearchResults(this.current.results, page.results)
|
|
69
|
+
: page.results,
|
|
70
|
+
ready: true,
|
|
71
|
+
loading: false,
|
|
72
|
+
loading_more: false,
|
|
73
|
+
error: undefined,
|
|
74
|
+
has_more: page.has_more,
|
|
75
|
+
total_count: page.total_count,
|
|
76
|
+
});
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (this.request !== request || request.signal.aborted) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
this.publish({
|
|
84
|
+
...this.current,
|
|
85
|
+
loading: false,
|
|
86
|
+
loading_more: false,
|
|
87
|
+
error: errUnknown(error),
|
|
88
|
+
});
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
if (this.request === request) {
|
|
93
|
+
this.request = undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
emptyState() {
|
|
98
|
+
return {
|
|
99
|
+
results: [],
|
|
100
|
+
ready: false,
|
|
101
|
+
loading: false,
|
|
102
|
+
loading_more: false,
|
|
103
|
+
error: undefined,
|
|
104
|
+
has_more: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
publish(state) {
|
|
108
|
+
this.current = state;
|
|
109
|
+
this.options.on_change(state);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -4,7 +4,7 @@ export type SearchPaginationOptions = {
|
|
|
4
4
|
page?: number;
|
|
5
5
|
per_page?: number;
|
|
6
6
|
};
|
|
7
|
-
export type SearchOptions = SearchPaginationOptions & {
|
|
7
|
+
export type SearchOptions = SearchPaginationOptions & Pick<SearchManyOptionsCRUD, "signal"> & {
|
|
8
8
|
q?: string;
|
|
9
9
|
};
|
|
10
10
|
export type RequiredSearchOptions = SearchPaginationOptions & {
|
|
@@ -54,3 +54,7 @@ export declare function runSearch<T>(opts: RunSearchOptions<T>): Promise<SearchP
|
|
|
54
54
|
export declare function normalizeSearchPage(value?: number): number;
|
|
55
55
|
export declare function normalizeSearchPerPage(value?: number): number;
|
|
56
56
|
export declare function normalizeSearchQuery(value?: string): string | undefined;
|
|
57
|
+
export type SearchResultWithID = {
|
|
58
|
+
readonly id: string;
|
|
59
|
+
};
|
|
60
|
+
export declare function appendUniqueSearchResults<T extends SearchResultWithID>(current: readonly T[], next: readonly T[]): T[];
|
package/dist/src/core/search.js
CHANGED
|
@@ -48,6 +48,7 @@ export async function runOwnerScopeSearch(opts) {
|
|
|
48
48
|
per_page,
|
|
49
49
|
query: opts.query,
|
|
50
50
|
search: opts.search,
|
|
51
|
+
signal: opts.signal,
|
|
51
52
|
})));
|
|
52
53
|
const results = new Map();
|
|
53
54
|
for (const ownerPage of pages) {
|
|
@@ -94,6 +95,7 @@ export async function runOwnerScopeFilteredSearch(opts) {
|
|
|
94
95
|
per_page,
|
|
95
96
|
query: opts.query,
|
|
96
97
|
search: opts.search,
|
|
98
|
+
signal: opts.signal,
|
|
97
99
|
}),
|
|
98
100
|
})));
|
|
99
101
|
for (const owner_page of pages) {
|
|
@@ -147,6 +149,7 @@ export async function runSearch(opts) {
|
|
|
147
149
|
};
|
|
148
150
|
const raw = await opts.search({
|
|
149
151
|
query,
|
|
152
|
+
signal: opts.signal,
|
|
150
153
|
});
|
|
151
154
|
return resolveSearchPage({
|
|
152
155
|
raw,
|
|
@@ -236,3 +239,17 @@ function maxDefined(values) {
|
|
|
236
239
|
}
|
|
237
240
|
return Math.max(...values.map((value) => value ?? 0));
|
|
238
241
|
}
|
|
242
|
+
export function appendUniqueSearchResults(current, next) {
|
|
243
|
+
const out = [...current];
|
|
244
|
+
const indexes = new Map(out.map((item, index) => [item.id, index]));
|
|
245
|
+
for (const item of next) {
|
|
246
|
+
const index = indexes.get(item.id);
|
|
247
|
+
if (index === undefined) {
|
|
248
|
+
indexes.set(item.id, out.length);
|
|
249
|
+
out.push(item);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
out[index] = item;
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from "./core/pre-action.js";
|
|
|
12
12
|
export * from "./core/pull.js";
|
|
13
13
|
export * from "./core/queue-store.js";
|
|
14
14
|
export * from "./core/queue.js";
|
|
15
|
+
export * from "./core/search-controller.js";
|
|
15
16
|
export * from "./core/search.js";
|
|
16
17
|
export * from "./feed/feed.js";
|
|
17
18
|
export * from "./fulfillments/fulfillments.js";
|
package/dist/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export * from "./core/pre-action.js";
|
|
|
12
12
|
export * from "./core/pull.js";
|
|
13
13
|
export * from "./core/queue-store.js";
|
|
14
14
|
export * from "./core/queue.js";
|
|
15
|
+
export * from "./core/search-controller.js";
|
|
15
16
|
export * from "./core/search.js";
|
|
16
17
|
export * from "./feed/feed.js";
|
|
17
18
|
export * from "./fulfillments/fulfillments.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
1
|
+
import { type MemosOperator } from "@fabriktor/client";
|
|
2
|
+
import { type Memo, type MemoFolder } from "@fabriktor/schema";
|
|
3
3
|
import { type OwnerSearchOptions, type SearchPage } from "../core/search.js";
|
|
4
4
|
type MemoInsertOptions = Parameters<MemosOperator["insertOneMemo"]>[0];
|
|
5
5
|
type MemoReplaceOptions = Parameters<MemosOperator["replaceOneMemo"]>[0];
|
|
@@ -9,7 +9,7 @@ export type CreateMemoOptions = MemoInsertOptions;
|
|
|
9
9
|
export type ReplaceMemoOptions = MemoReplaceOptions;
|
|
10
10
|
export type CreateMemoFolderOptions = MemoFolderInsertOptions;
|
|
11
11
|
export type ReplaceMemoFolderOptions = MemoFolderReplaceOptions;
|
|
12
|
-
export type SearchMemosOptions = OwnerSearchOptions
|
|
12
|
+
export type SearchMemosOptions = OwnerSearchOptions & Partial<Pick<Memo, "is_archived" | "folder_id">>;
|
|
13
13
|
export type SearchMemoFoldersOptions = OwnerSearchOptions;
|
|
14
14
|
export type SearchMemosPage = SearchPage<Memo>;
|
|
15
15
|
export type SearchMemoFoldersPage = SearchPage<MemoFolder>;
|
package/dist/src/memos/memos.js
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
4
4
|
// not use this file except in compliance with the License. You may obtain
|
|
5
5
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { queryParams } from "@fabriktor/client";
|
|
7
|
+
import { OwnerIDKey } from "@fabriktor/schema";
|
|
8
|
+
import { errRequired, errResolveFailed } from "../core/err.js";
|
|
9
|
+
import { requiredOperationID, resolvedID } from "../core/id.js";
|
|
8
10
|
import { runOwnerSearch, } from "../core/search.js";
|
|
9
11
|
const resourceMemo = "memo";
|
|
10
12
|
const resourceMemoFolder = "memo_folder";
|
|
11
13
|
const msgCreatedMemoIDMissing = "Created memo response did not contain an ID.";
|
|
12
14
|
const msgMemoMissing = "Memo could not be resolved after the mutation.";
|
|
15
|
+
const msgMemoOwnerRequired = "Memo owner is required.";
|
|
13
16
|
const msgCreatedMemoFolderIDMissing = "Created memo folder response did not contain an ID.";
|
|
14
17
|
const msgMemoFolderMissing = "Memo folder could not be resolved after the mutation.";
|
|
15
18
|
export class MemosFX {
|
|
@@ -36,8 +39,18 @@ export class MemosFX {
|
|
|
36
39
|
return await this.findMemoFolder(opts.id);
|
|
37
40
|
}
|
|
38
41
|
async searchMemos(opts) {
|
|
42
|
+
const { is_archived, folder_id, ...searchOpts } = opts;
|
|
43
|
+
const owner_id = resolvedID(opts.owner_id);
|
|
44
|
+
if (owner_id === undefined) {
|
|
45
|
+
throw errRequired({ field: OwnerIDKey, msg: msgMemoOwnerRequired });
|
|
46
|
+
}
|
|
39
47
|
return await runOwnerSearch({
|
|
40
|
-
...
|
|
48
|
+
...searchOpts,
|
|
49
|
+
owner_id,
|
|
50
|
+
query: queryParams({
|
|
51
|
+
is_archived,
|
|
52
|
+
folder_id: resolvedID(folder_id),
|
|
53
|
+
}),
|
|
41
54
|
search: (searchOpts) => this.memos.searchManyMemos(searchOpts),
|
|
42
55
|
});
|
|
43
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabriktor/fx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.106",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typescript": "^6.0.3"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fabriktor/client": "0.0.
|
|
20
|
+
"@fabriktor/client": "0.0.83",
|
|
21
21
|
"@fabriktor/fx": "0.0.94",
|
|
22
22
|
"@fabriktor/schema": "0.0.63"
|
|
23
23
|
}
|