@aws-amplify/amplify-util-uibuilder 1.5.0-binary-file-size.0 → 1.5.0-studio-forms.0
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 +2 -1
- package/amplify-plugin.json +10 -3
- package/lib/clients/amplify-studio-client.d.ts +13 -2
- package/lib/clients/amplify-studio-client.d.ts.map +1 -1
- package/lib/clients/amplify-studio-client.js +72 -4
- package/lib/clients/amplify-studio-client.js.map +1 -1
- package/lib/commands/generateComponents.d.ts.map +1 -1
- package/lib/commands/generateComponents.js +36 -15
- package/lib/commands/generateComponents.js.map +1 -1
- package/lib/commands/help.d.ts +1 -1
- package/lib/commands/help.d.ts.map +1 -1
- package/lib/commands/help.js +2 -2
- package/lib/commands/help.js.map +1 -1
- package/lib/commands/utils/codegenResources.d.ts +12 -2
- package/lib/commands/utils/codegenResources.d.ts.map +1 -1
- package/lib/commands/utils/codegenResources.js +70 -3
- package/lib/commands/utils/codegenResources.js.map +1 -1
- package/lib/commands/utils/featureFlags.d.ts +3 -0
- package/lib/commands/utils/featureFlags.d.ts.map +1 -0
- package/lib/commands/utils/featureFlags.js +34 -0
- package/lib/commands/utils/featureFlags.js.map +1 -0
- package/lib/commands/utils/getUiBuilderComponentsPath.d.ts.map +1 -1
- package/lib/commands/utils/getUiBuilderComponentsPath.js.map +1 -1
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.d.ts +12 -20
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.d.ts.map +1 -1
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.js +36 -3
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.js.map +1 -1
- package/lib/commands/version.d.ts +1 -1
- package/lib/commands/version.d.ts.map +1 -1
- package/lib/commands/version.js +2 -2
- package/lib/commands/version.js.map +1 -1
- package/lib/event-handlers/handle-PostEnvAdd.d.ts +1 -1
- package/lib/event-handlers/handle-PostEnvAdd.d.ts.map +1 -1
- package/lib/event-handlers/handle-PostEnvAdd.js +4 -6
- package/lib/event-handlers/handle-PostEnvAdd.js.map +1 -1
- package/lib/event-handlers/handle-PostPull.d.ts +1 -1
- package/lib/event-handlers/handle-PostPull.d.ts.map +1 -1
- package/lib/event-handlers/handle-PostPull.js +4 -3
- package/lib/event-handlers/handle-PostPull.js.map +1 -1
- package/lib/event-handlers/handle-PostPush.d.ts +3 -0
- package/lib/event-handlers/handle-PostPush.d.ts.map +1 -0
- package/lib/event-handlers/handle-PostPush.js +15 -0
- package/lib/event-handlers/handle-PostPush.js.map +1 -0
- package/package.json +8 -7
- package/src/__tests__/cloneComponentsFromEnv.test.ts +11 -0
- package/src/__tests__/createUiBuilderComponent.test.ts +19 -1
- package/src/__tests__/generateComponents.test.ts +35 -1
- package/src/__tests__/getAmplifyDataSchema.test.ts +43 -3
- package/src/__tests__/syncAmplifyUiComponents.test.ts +111 -8
- package/src/__tests__/utils.ts +70 -0
- package/src/clients/amplify-studio-client.ts +146 -63
- package/src/commands/generateComponents.ts +46 -16
- package/src/commands/help.ts +5 -2
- package/src/commands/utils/codegenResources.ts +108 -4
- package/src/commands/utils/featureFlags.ts +61 -0
- package/src/commands/utils/getUiBuilderComponentsPath.ts +7 -2
- package/src/commands/utils/syncAmplifyUiBuilderComponents.ts +74 -29
- package/src/commands/version.ts +5 -2
- package/src/event-handlers/handle-PostEnvAdd.ts +8 -6
- package/src/event-handlers/handle-PostPull.ts +7 -3
- package/src/event-handlers/handle-PostPush.ts +15 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/__tests__/handleEvents.test.ts +0 -21
|
@@ -6,9 +6,12 @@ import {
|
|
|
6
6
|
getEnvName,
|
|
7
7
|
getAppId,
|
|
8
8
|
resolveAppId,
|
|
9
|
+
generateUiBuilderForms,
|
|
9
10
|
} from '../commands/utils';
|
|
10
11
|
import { AmplifyStudioClient } from '../clients';
|
|
11
12
|
import * as createUiBuilderComponentDependency from '../commands/utils/codegenResources';
|
|
13
|
+
import { exampleSchema } from './utils';
|
|
14
|
+
import { GenericDataModel, GenericDataSchema } from '@aws-amplify/codegen-ui';
|
|
12
15
|
|
|
13
16
|
jest.mock('amplify-cli-core', () => ({
|
|
14
17
|
...jest.requireActual('amplify-cli-core'),
|
|
@@ -17,6 +20,9 @@ jest.mock('amplify-cli-core', () => ({
|
|
|
17
20
|
getNumber: () => 0,
|
|
18
21
|
},
|
|
19
22
|
}));
|
|
23
|
+
jest.mock('../commands/utils/featureFlags', () => ({
|
|
24
|
+
getTransformerVersion: jest.fn().mockImplementation(() => 2)
|
|
25
|
+
}));
|
|
20
26
|
|
|
21
27
|
const awsMock = aws as any;
|
|
22
28
|
const stateManagerMock = stateManager as any;
|
|
@@ -64,12 +70,12 @@ describe('should sync amplify ui builder components', () => {
|
|
|
64
70
|
promise: jest.fn(() => ({
|
|
65
71
|
entities: [
|
|
66
72
|
{
|
|
67
|
-
appId: 'd37nrm8rzt3oek',
|
|
73
|
+
appId: 'd37nrm8rzt3oek', // eslint-disable-line spellcheck/spell-checker
|
|
68
74
|
bindingProperties: {},
|
|
69
75
|
componentType: 'Box',
|
|
70
76
|
environmentName: 'staging',
|
|
71
|
-
id: 's-s4mU579Ycf6JGHwhqT',
|
|
72
|
-
name: 'aawwdd',
|
|
77
|
+
id: 's-s4mU579Ycf6JGHwhqT', // eslint-disable-line spellcheck/spell-checker
|
|
78
|
+
name: 'aawwdd', // eslint-disable-line spellcheck/spell-checker
|
|
73
79
|
overrides: {},
|
|
74
80
|
properties: {},
|
|
75
81
|
variants: [],
|
|
@@ -82,10 +88,62 @@ describe('should sync amplify ui builder components', () => {
|
|
|
82
88
|
entities: [{}],
|
|
83
89
|
})),
|
|
84
90
|
})),
|
|
91
|
+
exportForms: jest.fn(() => ({
|
|
92
|
+
promise: jest.fn(() => ({
|
|
93
|
+
entities: [{
|
|
94
|
+
name: 'BasicFormCreate',
|
|
95
|
+
formActionType: 'create',
|
|
96
|
+
dataType: {
|
|
97
|
+
dataSourceType: 'Custom',
|
|
98
|
+
dataTypeName: 'Post',
|
|
99
|
+
},
|
|
100
|
+
fields: {
|
|
101
|
+
name: {
|
|
102
|
+
inputType: {
|
|
103
|
+
required: true,
|
|
104
|
+
type: 'TextField',
|
|
105
|
+
name: 'name',
|
|
106
|
+
defaultValue: 'John Doe',
|
|
107
|
+
},
|
|
108
|
+
label: 'name',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
sectionalElements: {},
|
|
112
|
+
style: {},
|
|
113
|
+
}],
|
|
114
|
+
})),
|
|
115
|
+
})),
|
|
116
|
+
exportViews: jest.fn(() => ({
|
|
117
|
+
promise: jest.fn(() => ({
|
|
118
|
+
entities: [{
|
|
119
|
+
appId: '23342',
|
|
120
|
+
dataSource: { type: 'Custom' },
|
|
121
|
+
environmentName: 'staging',
|
|
122
|
+
id: 'id',
|
|
123
|
+
name: 'ProductTable',
|
|
124
|
+
// TODO: replace with export when Codegen updated
|
|
125
|
+
schemaVersion: '1.0',
|
|
126
|
+
style: {},
|
|
127
|
+
viewConfiguration: {
|
|
128
|
+
type: 'Table',
|
|
129
|
+
},
|
|
130
|
+
}],
|
|
131
|
+
})),
|
|
132
|
+
})),
|
|
133
|
+
getMetadata: jest.fn(() => ({
|
|
134
|
+
promise: jest.fn(() => ({
|
|
135
|
+
features: {
|
|
136
|
+
autoGenerateForms: 'true',
|
|
137
|
+
autoGenerateViews: 'true',
|
|
138
|
+
},
|
|
139
|
+
})),
|
|
140
|
+
})),
|
|
85
141
|
}));
|
|
86
142
|
|
|
87
143
|
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn();
|
|
88
144
|
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn();
|
|
145
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn();
|
|
146
|
+
createUiBuilderComponentDependencyMock.createUiBuilderView = jest.fn();
|
|
89
147
|
});
|
|
90
148
|
|
|
91
149
|
it('pulls components from aws-sdk and passes them to createUiBuilderComponent', () => {
|
|
@@ -94,14 +152,14 @@ describe('should sync amplify ui builder components', () => {
|
|
|
94
152
|
|
|
95
153
|
it('does not throw an error when createUiBuilderComponent fails', () => {
|
|
96
154
|
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn(() => {
|
|
97
|
-
throw new Error('ahhh!');
|
|
155
|
+
throw new Error('ahhh!'); // eslint-disable-line spellcheck/spell-checker
|
|
98
156
|
});
|
|
99
157
|
expect(async () => generateUiBuilderComponents(context, [])).not.toThrow();
|
|
100
158
|
});
|
|
101
159
|
|
|
102
160
|
it('does not throw an error when createUiBuilderThemes fails', () => {
|
|
103
161
|
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn(() => {
|
|
104
|
-
throw new Error('ahhh!');
|
|
162
|
+
throw new Error('ahhh!'); // eslint-disable-line spellcheck/spell-checker
|
|
105
163
|
});
|
|
106
164
|
expect(async () => generateUiBuilderThemes(context, [])).not.toThrow();
|
|
107
165
|
});
|
|
@@ -113,19 +171,30 @@ describe('should sync amplify ui builder components', () => {
|
|
|
113
171
|
expect(Object.keys(client)).toEqual(expect.arrayContaining([
|
|
114
172
|
'listComponents',
|
|
115
173
|
'listThemes',
|
|
174
|
+
'listForms',
|
|
116
175
|
'getModels',
|
|
176
|
+
'loadMetadata',
|
|
117
177
|
'createComponent',
|
|
118
178
|
]));
|
|
179
|
+
expect(client.metadata).toEqual(expect.objectContaining({
|
|
180
|
+
autoGenerateForms: true,
|
|
181
|
+
autoGenerateViews: true,
|
|
182
|
+
}));
|
|
183
|
+
});
|
|
184
|
+
it('can list components', async () => {
|
|
185
|
+
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
186
|
+
const components = await client.listComponents();
|
|
187
|
+
expect(components.entities).toHaveLength(1);
|
|
119
188
|
});
|
|
120
189
|
it('can list themes', async () => {
|
|
121
190
|
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
122
191
|
const themes = await client.listThemes();
|
|
123
192
|
expect(themes.entities).toHaveLength(1);
|
|
124
193
|
});
|
|
125
|
-
it('can
|
|
194
|
+
it('can list forms', async () => {
|
|
126
195
|
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
127
|
-
const
|
|
128
|
-
expect(
|
|
196
|
+
const forms = await client.listForms();
|
|
197
|
+
expect(forms.entities).toHaveLength(1);
|
|
129
198
|
});
|
|
130
199
|
it('can getAppId', async () => {
|
|
131
200
|
const appId = getAppId(context);
|
|
@@ -169,4 +238,38 @@ describe('should sync amplify ui builder components', () => {
|
|
|
169
238
|
const themes = generateUiBuilderThemes(context, [{}, {}]);
|
|
170
239
|
expect(themes.every(theme => theme.resultType === 'FAILURE')).toBeTruthy();
|
|
171
240
|
});
|
|
241
|
+
it('can generate ui builder forms', async () => {
|
|
242
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn().mockImplementation(() => ({}));
|
|
243
|
+
const forms = generateUiBuilderForms(context, [{}, {}]);
|
|
244
|
+
expect(forms.every(form => form.resultType === 'SUCCESS')).toBeTruthy();
|
|
245
|
+
});
|
|
246
|
+
it('can handle failed generation generate ui builder forms', async () => {
|
|
247
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn().mockImplementation(() => {
|
|
248
|
+
throw new Error('ahh!');
|
|
249
|
+
});
|
|
250
|
+
const forms = generateUiBuilderForms(context, [{}, {}]);
|
|
251
|
+
expect(forms.every(form => form.resultType === 'FAILURE')).toBeTruthy();
|
|
252
|
+
});
|
|
253
|
+
it('can generate uibuilder forms from data schema if autogen true', async () => {
|
|
254
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn().mockImplementation(() => ({}));
|
|
255
|
+
const forms = generateUiBuilderForms(context, [], exampleSchema, true);
|
|
256
|
+
expect(forms.every(form => form.resultType === 'SUCCESS')).toBeTruthy();
|
|
257
|
+
// create & update form for author model
|
|
258
|
+
expect(forms.length).toEqual(2);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should not autogen forms for join tables or unsupported models', async () => {
|
|
262
|
+
expect(Object.keys(exampleSchema.models)).toStrictEqual(['Author', 'JoinTable', 'EmptyModel' ])
|
|
263
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn().mockImplementation((context, schema, dataSchema) => ({name: schema.dataType.dataTypeName}));
|
|
264
|
+
const forms = generateUiBuilderForms(context, [], exampleSchema, true);
|
|
265
|
+
expect(forms.every(form => form.resultType === 'SUCCESS')).toBeTruthy();
|
|
266
|
+
// only create & update form for author model
|
|
267
|
+
expect(forms.map(f => (f.schema as any).name)).toStrictEqual(['Author', 'Author']);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('does not generate uibuilder forms from data schema if autogen false', async () => {
|
|
271
|
+
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn().mockImplementation(() => ({}));
|
|
272
|
+
const forms = generateUiBuilderForms(context, [], exampleSchema, false);
|
|
273
|
+
expect(forms.length).toEqual(0);
|
|
274
|
+
});
|
|
172
275
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { GenericDataSchema } from '@aws-amplify/codegen-ui';
|
|
2
|
+
|
|
3
|
+
export const exampleSchema: GenericDataSchema = {
|
|
4
|
+
dataSourceType: 'DataStore',
|
|
5
|
+
models: {
|
|
6
|
+
Author: {
|
|
7
|
+
fields: {
|
|
8
|
+
id: {
|
|
9
|
+
dataType: 'ID',
|
|
10
|
+
required: true,
|
|
11
|
+
readOnly: false,
|
|
12
|
+
isArray: false,
|
|
13
|
+
},
|
|
14
|
+
name: {
|
|
15
|
+
dataType: 'String',
|
|
16
|
+
required: false,
|
|
17
|
+
readOnly: false,
|
|
18
|
+
isArray: false,
|
|
19
|
+
},
|
|
20
|
+
profileImageSrc: {
|
|
21
|
+
dataType: 'AWSURL',
|
|
22
|
+
required: false,
|
|
23
|
+
readOnly: false,
|
|
24
|
+
isArray: false,
|
|
25
|
+
},
|
|
26
|
+
description: {
|
|
27
|
+
dataType: 'String',
|
|
28
|
+
required: false,
|
|
29
|
+
readOnly: false,
|
|
30
|
+
isArray: false,
|
|
31
|
+
},
|
|
32
|
+
books: {
|
|
33
|
+
dataType: 'String',
|
|
34
|
+
required: false,
|
|
35
|
+
readOnly: false,
|
|
36
|
+
isArray: true,
|
|
37
|
+
},
|
|
38
|
+
createdAt: {
|
|
39
|
+
dataType: 'AWSDateTime',
|
|
40
|
+
required: false,
|
|
41
|
+
readOnly: true,
|
|
42
|
+
isArray: false,
|
|
43
|
+
},
|
|
44
|
+
updatedAt: {
|
|
45
|
+
dataType: 'AWSDateTime',
|
|
46
|
+
required: false,
|
|
47
|
+
readOnly: true,
|
|
48
|
+
isArray: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
JoinTable: {
|
|
53
|
+
fields: {
|
|
54
|
+
id: {
|
|
55
|
+
dataType: 'ID',
|
|
56
|
+
required: true,
|
|
57
|
+
readOnly: false,
|
|
58
|
+
isArray: false,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
isJoinTable: true
|
|
62
|
+
},
|
|
63
|
+
EmptyModel: {
|
|
64
|
+
fields: {
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
enums: {}, // eslint-disable-line spellcheck/spell-checker
|
|
69
|
+
nonModels: {},
|
|
70
|
+
};
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { $TSContext, CloudformationProviderFacade } from 'amplify-cli-core';
|
|
2
2
|
import type { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
CreateComponentData, Component, Theme, Form,
|
|
5
|
+
} from 'aws-sdk/clients/amplifyuibuilder';
|
|
4
6
|
import { AmplifyUIBuilder, AmplifyBackend } from 'aws-sdk';
|
|
5
7
|
import { printer } from 'amplify-prompts';
|
|
6
8
|
import { getAppId, getEnvName } from '../commands/utils/environmentHelpers';
|
|
9
|
+
import { getTransformerVersion } from '../commands/utils/featureFlags';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* studio client metadata
|
|
13
|
+
*/
|
|
14
|
+
export type StudioMetadata = {
|
|
15
|
+
autoGenerateForms: boolean;
|
|
16
|
+
autoGenerateViews: boolean;
|
|
17
|
+
};
|
|
7
18
|
|
|
8
19
|
/**
|
|
9
20
|
* Builds the Amplify Backend Client
|
|
@@ -45,6 +56,8 @@ export default class AmplifyStudioClient {
|
|
|
45
56
|
#amplifyBackend: AmplifyBackend;
|
|
46
57
|
#appId: string;
|
|
47
58
|
#envName: string;
|
|
59
|
+
metadata: StudioMetadata;
|
|
60
|
+
isSupportedGraphQL = false;
|
|
48
61
|
/**
|
|
49
62
|
* Used to configure the AWS Amplify clients.
|
|
50
63
|
*/
|
|
@@ -56,19 +69,56 @@ export default class AmplifyStudioClient {
|
|
|
56
69
|
resolvedEnvName,
|
|
57
70
|
resolvedAppId,
|
|
58
71
|
])) as ServiceConfigurationOptions;
|
|
59
|
-
|
|
72
|
+
|
|
73
|
+
const client = new AmplifyStudioClient(awsConfigInfo, resolvedAppId, resolvedEnvName);
|
|
74
|
+
|
|
75
|
+
if ((await getTransformerVersion(context)) === 2) {
|
|
76
|
+
await client.loadMetadata();
|
|
77
|
+
client.isSupportedGraphQL = true;
|
|
78
|
+
} else {
|
|
79
|
+
client.isSupportedGraphQL = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return client;
|
|
60
83
|
}
|
|
61
84
|
|
|
62
85
|
/*
|
|
63
|
-
|
|
64
|
-
|
|
86
|
+
* Builds the clients
|
|
87
|
+
*/
|
|
65
88
|
constructor(awsConfigInfo: ServiceConfigurationOptions, appId: string, envName: string) {
|
|
66
89
|
this.#amplifyUiBuilder = buildAmplifyUiBuilderClient(awsConfigInfo);
|
|
67
90
|
this.#amplifyBackend = buildAmplifyBackendClient(awsConfigInfo);
|
|
68
91
|
this.#appId = appId;
|
|
69
92
|
this.#envName = envName;
|
|
93
|
+
this.metadata = {
|
|
94
|
+
autoGenerateForms: false,
|
|
95
|
+
autoGenerateViews: false,
|
|
96
|
+
};
|
|
70
97
|
}
|
|
71
98
|
|
|
99
|
+
/**
|
|
100
|
+
* loads metadata from appId/envName
|
|
101
|
+
*/
|
|
102
|
+
loadMetadata = async (envName?: string, appId?: string): Promise<void> => {
|
|
103
|
+
const environmentName = envName || this.#envName;
|
|
104
|
+
const resolvedAppId = appId || this.#appId;
|
|
105
|
+
try {
|
|
106
|
+
const response = await this.#amplifyUiBuilder
|
|
107
|
+
.getMetadata({
|
|
108
|
+
appId: resolvedAppId,
|
|
109
|
+
environmentName,
|
|
110
|
+
})
|
|
111
|
+
.promise();
|
|
112
|
+
this.metadata = {
|
|
113
|
+
autoGenerateForms: response.features?.autoGenerateForms === 'true',
|
|
114
|
+
autoGenerateViews: response.features?.autoGenerateViews === 'true',
|
|
115
|
+
};
|
|
116
|
+
} catch (e) {
|
|
117
|
+
printer.debug(e.toString());
|
|
118
|
+
throw e;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
72
122
|
/**
|
|
73
123
|
* listComponents from Studio
|
|
74
124
|
*/
|
|
@@ -95,67 +145,100 @@ export default class AmplifyStudioClient {
|
|
|
95
145
|
printer.debug(e);
|
|
96
146
|
throw e;
|
|
97
147
|
}
|
|
98
|
-
}
|
|
148
|
+
};
|
|
99
149
|
|
|
100
150
|
/**
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
let nextToken: string | undefined;
|
|
109
|
-
const uiBuilderThemes: Theme[] = [];
|
|
110
|
-
do {
|
|
111
|
-
const response = await this.#amplifyUiBuilder
|
|
112
|
-
.exportThemes({
|
|
113
|
-
appId: resolvedAppId,
|
|
114
|
-
environmentName,
|
|
115
|
-
nextToken,
|
|
116
|
-
})
|
|
117
|
-
.promise();
|
|
118
|
-
uiBuilderThemes.push(...response.entities);
|
|
119
|
-
nextToken = response.nextToken;
|
|
120
|
-
} while (nextToken);
|
|
121
|
-
printer.debug(JSON.stringify(uiBuilderThemes, null, 2));
|
|
122
|
-
return { entities: uiBuilderThemes };
|
|
123
|
-
} catch (e) {
|
|
124
|
-
printer.debug(e);
|
|
125
|
-
throw e;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
151
|
+
* Returns all the UI Builder themes from the app
|
|
152
|
+
*/
|
|
153
|
+
listThemes = async (envName?: string, appId?: string): Promise<{ entities: Theme[] }> => {
|
|
154
|
+
const environmentName = envName || this.#envName;
|
|
155
|
+
const resolvedAppId = appId || this.#appId;
|
|
128
156
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
try {
|
|
158
|
+
let nextToken: string | undefined;
|
|
159
|
+
const uiBuilderThemes: Theme[] = [];
|
|
160
|
+
do {
|
|
161
|
+
const response = await this.#amplifyUiBuilder
|
|
162
|
+
.exportThemes({
|
|
163
|
+
appId: resolvedAppId,
|
|
164
|
+
environmentName,
|
|
165
|
+
nextToken,
|
|
166
|
+
})
|
|
167
|
+
.promise();
|
|
168
|
+
uiBuilderThemes.push(...response.entities);
|
|
169
|
+
nextToken = response.nextToken;
|
|
170
|
+
} while (nextToken);
|
|
171
|
+
printer.debug(JSON.stringify(uiBuilderThemes, null, 2));
|
|
172
|
+
return { entities: uiBuilderThemes };
|
|
173
|
+
} catch (e) {
|
|
174
|
+
printer.debug(e);
|
|
175
|
+
throw e;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
listForms = async (envName?: string, appId?: string): Promise<{ entities: Form[] }> => {
|
|
180
|
+
const environmentName = envName || this.#envName;
|
|
181
|
+
const resolvedAppId = appId || this.#appId;
|
|
182
|
+
try {
|
|
183
|
+
let nextToken: string | undefined;
|
|
184
|
+
const uibuilderForms: Form[] = [];
|
|
185
|
+
do {
|
|
186
|
+
const response = await this.#amplifyUiBuilder
|
|
187
|
+
.exportForms({
|
|
188
|
+
appId: resolvedAppId,
|
|
189
|
+
environmentName,
|
|
190
|
+
nextToken,
|
|
191
|
+
})
|
|
192
|
+
.promise();
|
|
193
|
+
uibuilderForms.push(...response.entities);
|
|
194
|
+
nextToken = response.nextToken;
|
|
195
|
+
} while (nextToken);
|
|
196
|
+
printer.debug(JSON.stringify(uibuilderForms, null, 2));
|
|
197
|
+
return { entities: uibuilderForms };
|
|
198
|
+
} catch (e) {
|
|
199
|
+
printer.debug(e);
|
|
200
|
+
throw e;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
createComponent = async (component: CreateComponentData, envName?: string, appId?: string): Promise<Component | undefined> => {
|
|
205
|
+
const environmentName = envName || this.#envName;
|
|
206
|
+
const resolvedAppId = appId || this.#appId;
|
|
207
|
+
try {
|
|
208
|
+
const response = await this.#amplifyUiBuilder
|
|
209
|
+
.createComponent({
|
|
210
|
+
appId: resolvedAppId,
|
|
211
|
+
environmentName,
|
|
212
|
+
componentToCreate: component,
|
|
213
|
+
})
|
|
214
|
+
.promise();
|
|
215
|
+
return response.entity;
|
|
216
|
+
} catch (err) {
|
|
217
|
+
printer.debug(err.toString());
|
|
218
|
+
throw err;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
getModels = async (resourceName: string, envName?: string, appId?: string): Promise<string | undefined> => {
|
|
223
|
+
try {
|
|
224
|
+
const environmentName = envName || this.#envName;
|
|
225
|
+
const resolvedAppId = appId || this.#appId;
|
|
226
|
+
const { Models } = await this.#amplifyBackend
|
|
227
|
+
.getBackendAPIModels({
|
|
228
|
+
AppId: resolvedAppId,
|
|
229
|
+
BackendEnvironmentName: environmentName,
|
|
230
|
+
ResourceName: resourceName,
|
|
231
|
+
})
|
|
232
|
+
.promise();
|
|
233
|
+
return Models;
|
|
234
|
+
} catch (e) {
|
|
235
|
+
printer.debug(e);
|
|
236
|
+
throw new Error(`Models not found in AmplifyBackend:GetBackendAPIModels response: ${e.message}`);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
144
239
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const resolvedAppId = appId || this.#appId;
|
|
149
|
-
const { Models } = await this.#amplifyBackend.getBackendAPIModels({
|
|
150
|
-
AppId: resolvedAppId,
|
|
151
|
-
BackendEnvironmentName: environmentName,
|
|
152
|
-
ResourceName: resourceName,
|
|
153
|
-
})
|
|
154
|
-
.promise();
|
|
155
|
-
return Models;
|
|
156
|
-
} catch (e) {
|
|
157
|
-
printer.debug(e);
|
|
158
|
-
throw new Error(`Models not found in AmplifyBackend:GetBackendAPIModels response: ${e.message}`);
|
|
159
|
-
}
|
|
240
|
+
isAmplifyApp = async (context: $TSContext): Promise<boolean> => {
|
|
241
|
+
const { isAdminApp } = await CloudformationProviderFacade.isAmplifyAdminApp(context, this.#appId);
|
|
242
|
+
return isAdminApp;
|
|
160
243
|
}
|
|
161
244
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable spellcheck/spell-checker */
|
|
2
|
+
import { StudioSchema } from '@aws-amplify/codegen-ui';
|
|
2
3
|
import ora from 'ora';
|
|
3
4
|
import { printer } from 'amplify-prompts';
|
|
4
5
|
import { $TSContext } from 'amplify-cli-core';
|
|
@@ -10,6 +11,8 @@ import {
|
|
|
10
11
|
generateUiBuilderThemes,
|
|
11
12
|
getAmplifyDataSchema,
|
|
12
13
|
generateAmplifyUiBuilderIndexFile,
|
|
14
|
+
generateUiBuilderForms,
|
|
15
|
+
generateAmplifyUiBuilderUtilFile,
|
|
13
16
|
} from './utils';
|
|
14
17
|
|
|
15
18
|
/**
|
|
@@ -22,36 +25,63 @@ export const run = async (context: $TSContext): Promise<void> => {
|
|
|
22
25
|
const spinner = ora('');
|
|
23
26
|
try {
|
|
24
27
|
const studioClient = await AmplifyStudioClient.setClientInfo(context);
|
|
25
|
-
|
|
28
|
+
if (!(await studioClient.isAmplifyApp(context))) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const [componentSchemas, themeSchemas, formSchemas, dataSchema] = await Promise.all([
|
|
26
32
|
studioClient.listComponents(),
|
|
27
33
|
studioClient.listThemes(),
|
|
34
|
+
studioClient.listForms(),
|
|
28
35
|
getAmplifyDataSchema(studioClient),
|
|
29
36
|
]);
|
|
30
|
-
|
|
37
|
+
|
|
38
|
+
const nothingWouldAutogen = !dataSchema || !studioClient.metadata.autoGenerateForms || !studioClient.isSupportedGraphQL;
|
|
39
|
+
|
|
40
|
+
if (nothingWouldAutogen && [componentSchemas, themeSchemas, formSchemas].every(group => !group.entities.length)) {
|
|
31
41
|
printer.debug('Skipping UI component generation since none are found.');
|
|
32
42
|
return;
|
|
33
43
|
}
|
|
34
44
|
spinner.start('Generating UI components...');
|
|
35
|
-
const generatedComponentResults = generateUiBuilderComponents(context, componentSchemas.entities, dataSchema);
|
|
36
|
-
const generatedThemeResults = generateUiBuilderThemes(context, themeSchemas.entities);
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
const generatedResults = {
|
|
47
|
+
component: generateUiBuilderComponents(context, componentSchemas.entities, dataSchema),
|
|
48
|
+
theme: generateUiBuilderThemes(context, themeSchemas.entities),
|
|
49
|
+
form: generateUiBuilderForms(
|
|
50
|
+
context, formSchemas.entities, dataSchema, studioClient.metadata.autoGenerateForms && studioClient.isSupportedGraphQL,
|
|
51
|
+
),
|
|
52
|
+
};
|
|
42
53
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
];
|
|
54
|
+
const successfulSchemas: StudioSchema[] = [];
|
|
55
|
+
let hasSuccessfulForm = false;
|
|
56
|
+
const failedResponseNames: string[] = [];
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
Object.entries(generatedResults).forEach(([key, results]) => {
|
|
59
|
+
results.forEach(result => {
|
|
60
|
+
if (result.resultType === 'SUCCESS') {
|
|
61
|
+
successfulSchemas.push(result.schema);
|
|
62
|
+
if (key === 'form') {
|
|
63
|
+
hasSuccessfulForm = true;
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
failedResponseNames.push(result.schemaName);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
generateAmplifyUiBuilderIndexFile(context, successfulSchemas);
|
|
72
|
+
|
|
73
|
+
generateAmplifyUiBuilderUtilFile(context, { hasForms: hasSuccessfulForm, hasViews: false });
|
|
74
|
+
|
|
75
|
+
if (failedResponseNames.length > 0) {
|
|
76
|
+
spinner.fail(`Failed to sync the following components: ${failedResponseNames.join(', ')}`);
|
|
50
77
|
} else {
|
|
51
78
|
spinner.succeed('Synced UI components.');
|
|
52
79
|
}
|
|
53
80
|
|
|
54
|
-
const invalidComponentNames =
|
|
81
|
+
const invalidComponentNames = [
|
|
82
|
+
...componentSchemas.entities.filter(component => !component.schemaVersion).map(component => component.name),
|
|
83
|
+
...formSchemas.entities.filter(form => !form.schemaVersion).map(form => form.name),
|
|
84
|
+
];
|
|
55
85
|
if (invalidComponentNames.length) {
|
|
56
86
|
printer.warn(
|
|
57
87
|
`The components ${invalidComponentNames.join(
|
package/src/commands/help.ts
CHANGED