@strapi/plugin-documentation 0.0.0-dd35ac75ffdafc147b268d5db2bb95dd25e28457 → 0.0.0-de3d4081f5
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/admin/src/translations/sv.json +39 -0
- package/package.json +7 -7
- package/server/services/documentation.js +3 -2
- package/server/services/helpers/build-api-endpoint-path.js +1 -1
- package/server/services/helpers/build-component-schema.js +75 -18
- package/server/services/helpers/utils/clean-schema-attributes.js +49 -26
- package/server/services/helpers/utils/get-schema-data.js +2 -2
- package/server/services/helpers/utils/query-params.js +11 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"coming-soon": "Det här innehållet är för närvarande under uppbyggnad och kommer tillbaka om några veckor!",
|
|
3
|
+
"components.Row.open": "Öppen",
|
|
4
|
+
"components.Row.regenerate": "Återskapa",
|
|
5
|
+
"containers.HomePage.Block.title": "Versioner",
|
|
6
|
+
"containers.HomePage.Button.update": "Uppdatera",
|
|
7
|
+
"containers.HomePage.PluginHeader.title": "Dokumentation - Inställningar",
|
|
8
|
+
"containers.HomePage.PopUpWarning.confirm": "Jag förstår",
|
|
9
|
+
"containers.HomePage.PopUpWarning.message": "Är du säker på att du vill ta bort denna versionen?",
|
|
10
|
+
"containers.HomePage.copied": "Token har kopierats till urklipp",
|
|
11
|
+
"containers.HomePage.form.jwtToken": "Hämta din jwt-token",
|
|
12
|
+
"containers.HomePage.form.jwtToken.description": "Kopiera denna token och använd den i swagger för att göra förfrågningar",
|
|
13
|
+
"containers.HomePage.form.password": "Lösenord",
|
|
14
|
+
"containers.HomePage.form.password.inputDescription": "Ställ in lösenordet som ska behövas för att komma åt dokumentationen",
|
|
15
|
+
"containers.HomePage.form.restrictedAccess": "Begränsad åtkomst",
|
|
16
|
+
"containers.HomePage.form.restrictedAccess.inputDescription": "Gör dokumentationensrutten privat. Som standard är åtkomsten publik",
|
|
17
|
+
"containers.HomePage.form.showGeneratedFiles": "Visa genererade filer",
|
|
18
|
+
"containers.HomePage.form.showGeneratedFiles.inputDescription": "Användbart när du vill överskrida den automatiskt genererade dokumentationen. \nPluginet genererar filer uppdelade efter modell och plugin. \nGenom att aktivera det här blir det lättare att anpassa din dokumentation",
|
|
19
|
+
"error.deleteDoc.versionMissing": "Den version du försöker ta bort finns inte.",
|
|
20
|
+
"error.noVersion": "En version krävs",
|
|
21
|
+
"error.regenerateDoc": "Ett fel uppstod när dokumentet återskapades",
|
|
22
|
+
"error.regenerateDoc.versionMissing": "Den version du försöker generera finns inte",
|
|
23
|
+
"notification.delete.success": "Dokument raderat",
|
|
24
|
+
"notification.generate.success": "Dokument genererat",
|
|
25
|
+
"notification.update.success": "Inställningarna har uppdaterats",
|
|
26
|
+
"pages.PluginPage.Button.open": "Öppna dokumentation",
|
|
27
|
+
"pages.PluginPage.header.description": "Konfigurera dokumentationspluginet",
|
|
28
|
+
"pages.PluginPage.table.generated": "Senast genererade",
|
|
29
|
+
"pages.PluginPage.table.icon.regenerate": "Återskapa {target}",
|
|
30
|
+
"pages.PluginPage.table.icon.show": "Öppna {target}",
|
|
31
|
+
"pages.PluginPage.table.version": "Version",
|
|
32
|
+
"pages.SettingsPage.Button.description": "Konfigurera dokumentationspluginet",
|
|
33
|
+
"pages.SettingsPage.header.save": "Spara",
|
|
34
|
+
"pages.SettingsPage.toggle.hint": "Gör dokumentationensrutten privat",
|
|
35
|
+
"pages.SettingsPage.toggle.label": "Begränsad åtkomst",
|
|
36
|
+
"plugin.description.long": "Skapa ett OpenAPI-dokument och visualisera din API med SWAGGER UI.",
|
|
37
|
+
"plugin.description.short": "Skapa ett OpenAPI-dokument och visualisera din API med SWAGGER UI.",
|
|
38
|
+
"plugin.name": "Dokumentation"
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-documentation",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-de3d4081f5",
|
|
4
4
|
"description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test": "echo \"no tests yet\""
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@strapi/helper-plugin": "0.0.0-
|
|
28
|
-
"@strapi/utils": "0.0.0-
|
|
27
|
+
"@strapi/helper-plugin": "0.0.0-de3d4081f5",
|
|
28
|
+
"@strapi/utils": "0.0.0-de3d4081f5",
|
|
29
29
|
"bcryptjs": "2.4.3",
|
|
30
30
|
"cheerio": "^1.0.0-rc.12",
|
|
31
31
|
"fs-extra": "10.0.0",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"react": "^17.0.2",
|
|
37
37
|
"react-copy-to-clipboard": "^5.1.0",
|
|
38
38
|
"react-dom": "^17.0.2",
|
|
39
|
-
"react-intl": "5.
|
|
39
|
+
"react-intl": "5.25.1",
|
|
40
40
|
"react-redux": "7.2.8",
|
|
41
41
|
"react-router": "^5.2.0",
|
|
42
42
|
"react-router-dom": "5.2.0",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"@strapi/strapi": "^4.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@testing-library/react": "
|
|
52
|
+
"@testing-library/react": "12.1.4",
|
|
53
53
|
"msw": "0.42.3"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
|
-
"node": ">=14.19.1 <=
|
|
56
|
+
"node": ">=14.19.1 <=18.x.x",
|
|
57
57
|
"npm": ">=6.0.0"
|
|
58
58
|
},
|
|
59
59
|
"strapi": {
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
|
|
63
63
|
"kind": "plugin"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "de3d4081f5b32a6b265f993384f30c5b7b3ffcf7"
|
|
66
66
|
}
|
|
@@ -15,12 +15,13 @@ module.exports = ({ strapi }) => {
|
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
17
|
registerDoc(doc) {
|
|
18
|
+
let registeredDoc = doc;
|
|
18
19
|
// parseYaml
|
|
19
20
|
if (typeof doc === 'string') {
|
|
20
|
-
|
|
21
|
+
registeredDoc = require('yaml').parse(registeredDoc);
|
|
21
22
|
}
|
|
22
23
|
// receive an object we can register it directly
|
|
23
|
-
registeredDocs.push(
|
|
24
|
+
registeredDocs.push(registeredDoc);
|
|
24
25
|
},
|
|
25
26
|
getDocumentationVersion() {
|
|
26
27
|
return _.get(config, 'info.version');
|
|
@@ -20,6 +20,18 @@ const { hasFindMethod, isLocalizedPath } = require('./utils/routes');
|
|
|
20
20
|
const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
21
21
|
// Store response and request schemas in an object
|
|
22
22
|
let schemas = {};
|
|
23
|
+
let componentSchemas = {};
|
|
24
|
+
// adds a ComponentSchema to the Schemas so it can be used as Ref
|
|
25
|
+
const addComponentSchema = (schemaName, schema) => {
|
|
26
|
+
if (!Object.keys(schema) || !Object.keys(schema.properties)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
componentSchemas = {
|
|
30
|
+
...componentSchemas,
|
|
31
|
+
[schemaName]: schema,
|
|
32
|
+
};
|
|
33
|
+
return true;
|
|
34
|
+
};
|
|
23
35
|
// Get all the route methods
|
|
24
36
|
const routeMethods = routeInfo.routes.map((route) => route.method);
|
|
25
37
|
// Check for localized paths
|
|
@@ -56,7 +68,10 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
|
56
68
|
[`${pascalCase(uniqueName)}LocalizationRequest`]: {
|
|
57
69
|
required: [...requiredAttributes, 'locale'],
|
|
58
70
|
type: 'object',
|
|
59
|
-
properties: cleanSchemaAttributes(attributesForRequest, {
|
|
71
|
+
properties: cleanSchemaAttributes(attributesForRequest, {
|
|
72
|
+
isRequest: true,
|
|
73
|
+
addComponentSchema,
|
|
74
|
+
}),
|
|
60
75
|
},
|
|
61
76
|
};
|
|
62
77
|
}
|
|
@@ -71,7 +86,10 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
|
71
86
|
data: {
|
|
72
87
|
required: requiredAttributes,
|
|
73
88
|
type: 'object',
|
|
74
|
-
properties: cleanSchemaAttributes(attributesForRequest, {
|
|
89
|
+
properties: cleanSchemaAttributes(attributesForRequest, {
|
|
90
|
+
isRequest: true,
|
|
91
|
+
addComponentSchema,
|
|
92
|
+
}),
|
|
75
93
|
},
|
|
76
94
|
},
|
|
77
95
|
},
|
|
@@ -84,8 +102,8 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
|
84
102
|
[`${pascalCase(uniqueName)}LocalizationResponse`]: {
|
|
85
103
|
type: 'object',
|
|
86
104
|
properties: {
|
|
87
|
-
id: { type: '
|
|
88
|
-
...cleanSchemaAttributes(attributes),
|
|
105
|
+
id: { type: 'number' },
|
|
106
|
+
...cleanSchemaAttributes(attributes, { addComponentSchema }),
|
|
89
107
|
},
|
|
90
108
|
},
|
|
91
109
|
};
|
|
@@ -97,17 +115,37 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
|
97
115
|
// Build the list response schema
|
|
98
116
|
schemas = {
|
|
99
117
|
...schemas,
|
|
100
|
-
[`${pascalCase(uniqueName)}
|
|
118
|
+
[`${pascalCase(uniqueName)}ListResponseDataItem`]: {
|
|
101
119
|
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
id: { type: 'number' },
|
|
122
|
+
attributes: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: cleanSchemaAttributes(attributes, {
|
|
125
|
+
addComponentSchema,
|
|
126
|
+
componentSchemaRefName: `#/components/schemas/${pascalCase(
|
|
127
|
+
uniqueName
|
|
128
|
+
)}ListResponseDataItemLocalized`,
|
|
129
|
+
}),
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
[`${pascalCase(uniqueName)}ListResponseDataItemLocalized`]: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
id: { type: 'number' },
|
|
137
|
+
attributes: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
[`${pascalCase(uniqueName)}ListResponse`]: {
|
|
102
144
|
properties: {
|
|
103
145
|
data: {
|
|
104
146
|
type: 'array',
|
|
105
147
|
items: {
|
|
106
|
-
|
|
107
|
-
properties: {
|
|
108
|
-
id: { type: 'string' },
|
|
109
|
-
attributes: { type: 'object', properties: cleanSchemaAttributes(attributes) },
|
|
110
|
-
},
|
|
148
|
+
$ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponseDataItem`,
|
|
111
149
|
},
|
|
112
150
|
},
|
|
113
151
|
meta: {
|
|
@@ -131,22 +169,41 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
|
131
169
|
// Build the response schema
|
|
132
170
|
schemas = {
|
|
133
171
|
...schemas,
|
|
134
|
-
[`${pascalCase(uniqueName)}
|
|
172
|
+
[`${pascalCase(uniqueName)}ResponseDataObject`]: {
|
|
135
173
|
type: 'object',
|
|
136
174
|
properties: {
|
|
137
|
-
|
|
175
|
+
id: { type: 'number' },
|
|
176
|
+
attributes: {
|
|
138
177
|
type: 'object',
|
|
139
|
-
properties: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
178
|
+
properties: cleanSchemaAttributes(attributes, {
|
|
179
|
+
addComponentSchema,
|
|
180
|
+
componentSchemaRefName: `#/components/schemas/${pascalCase(
|
|
181
|
+
uniqueName
|
|
182
|
+
)}ResponseDataObjectLocalized`,
|
|
183
|
+
}),
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
[`${pascalCase(uniqueName)}ResponseDataObjectLocalized`]: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
id: { type: 'number' },
|
|
191
|
+
attributes: {
|
|
192
|
+
type: 'object',
|
|
193
|
+
properties: cleanSchemaAttributes(attributes, { addComponentSchema }),
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
[`${pascalCase(uniqueName)}Response`]: {
|
|
198
|
+
properties: {
|
|
199
|
+
data: {
|
|
200
|
+
$ref: `#/components/schemas/${pascalCase(uniqueName)}ResponseDataObject`,
|
|
143
201
|
},
|
|
144
202
|
meta: { type: 'object' },
|
|
145
203
|
},
|
|
146
204
|
},
|
|
147
205
|
};
|
|
148
|
-
|
|
149
|
-
return schemas;
|
|
206
|
+
return { ...schemas, ...componentSchemas };
|
|
150
207
|
};
|
|
151
208
|
|
|
152
209
|
const buildComponentSchema = (api) => {
|
|
@@ -2,15 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const getSchemaData = require('./get-schema-data');
|
|
5
|
-
|
|
5
|
+
const pascalCase = require('./pascal-case');
|
|
6
6
|
/**
|
|
7
7
|
* @description - Converts types found on attributes to OpenAPI acceptable data types
|
|
8
8
|
*
|
|
9
9
|
* @param {object} attributes - The attributes found on a contentType
|
|
10
|
-
* @param {{ typeMap: Map, isRequest: boolean }} opts
|
|
10
|
+
* @param {{ typeMap: Map, isRequest: boolean, addComponentSchema: function, componentSchemaRefName: string }} opts
|
|
11
11
|
* @returns Attributes using OpenAPI acceptable data types
|
|
12
12
|
*/
|
|
13
|
-
const cleanSchemaAttributes = (
|
|
13
|
+
const cleanSchemaAttributes = (
|
|
14
|
+
attributes,
|
|
15
|
+
{
|
|
16
|
+
typeMap = new Map(),
|
|
17
|
+
isRequest = false,
|
|
18
|
+
addComponentSchema = () => {},
|
|
19
|
+
componentSchemaRefName = '',
|
|
20
|
+
} = {}
|
|
21
|
+
) => {
|
|
14
22
|
const attributesCopy = _.cloneDeep(attributes);
|
|
15
23
|
|
|
16
24
|
for (const prop of Object.keys(attributesCopy)) {
|
|
@@ -86,43 +94,53 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa
|
|
|
86
94
|
}
|
|
87
95
|
case 'component': {
|
|
88
96
|
const componentAttributes = strapi.components[attribute.component].attributes;
|
|
89
|
-
|
|
97
|
+
const rawComponentSchema = {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
...(isRequest ? {} : { id: { type: 'number' } }),
|
|
101
|
+
...cleanSchemaAttributes(componentAttributes, {
|
|
102
|
+
typeMap,
|
|
103
|
+
isRequest,
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const refComponentSchema = {
|
|
108
|
+
$ref: `#/components/schemas/${pascalCase(attribute.component)}Component`,
|
|
109
|
+
};
|
|
110
|
+
const componentExists = addComponentSchema(
|
|
111
|
+
`${pascalCase(attribute.component)}Component`,
|
|
112
|
+
rawComponentSchema
|
|
113
|
+
);
|
|
114
|
+
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
|
90
115
|
if (attribute.repeatable) {
|
|
91
116
|
attributesCopy[prop] = {
|
|
92
117
|
type: 'array',
|
|
93
|
-
items:
|
|
94
|
-
type: 'object',
|
|
95
|
-
properties: {
|
|
96
|
-
...(isRequest ? {} : { id: { type: 'string' } }),
|
|
97
|
-
...cleanSchemaAttributes(componentAttributes, { typeMap, isRequest }),
|
|
98
|
-
},
|
|
99
|
-
},
|
|
118
|
+
items: finalComponentSchema,
|
|
100
119
|
};
|
|
101
120
|
} else {
|
|
102
|
-
attributesCopy[prop] =
|
|
103
|
-
type: 'object',
|
|
104
|
-
properties: {
|
|
105
|
-
...(isRequest ? {} : { id: { type: 'string' } }),
|
|
106
|
-
...cleanSchemaAttributes(componentAttributes, {
|
|
107
|
-
typeMap,
|
|
108
|
-
isRequest,
|
|
109
|
-
}),
|
|
110
|
-
},
|
|
111
|
-
};
|
|
121
|
+
attributesCopy[prop] = finalComponentSchema;
|
|
112
122
|
}
|
|
113
123
|
break;
|
|
114
124
|
}
|
|
115
125
|
case 'dynamiczone': {
|
|
116
126
|
const components = attribute.components.map((component) => {
|
|
117
127
|
const componentAttributes = strapi.components[component].attributes;
|
|
118
|
-
|
|
128
|
+
const rawComponentSchema = {
|
|
119
129
|
type: 'object',
|
|
120
130
|
properties: {
|
|
121
|
-
...(isRequest ? {} : { id: { type: '
|
|
131
|
+
...(isRequest ? {} : { id: { type: 'number' } }),
|
|
122
132
|
__component: { type: 'string' },
|
|
123
|
-
...cleanSchemaAttributes(componentAttributes, {
|
|
133
|
+
...cleanSchemaAttributes(componentAttributes, {
|
|
134
|
+
typeMap,
|
|
135
|
+
isRequest,
|
|
136
|
+
addComponentSchema,
|
|
137
|
+
}),
|
|
124
138
|
},
|
|
125
139
|
};
|
|
140
|
+
const refComponentSchema = { $ref: `#/components/schemas/${pascalCase(component)}` };
|
|
141
|
+
const componentExists = addComponentSchema(pascalCase(component), rawComponentSchema);
|
|
142
|
+
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
|
143
|
+
return finalComponentSchema;
|
|
126
144
|
});
|
|
127
145
|
|
|
128
146
|
attributesCopy[prop] = {
|
|
@@ -171,8 +189,13 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa
|
|
|
171
189
|
|
|
172
190
|
if (prop === 'localizations') {
|
|
173
191
|
attributesCopy[prop] = {
|
|
174
|
-
type: '
|
|
175
|
-
|
|
192
|
+
type: 'object',
|
|
193
|
+
properties: {
|
|
194
|
+
data: {
|
|
195
|
+
type: 'array',
|
|
196
|
+
items: componentSchemaRefName.length ? { $ref: componentSchemaRefName } : {},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
176
199
|
};
|
|
177
200
|
break;
|
|
178
201
|
}
|
|
@@ -15,7 +15,7 @@ module.exports = (isListOfEntities, attributes) => {
|
|
|
15
15
|
items: {
|
|
16
16
|
type: 'object',
|
|
17
17
|
properties: {
|
|
18
|
-
id: { type: '
|
|
18
|
+
id: { type: 'number' },
|
|
19
19
|
attributes: { type: 'object', properties: attributes },
|
|
20
20
|
},
|
|
21
21
|
},
|
|
@@ -25,7 +25,7 @@ module.exports = (isListOfEntities, attributes) => {
|
|
|
25
25
|
return {
|
|
26
26
|
type: 'object',
|
|
27
27
|
properties: {
|
|
28
|
-
id: { type: '
|
|
28
|
+
id: { type: 'number' },
|
|
29
29
|
attributes: { type: 'object', properties: attributes },
|
|
30
30
|
},
|
|
31
31
|
};
|