@axinom/mosaic-agent-skills 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/tools/graphql/index.d.ts +3 -0
- package/dist/tools/graphql/index.d.ts.map +1 -0
- package/dist/tools/graphql/index.js +84 -0
- package/dist/tools/graphql/index.js.map +1 -0
- package/dist/tools/graphql/tools.d.ts +71 -0
- package/dist/tools/graphql/tools.d.ts.map +1 -0
- package/dist/tools/graphql/tools.js +187 -0
- package/dist/tools/graphql/tools.js.map +1 -0
- package/dist/tools/graphql/utils.d.ts +20 -0
- package/dist/tools/graphql/utils.d.ts.map +1 -0
- package/dist/tools/graphql/utils.js +140 -0
- package/dist/tools/graphql/utils.js.map +1 -0
- package/dist/tools/skills/index.d.ts +3 -0
- package/dist/tools/skills/index.d.ts.map +1 -0
- package/dist/tools/skills/index.js +62 -0
- package/dist/tools/skills/index.js.map +1 -0
- package/dist/tools/skills/tools.d.ts +5 -0
- package/dist/tools/skills/tools.d.ts.map +1 -0
- package/dist/tools/skills/tools.js +67 -0
- package/dist/tools/skills/tools.js.map +1 -0
- package/dist/tools/skills/types.d.ts +12 -0
- package/dist/tools/skills/types.d.ts.map +1 -0
- package/dist/tools/skills/types.js +3 -0
- package/dist/tools/skills/types.js.map +1 -0
- package/dist/tools/skills/utils.d.ts +11 -0
- package/dist/tools/skills/utils.d.ts.map +1 -0
- package/dist/tools/skills/utils.js +127 -0
- package/dist/tools/skills/utils.js.map +1 -0
- package/package.json +40 -0
- package/skills/_shared/actions/execution-summary.md +53 -0
- package/skills/_shared/actions/typescript-codegen.md +32 -0
- package/skills/_shared/actions/typescript-validation.md +32 -0
- package/skills/_shared/conventions/field-component-mapping.md +155 -0
- package/skills/_shared/conventions/field-validation-schema.md +77 -0
- package/skills/_shared/discovery/discover-paths.md +52 -0
- package/skills/_shared/discovery/extract-entity-features.md +565 -0
- package/skills/generate-create-station/SKILL.md +93 -0
- package/skills/generate-create-station/refs/finalization/station-registration.md +163 -0
- package/skills/generate-create-station/refs/templates/create-form-station.md +206 -0
- package/skills/generate-create-station/refs/templates/graphql-operations.md +56 -0
- package/skills/generate-details-station/SKILL.md +125 -0
- package/skills/generate-details-station/refs/finalization/explorer-integration.md +242 -0
- package/skills/generate-details-station/refs/finalization/station-registration.md +139 -0
- package/skills/generate-details-station/refs/templates/actions.md +127 -0
- package/skills/generate-details-station/refs/templates/breadcrumb.md +67 -0
- package/skills/generate-details-station/refs/templates/details-form-station.md +589 -0
- package/skills/generate-details-station/refs/templates/details-wrapper.md +54 -0
- package/skills/generate-details-station/refs/templates/form-data-types.md +62 -0
- package/skills/generate-details-station/refs/templates/graphql-operations.md +256 -0
- package/skills/generate-details-station/refs/templates/managed-integrations/image-management-station.md +322 -0
- package/skills/generate-details-station/refs/templates/managed-integrations/video-management-station.md +283 -0
- package/skills/generate-explorer-station/SKILL.md +121 -0
- package/skills/generate-explorer-station/refs/finalization/station-registration.md +145 -0
- package/skills/generate-explorer-station/refs/select-columns-filters.md +63 -0
- package/skills/generate-explorer-station/refs/templates/bulk-edit.md +369 -0
- package/skills/generate-explorer-station/refs/templates/common/bulk-actions.md +64 -0
- package/skills/generate-explorer-station/refs/templates/common/columns.md +131 -0
- package/skills/generate-explorer-station/refs/templates/common/data-provider.md +83 -0
- package/skills/generate-explorer-station/refs/templates/common/filters.md +220 -0
- package/skills/generate-explorer-station/refs/templates/common/inline-actions.md +45 -0
- package/skills/generate-explorer-station/refs/templates/common/types.md +28 -0
- package/skills/generate-explorer-station/refs/templates/graphql-operations.md +235 -0
- package/skills/generate-explorer-station/refs/templates/navigation-explorer-station.md +144 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: station-registration
|
|
3
|
+
input:
|
|
4
|
+
- EntityFeatures
|
|
5
|
+
- Generated create component
|
|
6
|
+
- DiscoveredPaths
|
|
7
|
+
output:
|
|
8
|
+
- Updated registrations.tsx with create route
|
|
9
|
+
- Updated explorer with onCreateAction (if explorer exists)
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Register Create Station
|
|
13
|
+
|
|
14
|
+
Register create route and optionally integrate with explorer.
|
|
15
|
+
|
|
16
|
+
## File Path
|
|
17
|
+
|
|
18
|
+
`{workflowsPath}/src/Stations/{EntityPlural}/registrations.tsx`
|
|
19
|
+
|
|
20
|
+
## Add Import
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { {Entity}Create } from './{Entity}Create/{Entity}Create';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Add Route Registration
|
|
27
|
+
|
|
28
|
+
Add inside the `register()` function:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
app.registerPage('/{kebabCasePlural}/create', {Entity}Create, {
|
|
32
|
+
breadcrumb: () => 'New {Entity}',
|
|
33
|
+
permissions: { '{features.service.serviceId}': {features.service.permissions} },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Update Explorer Component (if exists)
|
|
38
|
+
|
|
39
|
+
**Search for:**
|
|
40
|
+
`{workflowsPath}/src/Stations/{EntityPlural}/{EntityPlural}Explorer/{EntityPlural}.tsx`
|
|
41
|
+
|
|
42
|
+
**If file exists:**
|
|
43
|
+
|
|
44
|
+
1. Check if `onCreateAction` prop already exists in `NavigationExplorer`
|
|
45
|
+
2. If prop has TODO comment, replace with actual path
|
|
46
|
+
3. If prop missing, add it
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
<NavigationExplorer<{Entity}Data>
|
|
50
|
+
title="{EntityPlural}"
|
|
51
|
+
stationKey="{EntityPlural}Explorer"
|
|
52
|
+
calculateNavigateUrl={(item) => `/{kebabCasePlural}/${item.id}`}
|
|
53
|
+
onCreateAction="/{kebabCasePlural}/create" // <-- Add or update this line
|
|
54
|
+
columns={{entityCamel}Columns}
|
|
55
|
+
// ... rest of props
|
|
56
|
+
/>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**If file does not exist:** Skip this step (explorer not yet generated)
|
|
60
|
+
|
|
61
|
+
## Example
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// In registrations.tsx
|
|
65
|
+
import { PiletApi } from '@axinom/mosaic-portal';
|
|
66
|
+
import React from 'react';
|
|
67
|
+
import {
|
|
68
|
+
Extensions,
|
|
69
|
+
ExtensionsContext,
|
|
70
|
+
} from '{discoveredPaths.extensionsContextPath}';
|
|
71
|
+
import { MediaIconName, MediaIcons } from '../../MediaIcons';
|
|
72
|
+
import { Movies } from './MoviesExplorer/Movies';
|
|
73
|
+
import { MovieDetails } from './MovieDetails/MovieDetails';
|
|
74
|
+
import { MovieDetailsCrumb } from './MovieDetails/MovieDetailsCrumb';
|
|
75
|
+
import { MovieCreate } from './MovieCreate/MovieCreate';
|
|
76
|
+
|
|
77
|
+
export function register(app: PiletApi, extensions: Extensions): void {
|
|
78
|
+
const moviesNav = {
|
|
79
|
+
name: 'movies',
|
|
80
|
+
path: '/movies',
|
|
81
|
+
label: 'Movies',
|
|
82
|
+
icon: <MediaIcons icon={MediaIconName.Movie} />,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
app.registerTile({ ...moviesNav, kind: 'home', type: 'large' }, false);
|
|
86
|
+
app.registerNavigationItem({ ...moviesNav, categoryName: 'Content' });
|
|
87
|
+
|
|
88
|
+
// Explorer route
|
|
89
|
+
app.registerPage(
|
|
90
|
+
'/movies',
|
|
91
|
+
() => (
|
|
92
|
+
<ExtensionsContext.Provider value={extensions}>
|
|
93
|
+
<Movies />
|
|
94
|
+
</ExtensionsContext.Provider>
|
|
95
|
+
),
|
|
96
|
+
{
|
|
97
|
+
breadcrumb: () => 'Movies',
|
|
98
|
+
permissions: { 'media-service': ['ADMIN', 'MOVIES_EDIT', 'MOVIES_VIEW'] },
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Create route
|
|
103
|
+
app.registerPage('/movies/create', MovieCreate, {
|
|
104
|
+
breadcrumb: () => 'New Movie',
|
|
105
|
+
permissions: { 'media-service': ['ADMIN', 'MOVIES_EDIT'] },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Details route
|
|
109
|
+
app.registerPage(
|
|
110
|
+
'/movies/:movieId',
|
|
111
|
+
() => (
|
|
112
|
+
<ExtensionsContext.Provider value={extensions}>
|
|
113
|
+
<MovieDetails />
|
|
114
|
+
</ExtensionsContext.Provider>
|
|
115
|
+
),
|
|
116
|
+
{
|
|
117
|
+
breadcrumb: MovieDetailsCrumb,
|
|
118
|
+
permissions: { 'media-service': ['ADMIN', 'MOVIES_EDIT', 'MOVIES_VIEW'] },
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// In MoviesExplorer/Movies.tsx
|
|
126
|
+
import { NavigationExplorer } from '@axinom/mosaic-ui';
|
|
127
|
+
import React from 'react';
|
|
128
|
+
import { useMoviesBulkActions } from './common/Movies.bulkActions';
|
|
129
|
+
import { moviesColumns } from './common/Movies.columns';
|
|
130
|
+
import { createMoviesDataProvider } from './common/Movies.dataProvider';
|
|
131
|
+
import { useMoviesFilters } from './common/Movies.filters';
|
|
132
|
+
import { useMoviesInlineActions } from './common/Movies.inlineActions';
|
|
133
|
+
import { MovieData } from './common/Movies.types';
|
|
134
|
+
|
|
135
|
+
export const Movies: React.FC = () => {
|
|
136
|
+
const { transformFilters, filterOptions } = useMoviesFilters();
|
|
137
|
+
const { bulkActions } = useMoviesBulkActions();
|
|
138
|
+
const { generateInlineMenuActions } = useMoviesInlineActions();
|
|
139
|
+
const dataProvider = createMoviesDataProvider(transformFilters);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<NavigationExplorer<MovieData>
|
|
143
|
+
title="Movies"
|
|
144
|
+
stationKey="MoviesExplorer"
|
|
145
|
+
calculateNavigateUrl={(item) => `/movies/${item.id}`}
|
|
146
|
+
onCreateAction="/movies/create" // <-- Integrated
|
|
147
|
+
columns={moviesColumns}
|
|
148
|
+
dataProvider={dataProvider}
|
|
149
|
+
filterOptions={filterOptions}
|
|
150
|
+
defaultSortOrder={{ column: 'updatedDate', direction: 'desc' }}
|
|
151
|
+
inlineMenuActions={generateInlineMenuActions}
|
|
152
|
+
bulkActions={bulkActions}
|
|
153
|
+
quickEditRegistrations={[]}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- Create route uses same permissions as explorer (with `EDIT` capabilities)
|
|
162
|
+
- Route path: `/{kebabCasePlural}/create`
|
|
163
|
+
- Breadcrumb: Simple function returning `'New {Entity}'`
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-form-station
|
|
3
|
+
input:
|
|
4
|
+
- EntityFeatures
|
|
5
|
+
- DiscoveredPaths
|
|
6
|
+
- Reference: field-component-mapping
|
|
7
|
+
- Reference: field-validation-schema
|
|
8
|
+
output:
|
|
9
|
+
- path: '{workflowsPath}/src/Stations/{EntityPlural}/{Entity}Create/{Entity}Create.tsx'
|
|
10
|
+
description:
|
|
11
|
+
'Create component with form, validation, mutation, navigation, breadcrumb'
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Generate Create Form Station
|
|
15
|
+
|
|
16
|
+
Create station with `@axinom/mosaic-ui` Create component, mutation, and
|
|
17
|
+
navigation.
|
|
18
|
+
|
|
19
|
+
## Template
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { BreadcrumbResolver } from '@axinom/mosaic-portal';
|
|
23
|
+
import {
|
|
24
|
+
ActionHandler,
|
|
25
|
+
Create,
|
|
26
|
+
Nullable,
|
|
27
|
+
// Import components based on field types (see field-component-mapping)
|
|
28
|
+
SingleLineTextField,
|
|
29
|
+
DateTimeTextField,
|
|
30
|
+
SelectField,
|
|
31
|
+
CheckboxField,
|
|
32
|
+
// ... other components as needed
|
|
33
|
+
} from '@axinom/mosaic-ui';
|
|
34
|
+
import { Field } from 'formik';
|
|
35
|
+
import { ObjectSchemaDefinition } from 'ObjectSchemaDefinition';
|
|
36
|
+
import React, { useCallback } from 'react';
|
|
37
|
+
import { useHistory } from 'react-router-dom';
|
|
38
|
+
import * as Yup from 'yup';
|
|
39
|
+
import { client } from '{discoveredPath}/apolloClient';
|
|
40
|
+
import {
|
|
41
|
+
Create{Entity}Mutation,
|
|
42
|
+
Create{Entity}MutationVariables,
|
|
43
|
+
useCreate{Entity}Mutation,
|
|
44
|
+
} from '../../../generated/graphql';
|
|
45
|
+
|
|
46
|
+
type FormData = Create{Entity}MutationVariables['input']['{entityCamel}'];
|
|
47
|
+
|
|
48
|
+
type SubmitResponse = Nullable<Create{Entity}Mutation['create{Entity}']>;
|
|
49
|
+
|
|
50
|
+
const {entityCamel}CreateSchema = Yup.object<ObjectSchemaDefinition<FormData>>({
|
|
51
|
+
// Generate validation for REQUIRED fields only from features.schema.input
|
|
52
|
+
// Use field-validation-schema patterns based on field.type
|
|
53
|
+
|
|
54
|
+
{titleField}: Yup.string().required('{TitleLabel} is a required field').max({maxLength}),
|
|
55
|
+
// ... other required fields only
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const {Entity}Create: React.FC = () => {
|
|
59
|
+
const [create{Entity}] = useCreate{Entity}Mutation({
|
|
60
|
+
client: client,
|
|
61
|
+
fetchPolicy: 'no-cache',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const saveData = useCallback(
|
|
65
|
+
async (formData: FormData): Promise<SubmitResponse> => {
|
|
66
|
+
return (
|
|
67
|
+
await create{Entity}({
|
|
68
|
+
variables: {
|
|
69
|
+
input: {
|
|
70
|
+
{entityCamel}: {
|
|
71
|
+
// Map REQUIRED fields from formData to mutation input
|
|
72
|
+
// Use field-component-mapping for type conversions (Number() for Int/Float)
|
|
73
|
+
{titleField}: formData.{titleField},
|
|
74
|
+
// ... other required fields
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
).data?.create{Entity};
|
|
80
|
+
},
|
|
81
|
+
[create{Entity}],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const history = useHistory();
|
|
85
|
+
const onProceed = useCallback<ActionHandler<FormData, SubmitResponse>>(
|
|
86
|
+
({ submitResponse }) => {
|
|
87
|
+
if (submitResponse?.{entityCamel}) {
|
|
88
|
+
// If Details station exists:
|
|
89
|
+
history.push(`/{kebabCasePlural}/${submitResponse?.{entityCamel}.id}`);
|
|
90
|
+
// If Details station does not exist:
|
|
91
|
+
// TODO: Update navigation once Details station is created
|
|
92
|
+
// history.push('/{kebabCasePlural}');
|
|
93
|
+
} else {
|
|
94
|
+
// The schema has the response.data properties marked as optional, since theoretically a user could have
|
|
95
|
+
// permissions to mutate but not to read. In practice this can not happen on that service, so we just throw
|
|
96
|
+
// an error in case we get there.
|
|
97
|
+
throw new Error('Not expected');
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
[history],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Create<FormData, SubmitResponse>
|
|
105
|
+
title="New {Entity}"
|
|
106
|
+
subtitle="Add new {entityCamel} metadata"
|
|
107
|
+
validationSchema={{entityCamel}CreateSchema}
|
|
108
|
+
saveData={saveData}
|
|
109
|
+
onProceed={onProceed}
|
|
110
|
+
cancelNavigationUrl="/{kebabCasePlural}" // Navigate to explorer (if explorer doesn't exist, add TODO)
|
|
111
|
+
initialData={{
|
|
112
|
+
loading: false,
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{/* Generate Field for each REQUIRED field in features.schema.input where field.isRequired === true */}
|
|
116
|
+
{/* Use field-component-mapping to select component based on field.type */}
|
|
117
|
+
<Field name="{titleField}" label="{TitleLabel}" as={SingleLineTextField} />
|
|
118
|
+
{/* ... other required fields */}
|
|
119
|
+
</Create>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const {Entity}CreateCrumb: BreadcrumbResolver = () => 'Create';
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Example
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { BreadcrumbResolver } from '@axinom/mosaic-portal';
|
|
130
|
+
import { ActionHandler, Create, SingleLineTextField } from '@axinom/mosaic-ui';
|
|
131
|
+
import { Field } from 'formik';
|
|
132
|
+
import { ObjectSchemaDefinition } from 'ObjectSchemaDefinition';
|
|
133
|
+
import React, { useCallback } from 'react';
|
|
134
|
+
import { useHistory } from 'react-router-dom';
|
|
135
|
+
import * as Yup from 'yup';
|
|
136
|
+
import { client } from '../../../apolloClient';
|
|
137
|
+
import {
|
|
138
|
+
CreateMovieMutation,
|
|
139
|
+
CreateMovieMutationVariables,
|
|
140
|
+
useCreateMovieMutation,
|
|
141
|
+
} from '../../../generated/graphql';
|
|
142
|
+
|
|
143
|
+
type FormData = CreateMovieMutationVariables['input']['movie'];
|
|
144
|
+
type SubmitResponse = CreateMovieMutation['createMovie'];
|
|
145
|
+
|
|
146
|
+
const movieCreateSchema = Yup.object().shape<ObjectSchemaDefinition<FormData>>({
|
|
147
|
+
title: Yup.string().required('Title is a required field').max(100),
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
export const MovieCreate: React.FC = () => {
|
|
151
|
+
const [movieCreate] = useCreateMovieMutation({
|
|
152
|
+
client: client,
|
|
153
|
+
fetchPolicy: 'no-cache',
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const saveData = useCallback(
|
|
157
|
+
async (formData: FormData): Promise<SubmitResponse> => {
|
|
158
|
+
return (
|
|
159
|
+
await movieCreate({
|
|
160
|
+
variables: { input: { movie: { title: formData.title } } },
|
|
161
|
+
})
|
|
162
|
+
).data?.createMovie;
|
|
163
|
+
},
|
|
164
|
+
[movieCreate],
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const history = useHistory();
|
|
168
|
+
const onProceed = useCallback<ActionHandler<FormData, SubmitResponse>>(
|
|
169
|
+
({ submitResponse }) => {
|
|
170
|
+
if (submitResponse?.movie) {
|
|
171
|
+
history.push(`/movies/${submitResponse.movie.id}`);
|
|
172
|
+
} else {
|
|
173
|
+
throw new Error('Not expected');
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
[history],
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Create<FormData, SubmitResponse>
|
|
181
|
+
title="New Movie"
|
|
182
|
+
subtitle="Add new movie metadata"
|
|
183
|
+
validationSchema={movieCreateSchema}
|
|
184
|
+
saveData={saveData}
|
|
185
|
+
onProceed={onProceed}
|
|
186
|
+
cancelNavigationUrl="/movies"
|
|
187
|
+
initialData={{ loading: false }}
|
|
188
|
+
>
|
|
189
|
+
<Field name="title" label="Title" as={SingleLineTextField} />
|
|
190
|
+
</Create>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const MovieCreateCrumb: BreadcrumbResolver = () => 'Create';
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Notes
|
|
198
|
+
|
|
199
|
+
- **Navigation after success (`onProceed`):**
|
|
200
|
+
- If Details station exists: Navigate to `/{kebabCasePlural}/${id}`
|
|
201
|
+
- If Details station does not exist: Keep commented fallback with TODO,
|
|
202
|
+
navigate to `/{kebabCasePlural}/${id}` (will be updated when Details is built)
|
|
203
|
+
- **Cancel navigation (`cancelNavigationUrl`):**
|
|
204
|
+
- If Explorer station exists: Navigate to `/{kebabCasePlural}`
|
|
205
|
+
- If Explorer station does not exist: ADD TODO comment above the prop
|
|
206
|
+
- **Only required fields** - no optional fields in create station
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graphql-operations
|
|
3
|
+
input:
|
|
4
|
+
- EntityFeatures
|
|
5
|
+
output:
|
|
6
|
+
- path: '{workflowsPath}/src/Stations/{EntityPlural}/{Entity}Create/{Entity}Create.graphql'
|
|
7
|
+
description: 'Create mutation returning id and title'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Generate GraphQL File
|
|
11
|
+
|
|
12
|
+
Single file with create mutation.
|
|
13
|
+
|
|
14
|
+
## Template
|
|
15
|
+
|
|
16
|
+
```graphql
|
|
17
|
+
mutation Create{features.name}($input: Create{features.name}Input!) {
|
|
18
|
+
create{features.name}(input: $input) {
|
|
19
|
+
{features.camelCase} {
|
|
20
|
+
id
|
|
21
|
+
{features.titleField}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Pattern
|
|
28
|
+
|
|
29
|
+
- Mutation name: `Create{Entity}`
|
|
30
|
+
- Input type: `Create{Entity}Input!` (standard PostGraphile pattern)
|
|
31
|
+
- Return payload path: `create{Entity}.{entityCamel}`
|
|
32
|
+
- Return fields: `id`
|
|
33
|
+
|
|
34
|
+
## Example
|
|
35
|
+
|
|
36
|
+
```graphql
|
|
37
|
+
mutation CreateMovie($input: CreateMovieInput!) {
|
|
38
|
+
createMovie(input: $input) {
|
|
39
|
+
movie {
|
|
40
|
+
id
|
|
41
|
+
title
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```graphql
|
|
48
|
+
mutation CreateCollection($input: CreateCollectionInput!) {
|
|
49
|
+
createCollection(input: $input) {
|
|
50
|
+
collection {
|
|
51
|
+
id
|
|
52
|
+
title
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: generate-details-station
|
|
3
|
+
description: |
|
|
4
|
+
Generates a Details station for a Mosaic entity from scratch using
|
|
5
|
+
components from the `@axinom/mosaic-ui` library and GraphQL schema
|
|
6
|
+
introspection.
|
|
7
|
+
|
|
8
|
+
This skill is SELF-CONTAINED with all conventions, naming patterns, code
|
|
9
|
+
structures, and templates defined in its `references`. The skill's templates
|
|
10
|
+
and conventions are the AUTHORITATIVE source - rely on them as the primary
|
|
11
|
+
guide for all generation decisions.
|
|
12
|
+
|
|
13
|
+
use the `get_skill_references` to retrieve ALL reference
|
|
14
|
+
files mentioned in the steps below BEFORE starting any code generation.
|
|
15
|
+
allowed-tools:
|
|
16
|
+
- search_schema
|
|
17
|
+
- get_type_definitions
|
|
18
|
+
- get_query_fields
|
|
19
|
+
- get_mutation_fields
|
|
20
|
+
- get_subscription_fields
|
|
21
|
+
- list_skills
|
|
22
|
+
- get_skill
|
|
23
|
+
- get_skill_references
|
|
24
|
+
- execute_skill
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Generate Details Station
|
|
28
|
+
|
|
29
|
+
## Input
|
|
30
|
+
|
|
31
|
+
**Entity name** (PascalCase): e.g., "Movie", "Product", "ServiceAccount"
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
|
|
35
|
+
Complete details station with:
|
|
36
|
+
|
|
37
|
+
- Details form with query, mutations, field rendering, info panel
|
|
38
|
+
- URL parameter wrapper component
|
|
39
|
+
- Actions hook (delete, navigate to child resources)
|
|
40
|
+
- Breadcrumb resolver
|
|
41
|
+
- Optional image management station (if entity has image capability)
|
|
42
|
+
- Optional video management station (if entity has video capability)
|
|
43
|
+
- Quick edit integration with explorer
|
|
44
|
+
- Route registration
|
|
45
|
+
|
|
46
|
+
## Steps
|
|
47
|
+
|
|
48
|
+
### 1. Discover Project Paths → `../_shared/discovery/discover-paths.md`
|
|
49
|
+
|
|
50
|
+
Discover: schema path, apollo client, generated types path, workflows path,
|
|
51
|
+
service name
|
|
52
|
+
|
|
53
|
+
### 2. Extract Entity Features → `../_shared/discovery/extract-entity-features.md`
|
|
54
|
+
|
|
55
|
+
Extract `EntityFeatures` from schema using MCP tools (fields, associations,
|
|
56
|
+
capabilities, mutations)
|
|
57
|
+
|
|
58
|
+
### 3. Generate GraphQL Operations → `refs/templates/graphql-operations.md`
|
|
59
|
+
|
|
60
|
+
Generate `.graphql` file with entity query, update/delete mutations, search
|
|
61
|
+
queries for autocomplete
|
|
62
|
+
|
|
63
|
+
### 4. Run Codegen → `../_shared/actions/typescript-codegen.md`
|
|
64
|
+
|
|
65
|
+
Generate TypeScript types from GraphQL operations
|
|
66
|
+
|
|
67
|
+
### 5. Generate Form Data Types → `refs/templates/form-data-types.md`
|
|
68
|
+
|
|
69
|
+
Generate form data type extending GraphQL update patch with transformed
|
|
70
|
+
association arrays
|
|
71
|
+
|
|
72
|
+
### 6. Generate Actions Hook → `refs/templates/actions.md`
|
|
73
|
+
|
|
74
|
+
Generate actions hook with delete mutation and navigation to child resources
|
|
75
|
+
|
|
76
|
+
### 7. Generate Details Form
|
|
77
|
+
|
|
78
|
+
#### 7.1. Read Field Component Mapping → `../_shared/conventions/field-component-mapping.md`
|
|
79
|
+
|
|
80
|
+
Reference for component selection rules (String → TextField, Boolean → Checkbox,
|
|
81
|
+
etc.)
|
|
82
|
+
|
|
83
|
+
#### 7.2. Read Field Validation Schema → `../_shared/conventions/field-validation-schema.md`
|
|
84
|
+
|
|
85
|
+
Reference for Yup validation patterns (required, length, format, etc.)
|
|
86
|
+
|
|
87
|
+
#### 7.3. Generate Form Component → `refs/templates/details-form-station.md`
|
|
88
|
+
|
|
89
|
+
Generate main `{Entity}DetailsForm.tsx` with query, mutations, field rendering,
|
|
90
|
+
info panel
|
|
91
|
+
|
|
92
|
+
### 8. Generate Details Wrapper → `refs/templates/details-wrapper.md`
|
|
93
|
+
|
|
94
|
+
Generate `{Entity}Details.tsx` wrapper that extracts URL params and delegates to
|
|
95
|
+
form
|
|
96
|
+
|
|
97
|
+
### 9. Generate Breadcrumb → `refs/templates/breadcrumb.md`
|
|
98
|
+
|
|
99
|
+
Generate async breadcrumb resolver for entity title
|
|
100
|
+
|
|
101
|
+
### 10. Generate Image Management → `refs/templates/managed-integrations/image-management-station.md`
|
|
102
|
+
|
|
103
|
+
Generate image management station
|
|
104
|
+
|
|
105
|
+
### 11. Generate Video Management → `refs/templates/managed-integrations/video-management-station.md`
|
|
106
|
+
|
|
107
|
+
Generate video management station
|
|
108
|
+
|
|
109
|
+
### 12. Integrate with Explorer → `refs/finalization/explorer-integration.md`
|
|
110
|
+
|
|
111
|
+
Integrate details station with explorer: quick edit components, inline actions,
|
|
112
|
+
and navigation URLs
|
|
113
|
+
|
|
114
|
+
### 13. Validate TypeScript → `../_shared/actions/typescript-validation.md`
|
|
115
|
+
|
|
116
|
+
Run `tsc --noEmit` to verify all generated files compile successfully
|
|
117
|
+
|
|
118
|
+
### 14. Register Station → `refs/finalization/station-registration.md`
|
|
119
|
+
|
|
120
|
+
Register details routes, image/video routes, and breadcrumbs in
|
|
121
|
+
registrations.tsx
|
|
122
|
+
|
|
123
|
+
### 15. Print Summary → `../_shared/actions/execution-summary.md`
|
|
124
|
+
|
|
125
|
+
Display execution summary with generated files, configuration, routes, TODOs
|