@graphcommerce/hygraph-cli 6.2.0-canary.8
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/CHANGELOG.md +7 -0
- package/Config.graphqls +37 -0
- package/README.md +7 -0
- package/dist/index.js +5 -0
- package/dist/migrateHygraph.js +68 -0
- package/dist/migrations/dynamicRow.js +207 -0
- package/dist/types.js +2 -0
- package/package.json +43 -0
- package/src/index.ts +1 -0
- package/src/migrateHygraph.ts +73 -0
- package/src/migrations/dynamicRow.ts +229 -0
- package/src/types.ts +4 -0
- package/tsconfig.json +14 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @graphcommerce/hygraph-cli
|
|
2
|
+
|
|
3
|
+
## 6.2.0-canary.8
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1912](https://github.com/graphcommerce-org/graphcommerce/pull/1912) [`a43d389e9`](https://github.com/graphcommerce-org/graphcommerce/commit/a43d389e956fe69b73238b12c98c781b7044e4bb) - Added dynamic rows feature and better performance for Hygraph ([@JoshuaS98](https://github.com/JoshuaS98))
|
package/Config.graphqls
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
extend input GraphCommerceConfig {
|
|
2
|
+
"""
|
|
3
|
+
Content API. **Only used for migrations.**
|
|
4
|
+
|
|
5
|
+
> Regular read & write endpoint that allows querying and mutating data in your project.
|
|
6
|
+
|
|
7
|
+
Project settings -> API Access -> Content API
|
|
8
|
+
"""
|
|
9
|
+
hygraphWriteAccessEndpoint: String
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
Hygraph Management SDK Authorization Token. **Only used for migrations.**
|
|
13
|
+
|
|
14
|
+
Project settings -> API Access -> Permanent Auth Tokens
|
|
15
|
+
|
|
16
|
+
1. Click 'Add token' and give it a name, something like 'GraphCommerce Write Access Token' and keep stage on 'Published'.
|
|
17
|
+
2. Under 'Management API', click 'Yes, Initialize defaults'
|
|
18
|
+
3. Click 'Edit Permissions' and enable: 'Update' and 'Delete' permissions for 'models', 'enumerations', 'fields', 'components' and 'sources'
|
|
19
|
+
- Update existing models
|
|
20
|
+
- Delete existing models
|
|
21
|
+
- Update existing fields
|
|
22
|
+
- Delete existing fields
|
|
23
|
+
- Update existing enumerations
|
|
24
|
+
- Delete existing enumerations
|
|
25
|
+
- Update existing components
|
|
26
|
+
- Delete existing components
|
|
27
|
+
- Update remote sources
|
|
28
|
+
- Delete remote sources
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
GC_HYGRAPH_WRITE_ACCESS_ENDPOINT="https://...hygraph.com/v2/..."
|
|
32
|
+
GC_HYGRAPH_WRITE_ACCESS_TOKEN="AccessTokenFromHygraph"
|
|
33
|
+
yarn graphcommerce hygraph-migrate
|
|
34
|
+
```
|
|
35
|
+
"""
|
|
36
|
+
hygraphWriteAccessToken: String
|
|
37
|
+
}
|
package/README.md
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrateHygraph = void 0;
|
|
4
|
+
var migrateHygraph_1 = require("./migrateHygraph");
|
|
5
|
+
Object.defineProperty(exports, "migrateHygraph", { enumerable: true, get: function () { return migrateHygraph_1.migrateHygraph; } });
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
exports.migrateHygraph = void 0;
|
|
7
|
+
/* eslint-disable no-console */
|
|
8
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
9
|
+
const readline_1 = __importDefault(require("readline"));
|
|
10
|
+
const dynamicRow_1 = require("./migrations/dynamicRow");
|
|
11
|
+
async function migrateHygraph() {
|
|
12
|
+
let forceRun = false;
|
|
13
|
+
// Interface to determine if force run should be enabled
|
|
14
|
+
readline_1.default.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout,
|
|
17
|
+
});
|
|
18
|
+
const affirmativeAnswers = ['y', 'yes', 'Y', 'YES'];
|
|
19
|
+
const handleKeypress = (key) => {
|
|
20
|
+
if (affirmativeAnswers.includes(key.toLowerCase())) {
|
|
21
|
+
console.log('\nForce run enabled');
|
|
22
|
+
forceRun = true;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log('\nForce run disabled');
|
|
26
|
+
forceRun = false;
|
|
27
|
+
}
|
|
28
|
+
process.stdin.pause();
|
|
29
|
+
};
|
|
30
|
+
// Listen for keypress events
|
|
31
|
+
process.stdin.on('keypress', handleKeypress);
|
|
32
|
+
process.stdin.setRawMode(true);
|
|
33
|
+
process.stdin.resume();
|
|
34
|
+
console.log('Enable force run? (y/n)');
|
|
35
|
+
// Wait for input
|
|
36
|
+
await new Promise((resolve) => {
|
|
37
|
+
process.stdin.once('data', () => {
|
|
38
|
+
// Stop listening for input
|
|
39
|
+
process.stdin.removeListener('keypress', handleKeypress);
|
|
40
|
+
process.stdin.setRawMode(false);
|
|
41
|
+
resolve();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
// TODO: Choose migration
|
|
45
|
+
// TODO: GC-Version based migration
|
|
46
|
+
const possibleMigrations = [
|
|
47
|
+
['add_dynamic_rows', dynamicRow_1.dynamicRow],
|
|
48
|
+
];
|
|
49
|
+
for (const [name, migration] of possibleMigrations) {
|
|
50
|
+
try {
|
|
51
|
+
// eslint-disable-next-line no-await-in-loop
|
|
52
|
+
const result = await migration(forceRun ? undefined : name);
|
|
53
|
+
console.log(result);
|
|
54
|
+
if (result.status !== 'SUCCESS') {
|
|
55
|
+
throw new Error(`Migration not successful: ${result.status} ${name}:\n${result.errors}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(`Migration successful: ${name}`);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err instanceof Error) {
|
|
61
|
+
const garbledErrorIndex = err.message.indexOf(': {"');
|
|
62
|
+
const msg = garbledErrorIndex > 0 ? err.message.slice(0, garbledErrorIndex) : err.message;
|
|
63
|
+
console.error(msg);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.migrateHygraph = migrateHygraph;
|
|
@@ -0,0 +1,207 @@
|
|
|
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
|
+
exports.dynamicRow = void 0;
|
|
7
|
+
const next_config_1 = require("@graphcommerce/next-config");
|
|
8
|
+
const management_sdk_1 = require("@hygraph/management-sdk");
|
|
9
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
|
+
dotenv_1.default.config();
|
|
11
|
+
const dynamicRow = async (name) => {
|
|
12
|
+
const config = (0, next_config_1.loadConfig)(process.cwd());
|
|
13
|
+
if (!config.hygraphWriteAccessEndpoint) {
|
|
14
|
+
throw new Error('Please provide hygraphWriteAccessEndpoint in your config or GC_HYGRAPH_WRITE_ACCESS_ENDPOINT in your env');
|
|
15
|
+
}
|
|
16
|
+
if (!config.hygraphWriteAccessToken) {
|
|
17
|
+
throw new Error('Please provide GC_HYGRAPH_WRITE_ACCESS_TOKEN in your env');
|
|
18
|
+
}
|
|
19
|
+
const client = new management_sdk_1.Client({
|
|
20
|
+
authToken: config.hygraphWriteAccessToken,
|
|
21
|
+
endpoint: config.hygraphWriteAccessEndpoint,
|
|
22
|
+
name,
|
|
23
|
+
});
|
|
24
|
+
// ? ENUMERATIONS
|
|
25
|
+
client.createEnumeration({
|
|
26
|
+
displayName: 'Dynamic Row Condition Number Operator',
|
|
27
|
+
apiId: 'DynamicRowConditionNumberOperator',
|
|
28
|
+
values: [
|
|
29
|
+
{ displayName: 'Greater than or equal to', apiId: 'GTE' },
|
|
30
|
+
{ displayName: 'Less than or equal to', apiId: 'LTE' },
|
|
31
|
+
{ displayName: 'Equal to', apiId: 'EQUAL' },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
client.createEnumeration({
|
|
35
|
+
displayName: 'Dynamic Row Placement',
|
|
36
|
+
apiId: 'DynamicRowPlacement',
|
|
37
|
+
values: [
|
|
38
|
+
{ displayName: 'Before', apiId: 'BEFORE' },
|
|
39
|
+
{ displayName: 'After', apiId: 'AFTER' },
|
|
40
|
+
{ displayName: 'Replace', apiId: 'REPLACE' },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
// ? COMPONENTS
|
|
44
|
+
client.createComponent({
|
|
45
|
+
displayName: 'Text',
|
|
46
|
+
apiId: 'ConditionText',
|
|
47
|
+
apiIdPlural: 'ConditionTexts',
|
|
48
|
+
});
|
|
49
|
+
client.createComponent({
|
|
50
|
+
displayName: 'Number',
|
|
51
|
+
apiId: 'ConditionNumber',
|
|
52
|
+
apiIdPlural: 'ConditionNumbers',
|
|
53
|
+
});
|
|
54
|
+
client.createComponent({
|
|
55
|
+
displayName: 'AND',
|
|
56
|
+
apiId: 'ConditionAnd',
|
|
57
|
+
apiIdPlural: 'ConditionAnds',
|
|
58
|
+
description: 'All of these conditions must match',
|
|
59
|
+
});
|
|
60
|
+
client.createComponent({
|
|
61
|
+
displayName: 'OR',
|
|
62
|
+
apiId: 'ConditionOr',
|
|
63
|
+
apiIdPlural: 'ConditionOrs',
|
|
64
|
+
description: 'One of these conditions must match',
|
|
65
|
+
});
|
|
66
|
+
client.createComponentUnionField({
|
|
67
|
+
displayName: 'Conditions',
|
|
68
|
+
apiId: 'conditions',
|
|
69
|
+
parentApiId: 'ConditionAnd',
|
|
70
|
+
componentApiIds: ['ConditionOr', 'ConditionText', 'ConditionNumber'],
|
|
71
|
+
isList: true,
|
|
72
|
+
});
|
|
73
|
+
client.createComponentUnionField({
|
|
74
|
+
displayName: 'Conditions',
|
|
75
|
+
apiId: 'conditions',
|
|
76
|
+
parentApiId: 'ConditionOr',
|
|
77
|
+
componentApiIds: ['ConditionText', 'ConditionNumber'],
|
|
78
|
+
isList: true,
|
|
79
|
+
});
|
|
80
|
+
client.createSimpleField({
|
|
81
|
+
displayName: 'Property',
|
|
82
|
+
apiId: 'property',
|
|
83
|
+
type: management_sdk_1.SimpleFieldType.String,
|
|
84
|
+
parentApiId: 'ConditionText',
|
|
85
|
+
description: 'Path to the value of the object being evaluated.\n\nFor products: url_key, category, sku',
|
|
86
|
+
isRequired: true,
|
|
87
|
+
validations: {
|
|
88
|
+
String: {
|
|
89
|
+
matches: {
|
|
90
|
+
flags: ['i', 's'],
|
|
91
|
+
regex: '^[a-z0-9-_.]+$',
|
|
92
|
+
errorMessage: 'Only letters, numbers, dashes (-), underscores (_) or dots allowed (.)',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
client.createSimpleField({
|
|
98
|
+
displayName: 'Value',
|
|
99
|
+
apiId: 'value',
|
|
100
|
+
type: management_sdk_1.SimpleFieldType.String,
|
|
101
|
+
parentApiId: 'ConditionText',
|
|
102
|
+
isRequired: true,
|
|
103
|
+
});
|
|
104
|
+
client.createSimpleField({
|
|
105
|
+
displayName: 'Property',
|
|
106
|
+
apiId: 'property',
|
|
107
|
+
type: management_sdk_1.SimpleFieldType.String,
|
|
108
|
+
parentApiId: 'ConditionNumber',
|
|
109
|
+
isRequired: true,
|
|
110
|
+
validations: {
|
|
111
|
+
String: {
|
|
112
|
+
matches: {
|
|
113
|
+
flags: ['i', 's'],
|
|
114
|
+
regex: '^[a-z0-9-_.]+$',
|
|
115
|
+
errorMessage: 'Only letters, numbers, dashes (-), underscores (_) or dots allowed (.)',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
client.createEnumerableField({
|
|
121
|
+
displayName: 'Operator',
|
|
122
|
+
apiId: 'operator',
|
|
123
|
+
parentApiId: 'ConditionNumber',
|
|
124
|
+
enumerationApiId: 'DynamicRowConditionNumberOperator',
|
|
125
|
+
isRequired: true,
|
|
126
|
+
});
|
|
127
|
+
client.createSimpleField({
|
|
128
|
+
displayName: 'Value',
|
|
129
|
+
apiId: 'value',
|
|
130
|
+
type: management_sdk_1.SimpleFieldType.Float,
|
|
131
|
+
parentApiId: 'ConditionNumber',
|
|
132
|
+
isRequired: true,
|
|
133
|
+
});
|
|
134
|
+
// ? MODEL
|
|
135
|
+
client.createModel({
|
|
136
|
+
apiId: 'DynamicRow',
|
|
137
|
+
apiIdPlural: 'DynamicRows',
|
|
138
|
+
displayName: 'Dynamic Row',
|
|
139
|
+
description: 'Dynamic rows allow you to add specific Row models to pages based on the properties of the page',
|
|
140
|
+
});
|
|
141
|
+
client.createSimpleField({
|
|
142
|
+
displayName: 'Internal name',
|
|
143
|
+
apiId: 'internalName',
|
|
144
|
+
description: 'Only used for internal reference',
|
|
145
|
+
type: management_sdk_1.SimpleFieldType.String,
|
|
146
|
+
isTitle: true,
|
|
147
|
+
isRequired: true,
|
|
148
|
+
isUnique: true,
|
|
149
|
+
modelApiId: 'DynamicRow',
|
|
150
|
+
});
|
|
151
|
+
client.createUnionField({
|
|
152
|
+
displayName: 'Row',
|
|
153
|
+
apiId: 'row',
|
|
154
|
+
reverseField: {
|
|
155
|
+
modelApiIds: ['RowQuote', 'RowLinks', 'RowColumnOne'],
|
|
156
|
+
apiId: 'dynamicRow',
|
|
157
|
+
displayName: 'DynamicRows',
|
|
158
|
+
visibility: management_sdk_1.VisibilityTypes.Hidden,
|
|
159
|
+
isList: true,
|
|
160
|
+
},
|
|
161
|
+
parentApiId: 'DynamicRow',
|
|
162
|
+
});
|
|
163
|
+
client.createEnumerableField({
|
|
164
|
+
displayName: 'Placement',
|
|
165
|
+
apiId: 'placement',
|
|
166
|
+
parentApiId: 'DynamicRow',
|
|
167
|
+
enumerationApiId: 'DynamicRowPlacement',
|
|
168
|
+
description: 'Where will the row be placed relative to the target',
|
|
169
|
+
isRequired: true,
|
|
170
|
+
});
|
|
171
|
+
client.createUnionField({
|
|
172
|
+
displayName: 'Placement target',
|
|
173
|
+
apiId: 'target',
|
|
174
|
+
description: 'Optional: When the target is left blank it will place the Dynamic Row on the start or end.',
|
|
175
|
+
reverseField: {
|
|
176
|
+
modelApiIds: [
|
|
177
|
+
'RowQuote',
|
|
178
|
+
'RowLinks',
|
|
179
|
+
'RowColumnOne',
|
|
180
|
+
'RowColumnTwo',
|
|
181
|
+
'RowColumnThree',
|
|
182
|
+
'RowServiceOptions',
|
|
183
|
+
'RowContentLinks',
|
|
184
|
+
'RowButtonLinkList',
|
|
185
|
+
'RowProduct',
|
|
186
|
+
'RowSpecialBanner',
|
|
187
|
+
'RowHeroBanner',
|
|
188
|
+
'RowBlogContent',
|
|
189
|
+
],
|
|
190
|
+
apiId: 'dynamicRowsTarget',
|
|
191
|
+
displayName: 'DynamicRowsTarget',
|
|
192
|
+
visibility: management_sdk_1.VisibilityTypes.Hidden,
|
|
193
|
+
isList: true,
|
|
194
|
+
},
|
|
195
|
+
parentApiId: 'DynamicRow',
|
|
196
|
+
});
|
|
197
|
+
client.createComponentUnionField({
|
|
198
|
+
displayName: 'Conditions (OR)',
|
|
199
|
+
apiId: 'conditions',
|
|
200
|
+
parentApiId: 'DynamicRow',
|
|
201
|
+
description: 'One of these conditions must match',
|
|
202
|
+
componentApiIds: ['ConditionAnd', 'ConditionText', 'ConditionNumber'],
|
|
203
|
+
isList: true,
|
|
204
|
+
});
|
|
205
|
+
return client.run(true);
|
|
206
|
+
};
|
|
207
|
+
exports.dynamicRow = dynamicRow;
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@graphcommerce/hygraph-cli",
|
|
3
|
+
"homepage": "https://www.graphcommerce.org/",
|
|
4
|
+
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
+
"version": "6.2.0-canary.8",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "tsc --preserveWatchOutput --watch",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"prepack": "tsc"
|
|
12
|
+
},
|
|
13
|
+
"type": "commonjs",
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "src/index.ts",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@graphcommerce/next-config": "6.2.0-canary.8",
|
|
18
|
+
"@graphql-codegen/cli": "3.2.2",
|
|
19
|
+
"@graphql-mesh/cli": "0.82.25",
|
|
20
|
+
"@graphql-mesh/types": "0.91.7",
|
|
21
|
+
"@graphql-mesh/utils": "0.43.15",
|
|
22
|
+
"@hygraph/management-sdk": "^1.1.2-alpha.1",
|
|
23
|
+
"graphql": "16.6.0",
|
|
24
|
+
"graphql-tag": "^2.12.6"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@graphcommerce/eslint-config-pwa": "6.2.0-canary.8",
|
|
28
|
+
"@graphcommerce/prettier-config-pwa": "6.2.0-canary.8",
|
|
29
|
+
"@graphcommerce/typescript-config-pwa": "6.2.0-canary.8",
|
|
30
|
+
"typescript": "4.9.5"
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
34
|
+
"eslint": {
|
|
35
|
+
"extends": "@graphcommerce/eslint-config-pwa"
|
|
36
|
+
},
|
|
37
|
+
"eslintConfig": {
|
|
38
|
+
"extends": "@graphcommerce/eslint-config-pwa",
|
|
39
|
+
"parserOptions": {
|
|
40
|
+
"project": "./tsconfig.json"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { migrateHygraph } from './migrateHygraph'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
3
|
+
import readline from 'readline'
|
|
4
|
+
import { MigrationInfo } from '@hygraph/management-sdk/dist/ManagementAPIClient'
|
|
5
|
+
import { dynamicRow } from './migrations/dynamicRow'
|
|
6
|
+
|
|
7
|
+
export async function migrateHygraph() {
|
|
8
|
+
let forceRun = false
|
|
9
|
+
|
|
10
|
+
// Interface to determine if force run should be enabled
|
|
11
|
+
readline.createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output: process.stdout,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const affirmativeAnswers = ['y', 'yes', 'Y', 'YES']
|
|
17
|
+
|
|
18
|
+
const handleKeypress = (key: string) => {
|
|
19
|
+
if (affirmativeAnswers.includes(key.toLowerCase())) {
|
|
20
|
+
console.log('\nForce run enabled')
|
|
21
|
+
forceRun = true
|
|
22
|
+
} else {
|
|
23
|
+
console.log('\nForce run disabled')
|
|
24
|
+
forceRun = false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
process.stdin.pause()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Listen for keypress events
|
|
31
|
+
process.stdin.on('keypress', handleKeypress)
|
|
32
|
+
process.stdin.setRawMode(true)
|
|
33
|
+
process.stdin.resume()
|
|
34
|
+
|
|
35
|
+
console.log('Enable force run? (y/n)')
|
|
36
|
+
|
|
37
|
+
// Wait for input
|
|
38
|
+
await new Promise<void>((resolve) => {
|
|
39
|
+
process.stdin.once('data', () => {
|
|
40
|
+
// Stop listening for input
|
|
41
|
+
process.stdin.removeListener('keypress', handleKeypress)
|
|
42
|
+
process.stdin.setRawMode(false)
|
|
43
|
+
|
|
44
|
+
resolve()
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// TODO: Choose migration
|
|
49
|
+
// TODO: GC-Version based migration
|
|
50
|
+
const possibleMigrations: [string, (name: string | undefined) => Promise<MigrationInfo>][] = [
|
|
51
|
+
['add_dynamic_rows', dynamicRow],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
for (const [name, migration] of possibleMigrations) {
|
|
55
|
+
try {
|
|
56
|
+
// eslint-disable-next-line no-await-in-loop
|
|
57
|
+
const result = await migration(forceRun ? undefined : name)
|
|
58
|
+
console.log(result)
|
|
59
|
+
|
|
60
|
+
if (result.status !== 'SUCCESS') {
|
|
61
|
+
throw new Error(`Migration not successful: ${result.status} ${name}:\n${result.errors}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(`Migration successful: ${name}`)
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (err instanceof Error) {
|
|
67
|
+
const garbledErrorIndex = err.message.indexOf(': {"')
|
|
68
|
+
const msg = garbledErrorIndex > 0 ? err.message.slice(0, garbledErrorIndex) : err.message
|
|
69
|
+
console.error(msg)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { loadConfig } from '@graphcommerce/next-config'
|
|
2
|
+
import { Client, SimpleFieldType, VisibilityTypes } from '@hygraph/management-sdk'
|
|
3
|
+
import dotenv from 'dotenv'
|
|
4
|
+
|
|
5
|
+
dotenv.config()
|
|
6
|
+
|
|
7
|
+
export const dynamicRow = async (name: string | undefined) => {
|
|
8
|
+
const config = loadConfig(process.cwd())
|
|
9
|
+
|
|
10
|
+
if (!config.hygraphWriteAccessEndpoint) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
'Please provide hygraphWriteAccessEndpoint in your config or GC_HYGRAPH_WRITE_ACCESS_ENDPOINT in your env',
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
if (!config.hygraphWriteAccessToken) {
|
|
16
|
+
throw new Error('Please provide GC_HYGRAPH_WRITE_ACCESS_TOKEN in your env')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const client = new Client({
|
|
20
|
+
authToken: config.hygraphWriteAccessToken,
|
|
21
|
+
endpoint: config.hygraphWriteAccessEndpoint,
|
|
22
|
+
name,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// ? ENUMERATIONS
|
|
26
|
+
client.createEnumeration({
|
|
27
|
+
displayName: 'Dynamic Row Condition Number Operator',
|
|
28
|
+
apiId: 'DynamicRowConditionNumberOperator',
|
|
29
|
+
values: [
|
|
30
|
+
{ displayName: 'Greater than or equal to', apiId: 'GTE' },
|
|
31
|
+
{ displayName: 'Less than or equal to', apiId: 'LTE' },
|
|
32
|
+
{ displayName: 'Equal to', apiId: 'EQUAL' },
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
client.createEnumeration({
|
|
37
|
+
displayName: 'Dynamic Row Placement',
|
|
38
|
+
apiId: 'DynamicRowPlacement',
|
|
39
|
+
values: [
|
|
40
|
+
{ displayName: 'Before', apiId: 'BEFORE' },
|
|
41
|
+
{ displayName: 'After', apiId: 'AFTER' },
|
|
42
|
+
{ displayName: 'Replace', apiId: 'REPLACE' },
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// ? COMPONENTS
|
|
47
|
+
client.createComponent({
|
|
48
|
+
displayName: 'Text',
|
|
49
|
+
apiId: 'ConditionText',
|
|
50
|
+
apiIdPlural: 'ConditionTexts',
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
client.createComponent({
|
|
54
|
+
displayName: 'Number',
|
|
55
|
+
apiId: 'ConditionNumber',
|
|
56
|
+
apiIdPlural: 'ConditionNumbers',
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
client.createComponent({
|
|
60
|
+
displayName: 'AND',
|
|
61
|
+
apiId: 'ConditionAnd',
|
|
62
|
+
apiIdPlural: 'ConditionAnds',
|
|
63
|
+
description: 'All of these conditions must match',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
client.createComponent({
|
|
67
|
+
displayName: 'OR',
|
|
68
|
+
apiId: 'ConditionOr',
|
|
69
|
+
apiIdPlural: 'ConditionOrs',
|
|
70
|
+
description: 'One of these conditions must match',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
client.createComponentUnionField({
|
|
74
|
+
displayName: 'Conditions',
|
|
75
|
+
apiId: 'conditions',
|
|
76
|
+
parentApiId: 'ConditionAnd',
|
|
77
|
+
componentApiIds: ['ConditionOr', 'ConditionText', 'ConditionNumber'],
|
|
78
|
+
isList: true,
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
client.createComponentUnionField({
|
|
82
|
+
displayName: 'Conditions',
|
|
83
|
+
apiId: 'conditions',
|
|
84
|
+
parentApiId: 'ConditionOr',
|
|
85
|
+
componentApiIds: ['ConditionText', 'ConditionNumber'],
|
|
86
|
+
isList: true,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
client.createSimpleField({
|
|
90
|
+
displayName: 'Property',
|
|
91
|
+
apiId: 'property',
|
|
92
|
+
type: SimpleFieldType.String,
|
|
93
|
+
parentApiId: 'ConditionText',
|
|
94
|
+
description:
|
|
95
|
+
'Path to the value of the object being evaluated.\n\nFor products: url_key, category, sku',
|
|
96
|
+
isRequired: true,
|
|
97
|
+
validations: {
|
|
98
|
+
String: {
|
|
99
|
+
matches: {
|
|
100
|
+
flags: ['i', 's'],
|
|
101
|
+
regex: '^[a-z0-9-_.]+$',
|
|
102
|
+
errorMessage: 'Only letters, numbers, dashes (-), underscores (_) or dots allowed (.)',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
client.createSimpleField({
|
|
109
|
+
displayName: 'Value',
|
|
110
|
+
apiId: 'value',
|
|
111
|
+
type: SimpleFieldType.String,
|
|
112
|
+
parentApiId: 'ConditionText',
|
|
113
|
+
isRequired: true,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
client.createSimpleField({
|
|
117
|
+
displayName: 'Property',
|
|
118
|
+
apiId: 'property',
|
|
119
|
+
type: SimpleFieldType.String,
|
|
120
|
+
parentApiId: 'ConditionNumber',
|
|
121
|
+
isRequired: true,
|
|
122
|
+
validations: {
|
|
123
|
+
String: {
|
|
124
|
+
matches: {
|
|
125
|
+
flags: ['i', 's'],
|
|
126
|
+
regex: '^[a-z0-9-_.]+$',
|
|
127
|
+
errorMessage: 'Only letters, numbers, dashes (-), underscores (_) or dots allowed (.)',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
client.createEnumerableField({
|
|
134
|
+
displayName: 'Operator',
|
|
135
|
+
apiId: 'operator',
|
|
136
|
+
parentApiId: 'ConditionNumber',
|
|
137
|
+
enumerationApiId: 'DynamicRowConditionNumberOperator',
|
|
138
|
+
isRequired: true,
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
client.createSimpleField({
|
|
142
|
+
displayName: 'Value',
|
|
143
|
+
apiId: 'value',
|
|
144
|
+
type: SimpleFieldType.Float,
|
|
145
|
+
parentApiId: 'ConditionNumber',
|
|
146
|
+
isRequired: true,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// ? MODEL
|
|
150
|
+
client.createModel({
|
|
151
|
+
apiId: 'DynamicRow',
|
|
152
|
+
apiIdPlural: 'DynamicRows',
|
|
153
|
+
displayName: 'Dynamic Row',
|
|
154
|
+
description:
|
|
155
|
+
'Dynamic rows allow you to add specific Row models to pages based on the properties of the page',
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
client.createSimpleField({
|
|
159
|
+
displayName: 'Internal name',
|
|
160
|
+
apiId: 'internalName',
|
|
161
|
+
description: 'Only used for internal reference',
|
|
162
|
+
type: SimpleFieldType.String,
|
|
163
|
+
isTitle: true,
|
|
164
|
+
isRequired: true,
|
|
165
|
+
isUnique: true,
|
|
166
|
+
modelApiId: 'DynamicRow',
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
client.createUnionField({
|
|
170
|
+
displayName: 'Row',
|
|
171
|
+
apiId: 'row',
|
|
172
|
+
reverseField: {
|
|
173
|
+
modelApiIds: ['RowQuote', 'RowLinks', 'RowColumnOne'],
|
|
174
|
+
apiId: 'dynamicRow',
|
|
175
|
+
displayName: 'DynamicRows',
|
|
176
|
+
visibility: VisibilityTypes.Hidden,
|
|
177
|
+
isList: true,
|
|
178
|
+
},
|
|
179
|
+
parentApiId: 'DynamicRow',
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
client.createEnumerableField({
|
|
183
|
+
displayName: 'Placement',
|
|
184
|
+
apiId: 'placement',
|
|
185
|
+
parentApiId: 'DynamicRow',
|
|
186
|
+
enumerationApiId: 'DynamicRowPlacement',
|
|
187
|
+
description: 'Where will the row be placed relative to the target',
|
|
188
|
+
isRequired: true,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
client.createUnionField({
|
|
192
|
+
displayName: 'Placement target',
|
|
193
|
+
apiId: 'target',
|
|
194
|
+
description:
|
|
195
|
+
'Optional: When the target is left blank it will place the Dynamic Row on the start or end.',
|
|
196
|
+
reverseField: {
|
|
197
|
+
modelApiIds: [
|
|
198
|
+
'RowQuote',
|
|
199
|
+
'RowLinks',
|
|
200
|
+
'RowColumnOne',
|
|
201
|
+
'RowColumnTwo',
|
|
202
|
+
'RowColumnThree',
|
|
203
|
+
'RowServiceOptions',
|
|
204
|
+
'RowContentLinks',
|
|
205
|
+
'RowButtonLinkList',
|
|
206
|
+
'RowProduct',
|
|
207
|
+
'RowSpecialBanner',
|
|
208
|
+
'RowHeroBanner',
|
|
209
|
+
'RowBlogContent',
|
|
210
|
+
],
|
|
211
|
+
apiId: 'dynamicRowsTarget',
|
|
212
|
+
displayName: 'DynamicRowsTarget',
|
|
213
|
+
visibility: VisibilityTypes.Hidden,
|
|
214
|
+
isList: true,
|
|
215
|
+
},
|
|
216
|
+
parentApiId: 'DynamicRow',
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
client.createComponentUnionField({
|
|
220
|
+
displayName: 'Conditions (OR)',
|
|
221
|
+
apiId: 'conditions',
|
|
222
|
+
parentApiId: 'DynamicRow',
|
|
223
|
+
description: 'One of these conditions must match',
|
|
224
|
+
componentApiIds: ['ConditionAnd', 'ConditionText', 'ConditionNumber'],
|
|
225
|
+
isList: true,
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
return client.run(true)
|
|
229
|
+
}
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exclude": ["**/node_modules", "example", "dist", "**/.*/", "__tests__", "__mocks__"],
|
|
3
|
+
"include": ["**/*.ts", "**/*.tsx"],
|
|
4
|
+
"files": ["src/index.ts"],
|
|
5
|
+
"extends": "@graphcommerce/typescript-config-pwa/node.json",
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"noEmit": false,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"sourceMap": false,
|
|
11
|
+
"noLib": false,
|
|
12
|
+
"strict": true
|
|
13
|
+
}
|
|
14
|
+
}
|