mirror of
https://github.com/strapi/strapi.git
synced 2025-10-29 17:04:13 +00:00
add frontend views (#11267)
This commit is contained in:
parent
6e5be7ac49
commit
39b76f140a
@ -0,0 +1,14 @@
|
||||
import styled from 'styled-components';
|
||||
import { FieldAction } from '@strapi/parts/Field';
|
||||
|
||||
const FieldActionWrapper = styled(FieldAction)`
|
||||
svg {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
path {
|
||||
fill: ${({ theme }) => theme.colors.neutral600};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default FieldActionWrapper;
|
||||
@ -25,7 +25,9 @@ export default {
|
||||
},
|
||||
permissions: pluginPermissions.main,
|
||||
Component: async () => {
|
||||
const component = await import(/* webpackChunkName: "documentation-page" */ './pages/App');
|
||||
const component = await import(
|
||||
/* webpackChunkName: "documentation-page" */ './pages/PluginPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
@ -41,7 +43,24 @@ export default {
|
||||
pluginLogo,
|
||||
});
|
||||
},
|
||||
bootstrap() {},
|
||||
bootstrap(app) {
|
||||
app.addSettingsLink('global', {
|
||||
intlLabel: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
defaultMessage: 'Documentation',
|
||||
},
|
||||
id: 'documentation',
|
||||
to: `/settings/${pluginId}`,
|
||||
Component: async () => {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "documentation-settings" */ './pages/SettingsPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
permissions: pluginPermissions.main,
|
||||
});
|
||||
},
|
||||
async registerTrads({ locales }) {
|
||||
const importedTrads = await Promise.all(
|
||||
locales.map(locale => {
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* This component is the skeleton around the actual pages, and should only
|
||||
* contain code that should be seen on all pages. (e.g. navigation bar)
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { CheckPagePermissions, NoContent } from '@strapi/helper-plugin';
|
||||
import { Layout, HeaderLayout, ContentLayout } from '@strapi/parts/Layout';
|
||||
import { Main } from '@strapi/parts/Main';
|
||||
import pluginPermissions from '../../permissions';
|
||||
import { getTrad } from '../../utils';
|
||||
// import HomePage from '../HomePage';
|
||||
|
||||
const ComingSoon = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Main>
|
||||
<HeaderLayout
|
||||
title={formatMessage({
|
||||
id: getTrad('plugin.name'),
|
||||
defaultMessage: 'Documentation',
|
||||
})}
|
||||
/>
|
||||
<ContentLayout>
|
||||
<NoContent
|
||||
content={{
|
||||
id: getTrad('coming.soon'),
|
||||
defaultMessage:
|
||||
'This content is currently under construction and will be back in a few weeks!',
|
||||
}}
|
||||
/>
|
||||
</ContentLayout>
|
||||
</Main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<CheckPagePermissions permissions={pluginPermissions.main}>
|
||||
{/* <HomePage /> */}
|
||||
<ComingSoon />
|
||||
</CheckPagePermissions>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@ -90,8 +90,6 @@ const HomePage = () => {
|
||||
setVersionToDelete(null);
|
||||
};
|
||||
|
||||
console.log(data);
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingIndicatorPage />;
|
||||
}
|
||||
|
||||
193
packages/plugins/documentation/admin/src/pages/PluginPage/index.js
Executable file
193
packages/plugins/documentation/admin/src/pages/PluginPage/index.js
Executable file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
*
|
||||
* This component is the skeleton around the actual pages, and should only
|
||||
* contain code that should be seen on all pages. (e.g. navigation bar)
|
||||
*
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import {
|
||||
CheckPermissions,
|
||||
ConfirmDialog,
|
||||
LoadingIndicatorPage,
|
||||
stopPropagation,
|
||||
EmptyStateLayout,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { Button } from '@strapi/parts/Button';
|
||||
import { Layout, HeaderLayout, ContentLayout } from '@strapi/parts/Layout';
|
||||
import { Main } from '@strapi/parts/Main';
|
||||
import { IconButton } from '@strapi/parts/IconButton';
|
||||
import { Text, TableLabel } from '@strapi/parts/Text';
|
||||
import { Row } from '@strapi/parts/Row';
|
||||
import { Table, Tr, Thead, Th, Tbody, Td } from '@strapi/parts/Table';
|
||||
|
||||
import DeleteIcon from '@strapi/icons/DeleteIcon';
|
||||
import Show from '@strapi/icons/Show';
|
||||
import Reload from '@strapi/icons/Reload';
|
||||
|
||||
import permissions from '../../permissions';
|
||||
import { getTrad } from '../../utils';
|
||||
import openWithNewTab from '../../utils/openWithNewTab';
|
||||
import useReactQuery from '../utils/useReactQuery';
|
||||
|
||||
const PluginPage = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { data, isLoading, deleteMutation, regenerateDocMutation } = useReactQuery();
|
||||
const [showConfirmDelete, setShowConfirmDelete] = useState(false);
|
||||
const [isConfirmButtonLoading, setIsConfirmButtonLoading] = useState(false);
|
||||
const [versionToDelete, setVersionToDelete] = useState();
|
||||
|
||||
const colCount = 4;
|
||||
const rowCount = (data?.docVersions?.length || 0) + 1;
|
||||
|
||||
const openDocVersion = () => {
|
||||
const slash = data?.prefix.startsWith('/') ? '' : '/';
|
||||
openWithNewTab(`${slash}${data?.prefix}/v${data?.currentVersion}`);
|
||||
};
|
||||
|
||||
const handleRegenerateDoc = version => {
|
||||
regenerateDocMutation.mutate({ version, prefix: data?.prefix });
|
||||
};
|
||||
|
||||
const handleShowConfirmDelete = () => {
|
||||
setShowConfirmDelete(!showConfirmDelete);
|
||||
};
|
||||
|
||||
const handleConfirmDelete = async () => {
|
||||
setIsConfirmButtonLoading(true);
|
||||
await deleteMutation.mutateAsync({ prefix: data?.prefix, version: versionToDelete });
|
||||
setShowConfirmDelete(!showConfirmDelete);
|
||||
setIsConfirmButtonLoading(false);
|
||||
};
|
||||
|
||||
const handleClickDelete = version => {
|
||||
setVersionToDelete(version);
|
||||
setShowConfirmDelete(!showConfirmDelete);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Main>
|
||||
<HeaderLayout
|
||||
title={formatMessage({
|
||||
id: getTrad('plugin.name'),
|
||||
defaultMessage: 'Documentation',
|
||||
})}
|
||||
subtitle={formatMessage({
|
||||
id: getTrad('pages.PluginPage.header.description'),
|
||||
defaultMessage: 'Configure the documentation plugin',
|
||||
})}
|
||||
primaryAction={
|
||||
// eslint-disable-next-line
|
||||
<CheckPermissions permissions={permissions.open}>
|
||||
<Button onClick={openDocVersion} startIcon={<Show />}>
|
||||
{formatMessage({
|
||||
id: getTrad('pages.PluginPage.Button.open'),
|
||||
defaultMessage: 'Open Documentation',
|
||||
})}
|
||||
</Button>
|
||||
</CheckPermissions>
|
||||
}
|
||||
/>
|
||||
<ContentLayout>
|
||||
{isLoading && <LoadingIndicatorPage>Plugin is loading</LoadingIndicatorPage>}
|
||||
{data?.docVersions.length ? (
|
||||
<Table colCount={colCount} rowCount={rowCount}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: getTrad('pages.PluginPage.table.version'),
|
||||
defaultMessage: 'Version',
|
||||
})}
|
||||
</TableLabel>
|
||||
</Th>
|
||||
<Th>
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: getTrad('pages.PluginPage.table.generated'),
|
||||
defaultMessage: 'Last Generated',
|
||||
})}
|
||||
</TableLabel>
|
||||
</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{data.docVersions
|
||||
.sort((a, b) => (a.generatedDate < b.generatedDate ? 1 : -1))
|
||||
.map(doc => (
|
||||
<Tr key={doc.version}>
|
||||
<Td width="50%">
|
||||
<Text>{doc.version}</Text>
|
||||
</Td>
|
||||
<Td width="50%">
|
||||
<Text>{doc.generatedDate}</Text>
|
||||
</Td>
|
||||
<Td>
|
||||
<Row justifyContent="end" {...stopPropagation}>
|
||||
<IconButton
|
||||
onClick={openDocVersion}
|
||||
noBorder
|
||||
icon={<Show />}
|
||||
label={formatMessage(
|
||||
{
|
||||
id: getTrad('pages.PluginPage.table.icon.show'),
|
||||
defaultMessage: 'Open {target}',
|
||||
},
|
||||
{ target: `${doc.version}` }
|
||||
)}
|
||||
/>
|
||||
<CheckPermissions permissions={permissions.regenerate}>
|
||||
<IconButton
|
||||
onClick={() => handleRegenerateDoc(doc.version)}
|
||||
noBorder
|
||||
icon={<Reload />}
|
||||
label={formatMessage(
|
||||
{
|
||||
id: getTrad('pages.PluginPage.table.icon.regenerate'),
|
||||
defaultMessage: 'Regnerate {target}',
|
||||
},
|
||||
{ target: `${doc.version}` }
|
||||
)}
|
||||
/>
|
||||
</CheckPermissions>
|
||||
<CheckPermissions permissions={permissions.update}>
|
||||
{doc.version !== data.currentVersion && (
|
||||
<IconButton
|
||||
onClick={() => handleClickDelete(doc.version)}
|
||||
noBorder
|
||||
icon={<DeleteIcon />}
|
||||
label={formatMessage(
|
||||
{
|
||||
id: getTrad('pages.PluginPage.table.icon.delete'),
|
||||
defaultMessage: 'Delete {target}',
|
||||
},
|
||||
{ target: `${doc.version}` }
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</CheckPermissions>
|
||||
</Row>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
) : (
|
||||
<EmptyStateLayout />
|
||||
)}
|
||||
</ContentLayout>
|
||||
<ConfirmDialog
|
||||
isConfirmButtonLoading={isConfirmButtonLoading}
|
||||
onConfirm={handleConfirmDelete}
|
||||
onToggleDialog={handleShowConfirmDelete}
|
||||
isOpen={showConfirmDelete}
|
||||
/>
|
||||
</Main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default PluginPage;
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
|
||||
const handlers = [
|
||||
rest.get('*/getInfos', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.delay(1000),
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
currentVersion: '1.0.0',
|
||||
docVersions: [
|
||||
{ version: '1.0.0', generatedDoc: '10/05/2021 2:52:44 PM' },
|
||||
{ version: '1.2.0', generatedDoc: '11/05/2021 3:00:00 PM' },
|
||||
],
|
||||
prefix: '/documentation',
|
||||
})
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
const server = setupServer(...handlers);
|
||||
|
||||
export default server;
|
||||
@ -0,0 +1,169 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Formik } from 'formik';
|
||||
import { CheckPermissions, Form, LoadingIndicatorPage } from '@strapi/helper-plugin';
|
||||
|
||||
// Strapi Parts
|
||||
import { ContentLayout, HeaderLayout } from '@strapi/parts/Layout';
|
||||
import { Main } from '@strapi/parts/Main';
|
||||
import { Button } from '@strapi/parts/Button';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
import { Stack } from '@strapi/parts/Stack';
|
||||
import { H3 } from '@strapi/parts/Text';
|
||||
import { ToggleInput } from '@strapi/parts/ToggleInput';
|
||||
import { TextInput } from '@strapi/parts/TextInput';
|
||||
import { Grid, GridItem } from '@strapi/parts/Grid';
|
||||
|
||||
// Strapi Icons
|
||||
import Show from '@strapi/icons/Show';
|
||||
import Hide from '@strapi/icons/Hide';
|
||||
import Check from '@strapi/icons/Check';
|
||||
|
||||
import permissions from '../../permissions';
|
||||
import { getTrad } from '../../utils';
|
||||
import useReactQuery from '../utils/useReactQuery';
|
||||
import FieldActionWrapper from '../../components/FieldActionWrapper';
|
||||
import schema from '../utils/schema';
|
||||
|
||||
const SettingsPage = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { submitMutation, data, isLoading } = useReactQuery();
|
||||
const [passwordShown, setPasswordShown] = useState(false);
|
||||
|
||||
const handleUpdateSettingsSubmit = body => {
|
||||
submitMutation.mutate({
|
||||
prefix: data?.prefix,
|
||||
body,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Main>
|
||||
{isLoading ? (
|
||||
<LoadingIndicatorPage>Plugin settings are loading</LoadingIndicatorPage>
|
||||
) : (
|
||||
<Formik
|
||||
initialValues={{
|
||||
restrictedAccess: data?.documentationAccess.restrictedAccess || false,
|
||||
password: data?.documentationAccess.password,
|
||||
}}
|
||||
onSubmit={handleUpdateSettingsSubmit}
|
||||
validationSchema={schema}
|
||||
>
|
||||
{({ handleSubmit, values, handleChange, errors }) => {
|
||||
return (
|
||||
<Form noValidate onSubmit={handleSubmit}>
|
||||
<HeaderLayout
|
||||
title={formatMessage({
|
||||
id: getTrad('plugin.name'),
|
||||
defaultMessage: 'Documentation',
|
||||
})}
|
||||
subtitle={formatMessage({
|
||||
id: getTrad('pages.SettingsPage.header.description'),
|
||||
defaultMessage: 'Configure the documentation plugin',
|
||||
})}
|
||||
primaryAction={
|
||||
// eslint-disable-next-line
|
||||
<CheckPermissions permissions={permissions.update}>
|
||||
<Button type="submit" startIcon={<Check />}>
|
||||
{formatMessage({
|
||||
id: getTrad('pages.SettingsPage.Button.save'),
|
||||
defaultMessage: 'Save',
|
||||
})}
|
||||
</Button>
|
||||
</CheckPermissions>
|
||||
}
|
||||
/>
|
||||
<ContentLayout>
|
||||
<Box
|
||||
background="neutral0"
|
||||
hasRadius
|
||||
shadow="filterShadow"
|
||||
paddingTop={6}
|
||||
paddingBottom={6}
|
||||
paddingLeft={7}
|
||||
paddingRight={7}
|
||||
>
|
||||
<Stack size={4}>
|
||||
<H3 as="h2">
|
||||
{formatMessage({
|
||||
id: getTrad('pages.SettingsPage.title'),
|
||||
defaultMessage: 'Settings',
|
||||
})}
|
||||
</H3>
|
||||
<Grid gap={4}>
|
||||
<GridItem col={6} s={12}>
|
||||
<ToggleInput
|
||||
name="restrictedAccess"
|
||||
label={formatMessage({
|
||||
id: getTrad('pages.SettingsPage.toggle.label'),
|
||||
defaultMessage: 'Restricted Access',
|
||||
})}
|
||||
hint={formatMessage({
|
||||
id: getTrad('pages.SettingsPage.toggle.hint'),
|
||||
defaultMessage: 'Make the documentation endpoint private',
|
||||
})}
|
||||
checked={values.restrictedAccess}
|
||||
onChange={handleChange}
|
||||
onLabel="On"
|
||||
offLabel="Off"
|
||||
/>
|
||||
</GridItem>
|
||||
{values.restrictedAccess && (
|
||||
<GridItem col={6} s={12}>
|
||||
<TextInput
|
||||
label={formatMessage({
|
||||
id: getTrad('pages.SettingsPage.password.label'),
|
||||
defaultMessage: 'Password',
|
||||
})}
|
||||
name="password"
|
||||
type={passwordShown ? 'text' : 'password'}
|
||||
value={values.password}
|
||||
onChange={handleChange}
|
||||
error={
|
||||
errors.password
|
||||
? formatMessage({
|
||||
id: errors.password,
|
||||
defaultMessage: 'Invalid value',
|
||||
})
|
||||
: null
|
||||
}
|
||||
endAction={
|
||||
// eslint-disable-next-line
|
||||
<FieldActionWrapper
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setPasswordShown(prev => !prev);
|
||||
}}
|
||||
label={formatMessage(
|
||||
passwordShown
|
||||
? {
|
||||
id: 'Auth.form.password.show-password',
|
||||
defaultMessage: 'Show password',
|
||||
}
|
||||
: {
|
||||
id: 'Auth.form.password.hide-password',
|
||||
defaultMessage: 'Hide password',
|
||||
}
|
||||
)}
|
||||
>
|
||||
{passwordShown ? <Show /> : <Hide />}
|
||||
</FieldActionWrapper>
|
||||
}
|
||||
/>
|
||||
</GridItem>
|
||||
)}
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Box>
|
||||
</ContentLayout>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
)}
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsPage;
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,18 @@
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
|
||||
const handlers = [
|
||||
rest.get('*/getInfos', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.delay(1000),
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
documentationAccess: { restrictedAccess: false, password: '' },
|
||||
})
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
const server = setupServer(...handlers);
|
||||
|
||||
export default server;
|
||||
31
packages/plugins/documentation/admin/src/pages/utils/api.js
Normal file
31
packages/plugins/documentation/admin/src/pages/utils/api.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { request } from '@strapi/helper-plugin';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
const deleteDoc = ({ prefix, version }) => {
|
||||
return request(`${prefix}/deleteDoc/${version}`, { method: 'DELETE' });
|
||||
};
|
||||
|
||||
const fetchDocumentationVersions = async toggleNotification => {
|
||||
try {
|
||||
const data = await request(`/${pluginId}/getInfos`, { method: 'GET' });
|
||||
|
||||
return data;
|
||||
} catch (err) {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: { id: 'notification.error' },
|
||||
});
|
||||
|
||||
// FIXME
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const regenerateDoc = ({ prefix, version }) => {
|
||||
return request(`${prefix}/regenerateDoc`, { method: 'POST', body: { version } });
|
||||
};
|
||||
|
||||
const updateSettings = ({ prefix, body }) =>
|
||||
request(`${prefix}/updateSettings`, { method: 'PUT', body });
|
||||
|
||||
export { deleteDoc, fetchDocumentationVersions, regenerateDoc, updateSettings };
|
||||
@ -0,0 +1,11 @@
|
||||
import { translatedErrors } from '@strapi/helper-plugin';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const schema = yup.object().shape({
|
||||
restrictedAccess: yup.boolean(),
|
||||
password: yup.string().when('restrictedAccess', (value, initSchema) => {
|
||||
return value ? initSchema.required(translatedErrors.required) : initSchema;
|
||||
}),
|
||||
});
|
||||
|
||||
export default schema;
|
||||
@ -0,0 +1,46 @@
|
||||
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
||||
import { useNotification } from '@strapi/helper-plugin';
|
||||
import { fetchDocumentationVersions, deleteDoc, regenerateDoc, updateSettings } from './api';
|
||||
import getTrad from '../../utils/getTrad';
|
||||
|
||||
const useReactQuery = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const toggleNotification = useNotification();
|
||||
const { isLoading, data } = useQuery('get-documentation', () =>
|
||||
fetchDocumentationVersions(toggleNotification)
|
||||
);
|
||||
|
||||
const handleError = err => {
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: err.response.payload.message,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSuccess = (type, tradId) => {
|
||||
queryClient.invalidateQueries('get-documentation');
|
||||
toggleNotification({
|
||||
type,
|
||||
message: { id: getTrad(tradId) },
|
||||
});
|
||||
};
|
||||
|
||||
const deleteMutation = useMutation(deleteDoc, {
|
||||
onSuccess: () => handleSuccess('info', 'notification.delete.success'),
|
||||
onError: error => handleError(error),
|
||||
});
|
||||
|
||||
const submitMutation = useMutation(updateSettings, {
|
||||
onSuccess: () => handleSuccess('success', 'notification.update.success'),
|
||||
onError: handleError,
|
||||
});
|
||||
|
||||
const regenerateDocMutation = useMutation(regenerateDoc, {
|
||||
onSuccess: () => handleSuccess('info', 'notification.generate.success'),
|
||||
onError: error => handleError(error),
|
||||
});
|
||||
|
||||
return { data, isLoading, deleteMutation, submitMutation, regenerateDocMutation };
|
||||
};
|
||||
|
||||
export default useReactQuery;
|
||||
@ -1,12 +1,9 @@
|
||||
{
|
||||
"coming-soon": "This content is currently under construction and will be back in a few weeks!",
|
||||
"components.Row.generatedDate": "Last generation",
|
||||
"components.Row.open": "Open",
|
||||
"components.Row.regenerate": "Regenerate",
|
||||
"containers.HomePage.Block.title": "Versions",
|
||||
"containers.HomePage.Button.open": "Open the documentation",
|
||||
"containers.HomePage.Button.update": "Update",
|
||||
"containers.HomePage.PluginHeader.description": "Configure the documentation plugin",
|
||||
"containers.HomePage.PluginHeader.title": "Documentation - Settings",
|
||||
"containers.HomePage.PopUpWarning.confirm": "I understand",
|
||||
"containers.HomePage.PopUpWarning.message": "Are you sure you want to delete this version?",
|
||||
@ -26,7 +23,20 @@
|
||||
"notification.delete.success": "Doc deleted",
|
||||
"notification.generate.success": "Doc generated",
|
||||
"notification.update.success": "Settings updated successfully",
|
||||
"pages.PluginPage.Button.open": "Open documentation",
|
||||
"pages.PluginPage.header.description": "Configure the documentation plugin",
|
||||
"pages.PluginPage.table.generated": "Last generated",
|
||||
"pages.PluginPage.table.icon.delete": "Delete {target}",
|
||||
"pages.PluginPage.table.icon.regnerate": "Regenerate {target}",
|
||||
"pages.PluginPage.table.icon.show": "Open {target}",
|
||||
"pages.PluginPage.table.version": "Version",
|
||||
"pages.SettingPage.title": "Settings",
|
||||
"pages.SettingsPage.Button.description": "Configure the documentation plugin",
|
||||
"pages.SettingsPage.header.save": "Save",
|
||||
"pages.SettingsPage.password.label": "Password",
|
||||
"pages.SettingsPage.toggle.label": "Restricted Access",
|
||||
"pages.SettingsPage.toggle.hint": "Make the documentation endpoint private",
|
||||
"plugin.description.long": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
|
||||
"plugin.description.short": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
|
||||
"plugin.name": "Documentation"
|
||||
}
|
||||
}
|
||||
@ -20,6 +20,8 @@
|
||||
"lodash": "4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
"path-to-regexp": "6.2.0",
|
||||
"pluralize": "8.0.0",
|
||||
"koa-session": "6.2.0",
|
||||
"react": "^17.0.2",
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const defaultConfig = require('./default-config');
|
||||
const sessionConfig = require('./session-config');
|
||||
|
||||
module.exports = {
|
||||
default: defaultConfig,
|
||||
default: { ...defaultConfig, ...sessionConfig },
|
||||
validator() {},
|
||||
};
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
session: {
|
||||
client: 'cookie',
|
||||
key: 'strapi.sid',
|
||||
prefix: 'strapi:sess:',
|
||||
ttl: 864000000,
|
||||
rolling: false,
|
||||
secretKeys: ['mySecretKey1', 'mySecretKey2'],
|
||||
cookie: {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
maxAge: 864000000,
|
||||
rewrite: true,
|
||||
signed: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -42,7 +42,11 @@ module.exports = {
|
||||
const version =
|
||||
major && minor && patch
|
||||
? `${major}.${minor}.${patch}`
|
||||
: strapi.plugins.documentation.config.info.version;
|
||||
: strapi
|
||||
.plugin('documentation')
|
||||
.service('documentation')
|
||||
.getDocumentationVersion();
|
||||
|
||||
const openAPISpecsPath = path.join(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
|
||||
@ -1,39 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
const koaStatic = require('koa-static');
|
||||
|
||||
const initialRoutes = [];
|
||||
const session = require('koa-session');
|
||||
const swaggerUi = require('swagger-ui-dist');
|
||||
|
||||
// TODO: delete when refactoring documentation plugin for v4
|
||||
module.exports = async ({ strapi }) => {
|
||||
// strapi.config.middleware.load.before.push('documentation');
|
||||
|
||||
initialRoutes.push(..._.cloneDeep(strapi.plugins.documentation.routes));
|
||||
|
||||
const swaggerUi = require('swagger-ui-dist');
|
||||
|
||||
// Find the plugins routes.
|
||||
strapi.plugins.documentation.routes = strapi.plugins.documentation.routes.map((route, index) => {
|
||||
if (route.handler === 'Documentation.getInfos') {
|
||||
return route;
|
||||
}
|
||||
|
||||
if (route.handler === 'Documentation.index' || route.path === '/login') {
|
||||
route.config.policies = initialRoutes[index].config.policies;
|
||||
}
|
||||
|
||||
// Set prefix to empty to be able to customise it.
|
||||
if (strapi.config.has('plugins.documentation.x-strapi-config.path')) {
|
||||
route.config.prefix = '';
|
||||
route.path = `/${strapi.config.get('plugin.documentation.x-strapi-config').path}${
|
||||
route.path
|
||||
}`.replace('//', '/');
|
||||
}
|
||||
|
||||
return route;
|
||||
});
|
||||
const sessionConfig = strapi.config.get('plugin.documentation').session;
|
||||
strapi.server.app.keys = sessionConfig.secretKeys;
|
||||
strapi.server.app.use(session(sessionConfig, strapi.server.app));
|
||||
|
||||
strapi.server.routes([
|
||||
{
|
||||
@ -43,7 +19,7 @@ module.exports = async ({ strapi }) => {
|
||||
ctx.url = path.basename(ctx.url);
|
||||
|
||||
return koaStatic(swaggerUi.getAbsoluteFSPath(), {
|
||||
maxage: 6000,
|
||||
maxage: sessionConfig.cookie.maxAge,
|
||||
defer: true,
|
||||
})(ctx, next);
|
||||
},
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
'use strict';
|
||||
const restrictAccess = require('../middlewares/restrict-access');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
@ -7,10 +8,15 @@ module.exports = [
|
||||
handler: 'documentation.index',
|
||||
config: {
|
||||
auth: false,
|
||||
// middlewares: [restrictAccess],
|
||||
// policies: [
|
||||
// { name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
|
||||
// ],
|
||||
middlewares: [restrictAccess],
|
||||
policies: [
|
||||
{
|
||||
name: 'admin::hasPermissions',
|
||||
config: {
|
||||
actions: ['plugin::documentation.read'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -19,10 +25,15 @@ module.exports = [
|
||||
handler: 'documentation.index',
|
||||
config: {
|
||||
auth: false,
|
||||
// middlewares: [restrictAccess],
|
||||
// policies: [
|
||||
// { name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
|
||||
// ],
|
||||
middlewares: [restrictAccess],
|
||||
policies: [
|
||||
{
|
||||
name: 'admin::hasPermissions',
|
||||
config: {
|
||||
actions: ['plugin::documentation.read'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -30,8 +41,14 @@ module.exports = [
|
||||
path: '/login',
|
||||
handler: 'documentation.loginView',
|
||||
config: {
|
||||
auth: false,
|
||||
policies: [
|
||||
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
|
||||
{
|
||||
name: 'admin::hasPermissions',
|
||||
config: {
|
||||
actions: ['plugin::documentation.read'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -40,6 +57,7 @@ module.exports = [
|
||||
path: '/login',
|
||||
handler: 'documentation.login',
|
||||
config: {
|
||||
auth: false,
|
||||
policies: [
|
||||
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
|
||||
],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user