@forestadmin/agent 1.0.0-beta.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/LICENSE +674 -0
- package/README.md +0 -0
- package/dist/agent/forestadmin-http-driver.d.ts +34 -0
- package/dist/agent/forestadmin-http-driver.js +73 -0
- package/dist/agent/routes/access/chart.d.ts +17 -0
- package/dist/agent/routes/access/chart.js +125 -0
- package/dist/agent/routes/access/count-related.d.ts +9 -0
- package/dist/agent/routes/access/count-related.js +24 -0
- package/dist/agent/routes/access/count.d.ts +9 -0
- package/dist/agent/routes/access/count.js +24 -0
- package/dist/agent/routes/access/csv-related.d.ts +9 -0
- package/dist/agent/routes/access/csv-related.js +33 -0
- package/dist/agent/routes/access/csv.d.ts +9 -0
- package/dist/agent/routes/access/csv.js +30 -0
- package/dist/agent/routes/access/get.d.ts +9 -0
- package/dist/agent/routes/access/get.js +28 -0
- package/dist/agent/routes/access/list-related.d.ts +9 -0
- package/dist/agent/routes/access/list-related.js +26 -0
- package/dist/agent/routes/access/list.d.ts +9 -0
- package/dist/agent/routes/access/list.js +23 -0
- package/dist/agent/routes/base-route.d.ts +14 -0
- package/dist/agent/routes/base-route.js +16 -0
- package/dist/agent/routes/collection-route.d.ts +12 -0
- package/dist/agent/routes/collection-route.js +20 -0
- package/dist/agent/routes/index.d.ts +30 -0
- package/dist/agent/routes/index.js +90 -0
- package/dist/agent/routes/modification/action.d.ts +17 -0
- package/dist/agent/routes/modification/action.js +103 -0
- package/dist/agent/routes/modification/associate-related.d.ts +12 -0
- package/dist/agent/routes/modification/associate-related.js +49 -0
- package/dist/agent/routes/modification/create.d.ts +14 -0
- package/dist/agent/routes/modification/create.js +81 -0
- package/dist/agent/routes/modification/delete.d.ts +11 -0
- package/dist/agent/routes/modification/delete.js +40 -0
- package/dist/agent/routes/modification/dissociate-delete-related.d.ts +20 -0
- package/dist/agent/routes/modification/dissociate-delete-related.js +88 -0
- package/dist/agent/routes/modification/update-relation.d.ts +11 -0
- package/dist/agent/routes/modification/update-relation.js +53 -0
- package/dist/agent/routes/modification/update.d.ts +9 -0
- package/dist/agent/routes/modification/update.js +29 -0
- package/dist/agent/routes/relation-route.d.ts +10 -0
- package/dist/agent/routes/relation-route.js +18 -0
- package/dist/agent/routes/security/authentication.d.ts +17 -0
- package/dist/agent/routes/security/authentication.js +86 -0
- package/dist/agent/routes/security/ip-whitelist.d.ts +14 -0
- package/dist/agent/routes/security/ip-whitelist.js +35 -0
- package/dist/agent/routes/security/scope-invalidation.d.ts +11 -0
- package/dist/agent/routes/security/scope-invalidation.js +28 -0
- package/dist/agent/routes/system/error-handling.d.ts +11 -0
- package/dist/agent/routes/system/error-handling.js +56 -0
- package/dist/agent/routes/system/healthcheck.d.ts +11 -0
- package/dist/agent/routes/system/healthcheck.js +22 -0
- package/dist/agent/routes/system/logger.d.ts +10 -0
- package/dist/agent/routes/system/logger.js +36 -0
- package/dist/agent/services/index.d.ts +10 -0
- package/dist/agent/services/index.js +12 -0
- package/dist/agent/services/permissions.d.ts +19 -0
- package/dist/agent/services/permissions.js +79 -0
- package/dist/agent/services/serializer.d.ts +17 -0
- package/dist/agent/services/serializer.js +120 -0
- package/dist/agent/types.d.ts +23 -0
- package/dist/agent/types.js +22 -0
- package/dist/agent/utils/body-parser.d.ts +7 -0
- package/dist/agent/utils/body-parser.js +18 -0
- package/dist/agent/utils/context-filter-factory.d.ts +7 -0
- package/dist/agent/utils/context-filter-factory.js +29 -0
- package/dist/agent/utils/csv-generator.d.ts +12 -0
- package/dist/agent/utils/csv-generator.js +39 -0
- package/dist/agent/utils/csv-route-context.d.ts +5 -0
- package/dist/agent/utils/csv-route-context.js +14 -0
- package/dist/agent/utils/forest-http-api.d.ts +63 -0
- package/dist/agent/utils/forest-http-api.js +173 -0
- package/dist/agent/utils/forest-schema/action-values.d.ts +34 -0
- package/dist/agent/utils/forest-schema/action-values.js +144 -0
- package/dist/agent/utils/forest-schema/emitter.d.ts +20 -0
- package/dist/agent/utils/forest-schema/emitter.js +70 -0
- package/dist/agent/utils/forest-schema/filterable.d.ts +16 -0
- package/dist/agent/utils/forest-schema/filterable.js +68 -0
- package/dist/agent/utils/forest-schema/generator-actions.d.ts +14 -0
- package/dist/agent/utils/forest-schema/generator-actions.js +99 -0
- package/dist/agent/utils/forest-schema/generator-collection.d.ts +7 -0
- package/dist/agent/utils/forest-schema/generator-collection.js +31 -0
- package/dist/agent/utils/forest-schema/generator-fields.d.ts +13 -0
- package/dist/agent/utils/forest-schema/generator-fields.js +131 -0
- package/dist/agent/utils/forest-schema/generator-segments.d.ts +6 -0
- package/dist/agent/utils/forest-schema/generator-segments.js +9 -0
- package/dist/agent/utils/forest-schema/types.d.ts +79 -0
- package/dist/agent/utils/forest-schema/types.js +16 -0
- package/dist/agent/utils/forest-schema/validation.d.ts +10 -0
- package/dist/agent/utils/forest-schema/validation.js +26 -0
- package/dist/agent/utils/http-driver-options.d.ts +13 -0
- package/dist/agent/utils/http-driver-options.js +86 -0
- package/dist/agent/utils/id.d.ts +8 -0
- package/dist/agent/utils/id.js +43 -0
- package/dist/agent/utils/query-string.d.ts +14 -0
- package/dist/agent/utils/query-string.js +130 -0
- package/dist/builder/agent.d.ts +81 -0
- package/dist/builder/agent.js +113 -0
- package/dist/builder/collection.d.ts +148 -0
- package/dist/builder/collection.js +226 -0
- package/dist/builder/types.d.ts +5 -0
- package/dist/builder/types.js +3 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +22 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.js +11 -0
- package/dist/utils/csv-generator.d.ts +12 -0
- package/dist/utils/csv-generator.js +39 -0
- package/package.json +55 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
8
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
9
|
+
const superagent_1 = __importDefault(require("superagent"));
|
|
10
|
+
class ForestHttpApi {
|
|
11
|
+
static async getIpWhitelistConfiguration(options) {
|
|
12
|
+
try {
|
|
13
|
+
const response = await superagent_1.default
|
|
14
|
+
.get(new URL('/liana/v1/ip-whitelist-rules', options.forestServerUrl).toString())
|
|
15
|
+
.set('forest-secret-key', options.envSecret);
|
|
16
|
+
const { attributes } = response.body.data;
|
|
17
|
+
return { isFeatureEnabled: attributes.use_ip_whitelist, ipRules: attributes.rules };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new Error('An error occurred while retrieving your IP whitelist.');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
static async getOpenIdIssuerMetadata(options) {
|
|
24
|
+
try {
|
|
25
|
+
const response = await superagent_1.default
|
|
26
|
+
.get(new URL('/oidc/.well-known/openid-configuration', options.forestServerUrl).toString())
|
|
27
|
+
.set('forest-secret-key', options.envSecret);
|
|
28
|
+
return response.body;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error('Failed to fetch open-id issuer metadata.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
static async getUserInformation(options, renderingId, accessToken) {
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(`/liana/v2/renderings/${renderingId}/authorization`, options.forestServerUrl);
|
|
37
|
+
const response = await superagent_1.default
|
|
38
|
+
.get(url.toString())
|
|
39
|
+
.set('forest-token', accessToken)
|
|
40
|
+
.set('forest-secret-key', options.envSecret);
|
|
41
|
+
const { attributes, id } = response.body.data;
|
|
42
|
+
return {
|
|
43
|
+
id: Number(id),
|
|
44
|
+
email: attributes.email,
|
|
45
|
+
firstName: attributes.first_name,
|
|
46
|
+
lastName: attributes.last_name,
|
|
47
|
+
team: attributes.teams[0],
|
|
48
|
+
role: attributes.role,
|
|
49
|
+
tags: attributes.tags?.reduce((memo, { key, value }) => ({ ...memo, [key]: value }), {}),
|
|
50
|
+
renderingId,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new Error('Failed to retrieve authorization informations.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
static async hasSchema(options, hash) {
|
|
58
|
+
const response = await superagent_1.default
|
|
59
|
+
.post(new URL('/forest/apimaps/hashcheck', options.forestServerUrl).toString())
|
|
60
|
+
.send({ schemaFileHash: hash })
|
|
61
|
+
.set('forest-secret-key', options.envSecret);
|
|
62
|
+
return !response?.body?.sendSchema;
|
|
63
|
+
}
|
|
64
|
+
static async uploadSchema(options, apimap) {
|
|
65
|
+
try {
|
|
66
|
+
await superagent_1.default
|
|
67
|
+
.post(new URL('/forest/apimaps', options.forestServerUrl).toString())
|
|
68
|
+
.send(apimap)
|
|
69
|
+
.set('forest-secret-key', options.envSecret);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
// Sending the schema to forestadmin-server is mandatory: crash the server gracefully
|
|
73
|
+
let message;
|
|
74
|
+
switch (e.response?.status) {
|
|
75
|
+
case 0:
|
|
76
|
+
message = 'Cannot send the apimap to Forest. Are you online?';
|
|
77
|
+
break;
|
|
78
|
+
case 404:
|
|
79
|
+
message =
|
|
80
|
+
'Cannot find the project related to the envSecret you configured. ' +
|
|
81
|
+
'Can you check on Forest that you copied it properly in the Forest initialization?';
|
|
82
|
+
break;
|
|
83
|
+
case 503:
|
|
84
|
+
message =
|
|
85
|
+
'Forest is in maintenance for a few minutes. ' +
|
|
86
|
+
'We are upgrading your experience in the forest. ' +
|
|
87
|
+
'We just need a few more minutes to get it right.';
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
message =
|
|
91
|
+
'An error occured with the apimap sent to Forest. ' +
|
|
92
|
+
'Please contact support@forestadmin.com for further investigations.';
|
|
93
|
+
}
|
|
94
|
+
throw new Error(message);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
static async getPermissions(options, renderingId) {
|
|
98
|
+
const { body } = await superagent_1.default
|
|
99
|
+
.get(`${options.forestServerUrl}/liana/v3/permissions`)
|
|
100
|
+
.set('forest-secret-key', options.envSecret)
|
|
101
|
+
.query(`renderingId=${renderingId}`);
|
|
102
|
+
if (!body.meta?.rolesACLActivated) {
|
|
103
|
+
throw new Error('Roles V2 are unsupported');
|
|
104
|
+
}
|
|
105
|
+
const actions = new Set();
|
|
106
|
+
const actionsByUser = {};
|
|
107
|
+
ForestHttpApi.decodeChartPermissions(body?.stats ?? {}, actions);
|
|
108
|
+
ForestHttpApi.decodeActionPermissions(body?.data?.collections ?? {}, actions, actionsByUser);
|
|
109
|
+
return {
|
|
110
|
+
actions,
|
|
111
|
+
actionsByUser,
|
|
112
|
+
scopes: ForestHttpApi.decodeScopePermissions(body?.data?.renderings?.[renderingId] ?? {}),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Helper to format permissions into something easy to validate against */
|
|
116
|
+
static decodeChartPermissions(chartsByType, actions) {
|
|
117
|
+
const serverCharts = Object.values(chartsByType).flat();
|
|
118
|
+
const frontendCharts = serverCharts.map(chart => ({
|
|
119
|
+
type: chart.type,
|
|
120
|
+
filters: chart.filter,
|
|
121
|
+
aggregate: chart.aggregator,
|
|
122
|
+
aggregate_field: chart.aggregateFieldName,
|
|
123
|
+
collection: chart.sourceCollectionId,
|
|
124
|
+
time_range: chart.timeRange,
|
|
125
|
+
group_by_date_field: (chart.type === 'Line' && chart.groupByFieldName) || null,
|
|
126
|
+
group_by_field: (chart.type !== 'Line' && chart.groupByFieldName) || null,
|
|
127
|
+
limit: chart.limit,
|
|
128
|
+
label_field: chart.labelFieldName,
|
|
129
|
+
relationship_field: chart.relationshipFieldName,
|
|
130
|
+
}));
|
|
131
|
+
const hashes = frontendCharts.map(chart => (0, object_hash_1.default)(chart, {
|
|
132
|
+
respectType: false,
|
|
133
|
+
excludeKeys: key => chart[key] === null || chart[key] === undefined,
|
|
134
|
+
}));
|
|
135
|
+
hashes.forEach(hash => actions.add(`chart:${hash}`));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Helper to format permissions into something easy to validate against
|
|
139
|
+
* Note that the format the server is sending varies depending on if we're using a remote or
|
|
140
|
+
* local environment.
|
|
141
|
+
*/
|
|
142
|
+
static decodeActionPermissions(collections, actions, actionsByUser) {
|
|
143
|
+
for (const [name, settings] of Object.entries(collections)) {
|
|
144
|
+
for (const [actionName, userIds] of Object.entries(settings.collection ?? {})) {
|
|
145
|
+
const shortName = actionName.substring(0, actionName.length - 'Enabled'.length);
|
|
146
|
+
if (typeof userIds === 'boolean')
|
|
147
|
+
actions.add(`${shortName}:${name}`);
|
|
148
|
+
else
|
|
149
|
+
actionsByUser[`${shortName}:${name}`] = new Set(userIds);
|
|
150
|
+
}
|
|
151
|
+
for (const [actionName, actionPerms] of Object.entries(settings.actions ?? {})) {
|
|
152
|
+
const userIds = actionPerms.triggerEnabled;
|
|
153
|
+
if (typeof userIds === 'boolean')
|
|
154
|
+
actions.add(`custom:${actionName}:${name}`);
|
|
155
|
+
else
|
|
156
|
+
actionsByUser[`custom:${actionName}:${name}`] = new Set(userIds);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Helper to format permissions into something easy to validate against */
|
|
161
|
+
static decodeScopePermissions(rendering) {
|
|
162
|
+
const scopes = {};
|
|
163
|
+
for (const [name, { scope }] of Object.entries(rendering)) {
|
|
164
|
+
scopes[name] = scope && {
|
|
165
|
+
conditionTree: datasource_toolkit_1.ConditionTreeFactory.fromPlainObject(scope.filter),
|
|
166
|
+
dynamicScopeValues: scope.dynamicScopesValues?.users ?? {},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return scopes;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.default = ForestHttpApi;
|
|
173
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0LWh0dHAtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FnZW50L3V0aWxzL2ZvcmVzdC1odHRwLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHVEQUF1RDtBQUN2RCx3RUFBc0Y7QUFHdEYsOERBQXFDO0FBQ3JDLDREQUFpRTtBQXVDakUsTUFBcUIsYUFBYTtJQUNoQyxNQUFNLENBQUMsS0FBSyxDQUFDLDJCQUEyQixDQUN0QyxPQUFvQjtRQUVwQixJQUFJO1lBQ0YsTUFBTSxRQUFRLEdBQWEsTUFBTSxvQkFBVTtpQkFDeEMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLDhCQUE4QixFQUFFLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztpQkFDaEYsR0FBRyxDQUFDLG1CQUFtQixFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUUvQyxNQUFNLEVBQUUsVUFBVSxFQUFFLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFFMUMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ3JGO1FBQUMsTUFBTTtZQUNOLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztTQUMxRTtJQUNILENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLHVCQUF1QixDQUFDLE9BQW9CO1FBQ3ZELElBQUk7WUFDRixNQUFNLFFBQVEsR0FBYSxNQUFNLG9CQUFVO2lCQUN4QyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsd0NBQXdDLEVBQUUsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO2lCQUMxRixHQUFHLENBQUMsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRS9DLE9BQU8sUUFBUSxDQUFD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
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ActionField, DataSource } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
declare type FormData = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* This utility class converts form values from our internal format to the format that is
|
|
5
|
+
* used in the frontend for smart action forms.
|
|
6
|
+
*/
|
|
7
|
+
export default class ForestValueConverter {
|
|
8
|
+
/**
|
|
9
|
+
* Proper form data parser which converts data from a smart action form result to the format
|
|
10
|
+
* that is internally used in datasources.
|
|
11
|
+
*/
|
|
12
|
+
static makeFormData(dataSource: DataSource, rawData: FormData, fields: ActionField[]): FormData;
|
|
13
|
+
/**
|
|
14
|
+
* Form data parser which extracts the data from what is provided by the frontend when
|
|
15
|
+
* change hooks are called.
|
|
16
|
+
*/
|
|
17
|
+
static makeFormDataFromFields(dataSource: DataSource, fields: any[]): FormData;
|
|
18
|
+
/**
|
|
19
|
+
* This last form data parser tries to guess the types from the data itself.
|
|
20
|
+
*
|
|
21
|
+
* - Fields with type "Collection" which target collections where the pk is not a string or
|
|
22
|
+
* derivative (mongoid, uuid, ...) won't be parser correctly, as we don't have enough information
|
|
23
|
+
* to properly guess the type
|
|
24
|
+
* - Fields of type "String" but where the final user entered a data-uri manually in the frontend
|
|
25
|
+
* will be wrongfully parsed.
|
|
26
|
+
*/
|
|
27
|
+
static makeFormDataUnsafe(rawData: FormData): FormData;
|
|
28
|
+
static valueToForest(field: ActionField, value: unknown): unknown;
|
|
29
|
+
private static parseDataUri;
|
|
30
|
+
private static makeDataUri;
|
|
31
|
+
private static isDataUri;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=action-values.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const id_1 = __importDefault(require("../id"));
|
|
7
|
+
const generator_actions_1 = __importDefault(require("./generator-actions"));
|
|
8
|
+
/**
|
|
9
|
+
* This utility class converts form values from our internal format to the format that is
|
|
10
|
+
* used in the frontend for smart action forms.
|
|
11
|
+
*/
|
|
12
|
+
class ForestValueConverter {
|
|
13
|
+
/**
|
|
14
|
+
* Proper form data parser which converts data from a smart action form result to the format
|
|
15
|
+
* that is internally used in datasources.
|
|
16
|
+
*/
|
|
17
|
+
static makeFormData(dataSource, rawData, fields) {
|
|
18
|
+
const data = {};
|
|
19
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
20
|
+
const field = fields.find(f => f.label === key);
|
|
21
|
+
// Skip fields from the default form
|
|
22
|
+
if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(key)) {
|
|
23
|
+
if (field?.type === 'Collection' && value) {
|
|
24
|
+
const collection = dataSource.getCollection(field.collectionName);
|
|
25
|
+
data[key] = id_1.default.unpackId(collection.schema, value);
|
|
26
|
+
}
|
|
27
|
+
else if (field?.type === 'File') {
|
|
28
|
+
data[key] = this.parseDataUri(value);
|
|
29
|
+
}
|
|
30
|
+
else if (field?.type === 'FileList') {
|
|
31
|
+
data[key] = value?.map(v => this.parseDataUri(v));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
data[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Form data parser which extracts the data from what is provided by the frontend when
|
|
42
|
+
* change hooks are called.
|
|
43
|
+
*/
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
static makeFormDataFromFields(dataSource, fields) {
|
|
46
|
+
const data = {};
|
|
47
|
+
for (const field of fields) {
|
|
48
|
+
// Skip fields from the default form
|
|
49
|
+
if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(field.field)) {
|
|
50
|
+
if (field.reference && field.value) {
|
|
51
|
+
const [collectionName] = field.reference.split('.');
|
|
52
|
+
const collection = dataSource.getCollection(collectionName);
|
|
53
|
+
data[field.field] = id_1.default.unpackId(collection.schema, field.value);
|
|
54
|
+
}
|
|
55
|
+
else if (field.type === 'File') {
|
|
56
|
+
data[field.field] = this.parseDataUri(field.value);
|
|
57
|
+
}
|
|
58
|
+
else if (Array.isArray(field.type) && field.type[0] === 'File') {
|
|
59
|
+
data[field.field] = field.value?.map(v => this.parseDataUri(v));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
data[field.field] = field.value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return data;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* This last form data parser tries to guess the types from the data itself.
|
|
70
|
+
*
|
|
71
|
+
* - Fields with type "Collection" which target collections where the pk is not a string or
|
|
72
|
+
* derivative (mongoid, uuid, ...) won't be parser correctly, as we don't have enough information
|
|
73
|
+
* to properly guess the type
|
|
74
|
+
* - Fields of type "String" but where the final user entered a data-uri manually in the frontend
|
|
75
|
+
* will be wrongfully parsed.
|
|
76
|
+
*/
|
|
77
|
+
static makeFormDataUnsafe(rawData) {
|
|
78
|
+
const data = {};
|
|
79
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
80
|
+
// Skip fields from the default form
|
|
81
|
+
if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(key)) {
|
|
82
|
+
if (Array.isArray(value) && value.every(v => this.isDataUri(v))) {
|
|
83
|
+
data[key] = value.map(uri => this.parseDataUri(uri));
|
|
84
|
+
}
|
|
85
|
+
else if (this.isDataUri(value)) {
|
|
86
|
+
data[key] = this.parseDataUri(value);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
data[key] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return data;
|
|
94
|
+
}
|
|
95
|
+
static valueToForest(field, value) {
|
|
96
|
+
if (field.type === 'Enum') {
|
|
97
|
+
return field.enumValues.includes(value) ? value : null;
|
|
98
|
+
}
|
|
99
|
+
if (field.type === 'EnumList') {
|
|
100
|
+
return value?.filter(v => field.enumValues.includes(v));
|
|
101
|
+
}
|
|
102
|
+
if (field.type === 'Collection') {
|
|
103
|
+
return value?.join('|');
|
|
104
|
+
}
|
|
105
|
+
if (field.type === 'File') {
|
|
106
|
+
return this.makeDataUri(value);
|
|
107
|
+
}
|
|
108
|
+
if (field.type === 'FileList') {
|
|
109
|
+
return value?.map(f => this.makeDataUri(f));
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
static parseDataUri(dataUri) {
|
|
114
|
+
if (!dataUri)
|
|
115
|
+
return null;
|
|
116
|
+
// Poor man's data uri parser (spec compliants one don't get the filename).
|
|
117
|
+
// Hopefully this does not break.
|
|
118
|
+
const [header, data] = dataUri.substring(5).split(',');
|
|
119
|
+
const [mimeType, ...mediaTypes] = header.split(';');
|
|
120
|
+
const result = { mimeType, buffer: Buffer.from(data, 'base64') };
|
|
121
|
+
for (const mediaType of mediaTypes) {
|
|
122
|
+
const index = mediaType.indexOf('=');
|
|
123
|
+
if (index !== -1)
|
|
124
|
+
result[mediaType.substring(0, index)] = decodeURIComponent(mediaType.substring(index + 1));
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
static makeDataUri(file) {
|
|
129
|
+
if (!file)
|
|
130
|
+
return null;
|
|
131
|
+
const { mimeType, buffer, ...rest } = file;
|
|
132
|
+
const mediaTypes = Object.entries(rest)
|
|
133
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
134
|
+
.join(';');
|
|
135
|
+
return mediaTypes.length
|
|
136
|
+
? `data:${file.mimeType};${mediaTypes};base64,${buffer.toString('base64')}`
|
|
137
|
+
: `data:${file.mimeType};base64,${buffer.toString('base64')}`;
|
|
138
|
+
}
|
|
139
|
+
static isDataUri(value) {
|
|
140
|
+
return typeof value === 'string' && value.startsWith('data:');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.default = ForestValueConverter;
|
|
144
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXZhbHVlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC91dGlscy9mb3Jlc3Qtc2NoZW1hL2FjdGlvbi12YWx1ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwrQ0FBNEI7QUFDNUIsNEVBQXlEO0FBSXpEOzs7R0FHRztBQUNILE1BQXFCLG9CQUFvQjtJQUN2Qzs7O09BR0c7SUFDSCxNQUFNLENBQUMsWUFBWSxDQUFDLFVBQXNCLEVBQUUsT0FBaUIsRUFBRSxNQUFxQjtRQUNsRixNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7UUFFaEIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDbEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUM7WUFFaEQsb0NBQW9DO1lBQ3BDLElBQUksQ0FBQywyQkFBc0IsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDekUsSUFBSSxLQUFLLEVBQUUsSUFBSSxLQUFLLFlBQVksSUFBSSxLQUFLLEVBQUU7b0JBQ3pDLE1BQU0sVUFBVSxHQUFHLFVBQVUsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDO29CQUVsRSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEtBQWUsQ0FBQyxDQUFDO2lCQUNsRTtxQkFBTSxJQUFJLEtBQUssRUFBRSxJQUFJLEtBQUssTUFBTSxFQUFFO29CQUNqQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdB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
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { AgentOptions } from '../../../types';
|
|
3
|
+
declare type SerializedSchema = {
|
|
4
|
+
meta: {
|
|
5
|
+
schemaFileHash: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
declare type Options = Pick<AgentOptions, 'isProduction' | 'prefix' | 'schemaPath'>;
|
|
9
|
+
/**
|
|
10
|
+
* Generate and dispatch dataSource schema on agent start.
|
|
11
|
+
*/
|
|
12
|
+
export default class SchemaEmitter {
|
|
13
|
+
private static readonly meta;
|
|
14
|
+
static getSerializedSchema(options: Options, dataSource: DataSource): Promise<SerializedSchema>;
|
|
15
|
+
private static loadFromDisk;
|
|
16
|
+
private static generate;
|
|
17
|
+
private static serialize;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const json_api_serializer_1 = __importDefault(require("json-api-serializer"));
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const json_stringify_pretty_compact_1 = __importDefault(require("json-stringify-pretty-compact"));
|
|
10
|
+
const generator_collection_1 = __importDefault(require("./generator-collection"));
|
|
11
|
+
// Load version from package.json at startup
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
13
|
+
const { version } = require('../../../../package.json');
|
|
14
|
+
/**
|
|
15
|
+
* Generate and dispatch dataSource schema on agent start.
|
|
16
|
+
*/
|
|
17
|
+
class SchemaEmitter {
|
|
18
|
+
static async getSerializedSchema(options, dataSource) {
|
|
19
|
+
const schema = options.isProduction
|
|
20
|
+
? await SchemaEmitter.loadFromDisk(options.schemaPath)
|
|
21
|
+
: await SchemaEmitter.generate(options.prefix, dataSource);
|
|
22
|
+
if (!options.isProduction) {
|
|
23
|
+
const pretty = (0, json_stringify_pretty_compact_1.default)(schema, { maxLength: 80 });
|
|
24
|
+
await (0, promises_1.writeFile)(options.schemaPath, pretty, { encoding: 'utf-8' });
|
|
25
|
+
}
|
|
26
|
+
const hash = crypto_1.default.createHash('sha1').update(JSON.stringify(schema)).digest('hex');
|
|
27
|
+
return SchemaEmitter.serialize(schema, hash);
|
|
28
|
+
}
|
|
29
|
+
static async loadFromDisk(schemaPath) {
|
|
30
|
+
try {
|
|
31
|
+
const fileContent = await (0, promises_1.readFile)(schemaPath, { encoding: 'utf-8' });
|
|
32
|
+
return JSON.parse(fileContent);
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
throw new Error(`Cannot load ${schemaPath}. Providing a schema is mandatory in production mode.`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
static async generate(prefix, dataSource) {
|
|
39
|
+
const allCollectionSchemas = [];
|
|
40
|
+
const dataSourceCollectionSchemas = dataSource.collections.map(collection => generator_collection_1.default.buildSchema(prefix, collection));
|
|
41
|
+
allCollectionSchemas.push(...dataSourceCollectionSchemas);
|
|
42
|
+
return Promise.all(allCollectionSchemas);
|
|
43
|
+
}
|
|
44
|
+
static serialize(schema, hash) {
|
|
45
|
+
// Build serializer
|
|
46
|
+
const serializer = new json_api_serializer_1.default();
|
|
47
|
+
serializer.register('collections', {
|
|
48
|
+
// Pass the metadata provided to the serialization fn
|
|
49
|
+
topLevelMeta: (extraData) => extraData,
|
|
50
|
+
relationships: {
|
|
51
|
+
segments: { type: 'segments' },
|
|
52
|
+
actions: { type: 'actions' },
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
serializer.register('segments', {});
|
|
56
|
+
serializer.register('actions', {});
|
|
57
|
+
// Serialize
|
|
58
|
+
return serializer.serialize('collections', schema.map(c => ({ id: c.name, ...c })), { ...SchemaEmitter.meta, schemaFileHash: hash });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.default = SchemaEmitter;
|
|
62
|
+
SchemaEmitter.meta = {
|
|
63
|
+
liana: 'forest-nodejs-agent',
|
|
64
|
+
liana_version: version,
|
|
65
|
+
stack: {
|
|
66
|
+
engine: 'nodejs',
|
|
67
|
+
engine_version: process.versions && process.versions.node,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1pdHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC91dGlscy9mb3Jlc3Qtc2NoZW1hL2VtaXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwwQ0FBa0Q7QUFDbEQsOEVBQW9EO0FBQ3BELG9EQUE0QjtBQUM1QixrR0FBc0Q7QUFJdEQsa0ZBQStEO0FBTS9ELDRDQUE0QztBQUM1Qyw4REFBOEQ7QUFDOUQsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBRXhEOztHQUVHO0FBQ0gsTUFBcUIsYUFBYTtJQVVoQyxNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUM5QixPQUFnQixFQUNoQixVQUFzQjtRQUV0QixNQUFNLE1BQU0sR0FBYyxPQUFPLENBQUMsWUFBWTtZQUM1QyxDQUFDLENBQUMsTUFBTSxhQUFhLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7WUFDdEQsQ0FBQyxDQUFDLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRTdELElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFO1lBQ3pCLE1BQU0sTUFBTSxHQUFHLElBQUEsdUNBQVMsRUFBQyxNQUFNLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNwRCxNQUFNLElBQUEsb0JBQVMsRUFBQyxPQUFPLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1NBQ3BFO1FBRUQsTUFBTSxJQUFJLEdBQUcsZ0JBQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFF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
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ColumnType, Operator } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
export default class FrontendFilterableUtils {
|
|
3
|
+
private static readonly baseOperators;
|
|
4
|
+
private static readonly dateOperators;
|
|
5
|
+
private static readonly operatorByType;
|
|
6
|
+
/**
|
|
7
|
+
* Compute if a column if filterable according to forestadmin's frontend.
|
|
8
|
+
*
|
|
9
|
+
* @param type column's type (string, number, or a composite type)
|
|
10
|
+
* @param operators list of operators that the column supports
|
|
11
|
+
* @returns either if the frontend would consider this column filterable or not.
|
|
12
|
+
*/
|
|
13
|
+
static isFilterable(type: ColumnType, operators?: Set<Operator>): boolean;
|
|
14
|
+
static getRequiredOperators(type: ColumnType): Operator[] | null;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=filterable.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class FrontendFilterableUtils {
|
|
4
|
+
/**
|
|
5
|
+
* Compute if a column if filterable according to forestadmin's frontend.
|
|
6
|
+
*
|
|
7
|
+
* @param type column's type (string, number, or a composite type)
|
|
8
|
+
* @param operators list of operators that the column supports
|
|
9
|
+
* @returns either if the frontend would consider this column filterable or not.
|
|
10
|
+
*/
|
|
11
|
+
static isFilterable(type, operators) {
|
|
12
|
+
const neededOperators = FrontendFilterableUtils.getRequiredOperators(type);
|
|
13
|
+
const supportedOperators = operators ?? new Set();
|
|
14
|
+
return Boolean(neededOperators && neededOperators.every(op => supportedOperators.has(op)));
|
|
15
|
+
}
|
|
16
|
+
static getRequiredOperators(type) {
|
|
17
|
+
if (typeof type === 'string' && FrontendFilterableUtils.operatorByType[type]) {
|
|
18
|
+
return FrontendFilterableUtils.operatorByType[type];
|
|
19
|
+
}
|
|
20
|
+
// It sound highly unlikely that this operator can work with dates, or nested objects
|
|
21
|
+
// and they should be more restricted, however the frontend code does not seems to check the
|
|
22
|
+
// array's content so I'm replicating the same test here
|
|
23
|
+
if (Array.isArray(type)) {
|
|
24
|
+
return ['IncludesAll'];
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = FrontendFilterableUtils;
|
|
30
|
+
FrontendFilterableUtils.baseOperators = ['Equal', 'NotEqual', 'Present', 'Blank'];
|
|
31
|
+
FrontendFilterableUtils.dateOperators = [
|
|
32
|
+
...FrontendFilterableUtils.baseOperators,
|
|
33
|
+
'LessThan',
|
|
34
|
+
'GreaterThan',
|
|
35
|
+
'Today',
|
|
36
|
+
'Yesterday',
|
|
37
|
+
'PreviousXDays',
|
|
38
|
+
'PreviousWeek',
|
|
39
|
+
'PreviousQuarter',
|
|
40
|
+
'PreviousYear',
|
|
41
|
+
'PreviousXDaysToDate',
|
|
42
|
+
'PreviousWeekToDate',
|
|
43
|
+
'PreviousMonthToDate',
|
|
44
|
+
'PreviousQuarterToDate',
|
|
45
|
+
'PreviousYearToDate',
|
|
46
|
+
'Past',
|
|
47
|
+
'Future',
|
|
48
|
+
'BeforeXHoursAgo',
|
|
49
|
+
'AfterXHoursAgo',
|
|
50
|
+
];
|
|
51
|
+
FrontendFilterableUtils.operatorByType = {
|
|
52
|
+
Boolean: FrontendFilterableUtils.baseOperators,
|
|
53
|
+
Date: FrontendFilterableUtils.dateOperators,
|
|
54
|
+
Dateonly: FrontendFilterableUtils.dateOperators,
|
|
55
|
+
Enum: [...FrontendFilterableUtils.baseOperators, 'In'],
|
|
56
|
+
Number: [...FrontendFilterableUtils.baseOperators, 'In', 'GreaterThan', 'LessThan'],
|
|
57
|
+
String: [
|
|
58
|
+
...FrontendFilterableUtils.baseOperators,
|
|
59
|
+
'In',
|
|
60
|
+
'StartsWith',
|
|
61
|
+
'EndsWith',
|
|
62
|
+
'Contains',
|
|
63
|
+
'NotContains',
|
|
64
|
+
],
|
|
65
|
+
Timeonly: [...FrontendFilterableUtils.baseOperators, 'GreaterThan', 'LessThan'],
|
|
66
|
+
Uuid: FrontendFilterableUtils.baseOperators,
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyYWJsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC91dGlscy9mb3Jlc3Qtc2NoZW1hL2ZpbHRlcmFibGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxNQUFxQix1QkFBdUI7SUEwQzFDOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxZQUFZLENBQUMsSUFBZ0IsRUFBRSxTQUF5QjtRQUM3RCxNQUFNLGVBQWUsR0FBRyx1QkFBdUIsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRSxNQUFNLGtCQUFrQixHQUFHLFNBQVMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRWxELE9BQU8sT0FBTyxDQUFDLGVBQWUsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBRUQsTUFBTSxDQUFDLG9CQUFvQixDQUFDLElBQWdCO1FBQzFDLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUM1RSxPQUFPLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNyRDtRQUVELHFGQUFxRjtRQUNyRiw0RkFBNEY7UUFDNUYsd0RBQXdEO1FBQ3hELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN2QixPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDeEI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7O0FBckVILDBDQXNFQztBQXJFeUIscUNBQWEsR0FBZSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBRXRFLHFDQUFhLEdBQWU7SUFDbEQsR0FBRyx1QkFBdUIsQ0FBQyxhQUFhO0lBQ3hDLFVBQVU7SUFDVixhQUFhO0lBQ2IsT0FBTztJQUNQLFdBQVc7SUFDWCxlQUFlO0lBQ2YsY0FBYztJQUNkLGlCQUFpQjtJQUNqQixjQUFjO0lBQ2QscUJBQXFCO0lBQ3JCLG9CQUFvQjtJQUNwQixxQkFBcUI7SUFDckIsdUJBQXVCO0lBQ3ZCLG9CQUFvQjtJQUNwQixNQUFNO0lBQ04sUUFBUTtJQUNSLGlCQUFpQjtJQUNqQixnQkFBZ0I7Q0FDakIsQ0FBQztBQUVzQixzQ0FBYyxHQUFnRDtJQUNwRixPQUFPLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUM5QyxJQUFJLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUMzQyxRQUFRLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUMvQyxJQUFJLEVBQUUsQ0FBQyxHQUFHLHVCQUF1QixDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUM7SUFDdEQsTUFBTSxFQUFFLENBQUMsR0FBRyx1QkFBdUIsQ0FBQyxhQUFhLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxVQUFVLENBQUM7SUFDbkYsTUFBTSxFQUFFO1FBQ04sR0FBRyx1QkFBdUIsQ0FBQyxhQUFhO1FBQ3hDLElBQUk7UUFDSixZQUFZO1FBQ1osVUFBVTtRQUNWLFVBQVU7UUFDVixhQUFhO0tBQ2Q7SUFDRCxRQUFRLEVBQUUsQ0FBQyxHQUFHLHVCQUF1QixDQUFDLGFBQWEsRUFBRSxhQUFhLEVBQUUsVUFBVSxDQUFDO0lBQy9FLElBQUksRUFBRSx1QkFBdUIsQ0FBQyxhQUFhO0NBQzVDLENBQUMifQ==
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ActionField, Collection, DataSource } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { ForestServerAction, ForestServerActionField } from './types';
|
|
3
|
+
export default class SchemaGeneratorActions {
|
|
4
|
+
/**
|
|
5
|
+
* 'fields' sent to forestadmin-server when we want to generate the form on demand.
|
|
6
|
+
* This works around a bug in frontend which won't call the server if no fields are defined.
|
|
7
|
+
*/
|
|
8
|
+
static defaultFields: ForestServerActionField[];
|
|
9
|
+
static buildSchema(prefix: string, collection: Collection, name: string): Promise<ForestServerAction>;
|
|
10
|
+
/** Build schema for given field */
|
|
11
|
+
static buildFieldSchema(dataSource: DataSource, field: ActionField): ForestServerActionField;
|
|
12
|
+
private static buildFields;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=generator-actions.d.ts.map
|