Merge pull request #147 from pluginpal/feature/beta-fixes

Feature/beta fixes
pull/148/head
Boaz Poolman 2024-10-12 20:13:45 +02:00 committed by GitHub
commit 4f0ceccb85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 572 additions and 846 deletions

View File

@ -41,9 +41,13 @@ jobs:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
cache: 'yarn' cache: 'yarn'
- name: Install dependencies plugin - name: Install dependencies plugin
run: yarn --no-lockfile --unsafe-perm --production run: yarn --no-lockfile --unsafe-perm
- name: Push the package to yalc
run: yarn build
- name: Add yalc package to the playground
run: yarn playground:yalc-add
- name: Install dependencies playground - name: Install dependencies playground
run: yarn playground:install --unsafe-perm run: cd playground && yarn install --unsafe-perm
- name: Build playground - name: Build playground
run: yarn playground:build run: yarn playground:build
- name: Run test - name: Run test

View File

@ -4,60 +4,55 @@ We want this community to be friendly and respectful to each other. Please follo
## Development Workflow ## Development Workflow
To get started with the project, make sure you have a local instance of Strapi running. This plugin provides a local development instance of Strapi to develop it's features. We call this instance `playground` and it can be found in the playground folder in the root of the project. For that reason it is not needed to have your own Strapi instance running to work on this plugin. Just clone the repo and you're ready to go!
See the [Strapi docs](https://github.com/strapi/strapi#getting-started) on how to setup a Strapi project.
#### 1. Fork the [repository](https://github.com/boazpoolman/strapi-plugin-config-sync) #### 1. Fork the [repository](https://github.com/pluginpal/strapi-plugin-config-sync)
[Go to the repository](https://github.com/boazpoolman/strapi-plugin-config-sync) and fork it to your own GitHub account. [Go to the repository](https://github.com/pluginpal/strapi-plugin-config-sync) and fork it to your own GitHub account.
#### 2. Clone from your repository into the plugins folder #### 2. Clone the forked repository
```bash ```bash
cd YOUR_STRAPI_PROJECT/src/plugins git clone git@github.com:YOUR_USERNAME/strapi-plugin-config-sync.git
git clone git@github.com:YOUR_USERNAME/strapi-plugin-config-sync.git config-sync
``` ```
#### 3. Install the dependencies #### 3. Install the dependencies
Go to the plugin and install it's dependencies. Go to the folder and install the dependencies
```bash ```bash
cd YOUR_STRAPI_PROJECT/src/plugins/config-sync/ && yarn plugin:install cd strapi-plugin-config-sync && yarn install
``` ```
#### 4. Enable the plugin #### 4. Install the playground dependencies
Add the following lines to the `config/plugins.js` file in your Strapi project. Run this in the root of the repository
```
const path = require('path');
// ...
{
'config-sync': {
enabled: true,
resolve: path.resolve(__dirname, '../src/plugins/config-sync'),
},
}
```
#### 5. Rebuild your Strapi project
Rebuild your strapi project to build the admin part of the plugin.
```bash ```bash
cd YOUR_STRAPI_PROJECT && yarn build yarn playground:install
``` ```
#### 6. Running the administration panel in development mode #### 5. Run the compiler of the plugin
**Start the administration panel server for development** We use `yalc` to publish the package to a local registry. Run the following command o watch for changes and push to `yalc` every time a change is made:
```bash ```bash
cd YOUR_STRAPI_PROJECT && yarn develop --watch-admin yarn develop
``` ```
The administration panel will be available at http://localhost:8080/admin #### 6. Start the playground instance
Leave the watcher running, open up a new terminal window and browse back to the root of the plugin repo. Run the following command:
```bash
yarn playground:develop
```
This will start the playground instance that will have the plugin installed from the `yalc` registry. Browse to http://localhost:1337 and create a test admin user to log in to the playground.
#### 7. Start your contribution!
You can now start working on your contribution. If you had trouble setting up this testing environment please feel free to report an issue on Github.
### Commit message convention ### Commit message convention
@ -82,12 +77,10 @@ The `package.json` file contains various scripts for common tasks:
- `yarn eslint`: lint files with ESLint. - `yarn eslint`: lint files with ESLint.
- `yarn eslint:fix`: auto-fix ESLint issues. - `yarn eslint:fix`: auto-fix ESLint issues.
- `yarn test:unit`: run unit tests with Jest. - `yarn test:integration`: run integration tests with Jest.
### Sending a pull request ### Sending a pull request
> **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
When you're sending a pull request: When you're sending a pull request:
- Prefer small pull requests focused on one change. - Prefer small pull requests focused on one change.

View File

@ -1,8 +1,8 @@
import React, { useState } from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { Button } from '@strapi/design-system'; import { Button, Typography } from '@strapi/design-system';
import { Map } from 'immutable'; import { Map } from 'immutable';
import { getFetchClient, useNotification } from '@strapi/strapi/admin'; import { getFetchClient, useNotification } from '@strapi/strapi/admin';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@ -14,38 +14,32 @@ const ActionButtons = () => {
const { post, get } = getFetchClient(); const { post, get } = getFetchClient();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { toggleNotification } = useNotification(); const { toggleNotification } = useNotification();
const [modalIsOpen, setModalIsOpen] = useState(false);
const [actionType, setActionType] = useState('');
const partialDiff = useSelector((state) => state.getIn(['config', 'partialDiff'], Map({}))).toJS(); const partialDiff = useSelector((state) => state.getIn(['config', 'partialDiff'], Map({}))).toJS();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const closeModal = () => {
setActionType('');
setModalIsOpen(false);
};
const openModal = (type) => {
setActionType(type);
setModalIsOpen(true);
};
return ( return (
<ActionButtonsStyling> <ActionButtonsStyling>
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('import')}> <ConfirmModal
type="import"
trigger={(
<Button disabled={isEmpty(partialDiff)}>
{formatMessage({ id: 'config-sync.Buttons.Import' })} {formatMessage({ id: 'config-sync.Buttons.Import' })}
</Button> </Button>
<Button disabled={isEmpty(partialDiff)} onClick={() => openModal('export')}> )}
onSubmit={(force) => dispatch(importAllConfig(partialDiff, force, toggleNotification, formatMessage, post, get))}
/>
<ConfirmModal
type="export"
trigger={(
<Button disabled={isEmpty(partialDiff)}>
{formatMessage({ id: 'config-sync.Buttons.Export' })} {formatMessage({ id: 'config-sync.Buttons.Export' })}
</Button> </Button>
{!isEmpty(partialDiff) && (
<h4 style={{ display: 'inline' }}>{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</h4>
)} )}
<ConfirmModal onSubmit={(force) => dispatch(exportAllConfig(partialDiff, toggleNotification, formatMessage, post, get))}
isOpen={modalIsOpen}
onClose={closeModal}
type={actionType}
onSubmit={(force) => actionType === 'import' ? dispatch(importAllConfig(partialDiff, force, toggleNotification, formatMessage, post, get)) : dispatch(exportAllConfig(partialDiff, toggleNotification, formatMessage, post, get))}
/> />
{!isEmpty(partialDiff) && (
<Typography variant="epsilon">{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</Typography>
)}
</ActionButtonsStyling> </ActionButtonsStyling>
); );
}; };

View File

@ -8,15 +8,15 @@ import {
Typography, Typography,
} from '@strapi/design-system'; } from '@strapi/design-system';
const ConfigDiff = ({ isOpen, onClose, oldValue, newValue, configName }) => { const ConfigDiff = ({ oldValue, newValue, configName, trigger }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
if (!isOpen) return null;
return ( return (
<Modal.Root <Modal.Root>
onClose={onClose} <Modal.Trigger>
labelledBy="title" {trigger}
> </Modal.Trigger>
<Modal.Content>
<Modal.Header> <Modal.Header>
<Typography variant="omega" fontWeight="bold" textColor="neutral800"> <Typography variant="omega" fontWeight="bold" textColor="neutral800">
{formatMessage({ id: 'config-sync.ConfigDiff.Title' })} {configName} {formatMessage({ id: 'config-sync.ConfigDiff.Title' })} {configName}
@ -25,19 +25,22 @@ const ConfigDiff = ({ isOpen, onClose, oldValue, newValue, configName }) => {
<Modal.Body> <Modal.Body>
<Grid.Root paddingBottom={4} style={{ textAlign: 'center' }}> <Grid.Root paddingBottom={4} style={{ textAlign: 'center' }}>
<Grid.Item col={6}> <Grid.Item col={6}>
<Typography variant="delta">{formatMessage({ id: 'config-sync.ConfigDiff.SyncDirectory' })}</Typography> <Typography variant="delta" style={{ width: '100%' }}>{formatMessage({ id: 'config-sync.ConfigDiff.SyncDirectory' })}</Typography>
</Grid.Item> </Grid.Item>
<Grid.Item col={6}> <Grid.Item col={6}>
<Typography variant="delta">{formatMessage({ id: 'config-sync.ConfigDiff.Database' })}</Typography> <Typography variant="delta" style={{ width: '100%' }}>{formatMessage({ id: 'config-sync.ConfigDiff.Database' })}</Typography>
</Grid.Item> </Grid.Item>
</Grid.Root> </Grid.Root>
<Typography variant="pi">
<ReactDiffViewer <ReactDiffViewer
oldValue={JSON.stringify(oldValue, null, 2)} oldValue={JSON.stringify(oldValue, null, 2)}
newValue={JSON.stringify(newValue, null, 2)} newValue={JSON.stringify(newValue, null, 2)}
splitView splitView
compareMethod={DiffMethod.WORDS} compareMethod={DiffMethod.WORDS}
/> />
</Typography>
</Modal.Body> </Modal.Body>
</Modal.Content>
</Modal.Root> </Modal.Root>
); );
}; };

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { Tr, Td, Checkbox } from '@strapi/design-system'; import { Tr, Td, Checkbox, Typography } from '@strapi/design-system';
const CustomRow = ({ row, checked, updateValue }) => { const CustomRow = ({ row, checked, updateValue, ...props }) => {
const { configName, configType, state, onClick } = row; const { configName, configType, state, onClick } = row;
const stateStyle = (stateStr) => { const stateStyle = (stateStr) => {
@ -34,6 +34,7 @@ const CustomRow = ({ row, checked, updateValue }) => {
return ( return (
<Tr <Tr
{...props}
onClick={(e) => { onClick={(e) => {
if (e.target.type !== 'checkbox') { if (e.target.type !== 'checkbox') {
onClick(configType, configName); onClick(configType, configName);
@ -44,18 +45,18 @@ const CustomRow = ({ row, checked, updateValue }) => {
<Td> <Td>
<Checkbox <Checkbox
aria-label={`Select ${configName}`} aria-label={`Select ${configName}`}
value={checked} checked={checked}
onValueChange={updateValue} onCheckedChange={updateValue}
/> />
</Td> </Td>
<Td> <Td onClick={(e) => props.onClick(e)}>
<p>{configName}</p> <Typography variant="omega">{configName}</Typography>
</Td> </Td>
<Td> <Td onClick={(e) => props.onClick(e)}>
<p>{configType}</p> <Typography variant="omega">{configType}</Typography>
</Td> </Td>
<Td> <Td onClick={(e) => props.onClick(e)}>
<p style={stateStyle(state)}>{state}</p> <Typography variant="omega" style={stateStyle(state)}>{state}</Typography>
</Td> </Td>
</Tr> </Tr>
); );

View File

@ -22,7 +22,6 @@ import { setConfigPartialDiffInState } from '../../state/actions/Config';
const ConfigList = ({ diff, isLoading }) => { const ConfigList = ({ diff, isLoading }) => {
const [openModal, setOpenModal] = useState(false);
const [originalConfig, setOriginalConfig] = useState({}); const [originalConfig, setOriginalConfig] = useState({});
const [newConfig, setNewConfig] = useState({}); const [newConfig, setNewConfig] = useState({});
const [cName, setCname] = useState(''); const [cName, setCname] = useState('');
@ -72,7 +71,6 @@ const ConfigList = ({ diff, isLoading }) => {
setOriginalConfig(diff.fileConfig[`${configType}.${configName}`]); setOriginalConfig(diff.fileConfig[`${configType}.${configName}`]);
setNewConfig(diff.databaseConfig[`${configType}.${configName}`]); setNewConfig(diff.databaseConfig[`${configType}.${configName}`]);
setCname(`${configType}.${configName}`); setCname(`${configType}.${configName}`);
setOpenModal(true);
}, },
}); });
}); });
@ -89,13 +87,6 @@ const ConfigList = ({ diff, isLoading }) => {
dispatch(setConfigPartialDiffInState(newPartialDiff)); dispatch(setConfigPartialDiffInState(newPartialDiff));
}, [checkedItems]); }, [checkedItems]);
const closeModal = () => {
setOriginalConfig({});
setNewConfig({});
setCname('');
setOpenModal(false);
};
if (isLoading) { if (isLoading) {
return ( return (
<div style={{ textAlign: 'center', marginTop: 40 }}> <div style={{ textAlign: 'center', marginTop: 40 }}>
@ -117,22 +108,14 @@ const ConfigList = ({ diff, isLoading }) => {
return ( return (
<div> <div>
<ConfigDiff
isOpen={openModal}
oldValue={originalConfig}
newValue={newConfig}
onClose={closeModal}
configName={cName}
/>
<Table colCount={4} rowCount={rows.length + 1}> <Table colCount={4} rowCount={rows.length + 1}>
<Thead> <Thead>
<Tr> <Tr>
<Th> <Th>
<Checkbox <Checkbox
aria-label={formatMessage({ id: 'config-sync.ConfigList.SelectAll' })} aria-label={formatMessage({ id: 'config-sync.ConfigList.SelectAll' })}
indeterminate={isIndeterminate} checked={isIndeterminate ? "indeterminate" : allChecked}
onValueChange={(value) => setCheckedItems(checkedItems.map(() => value))} onCheckedChange={(value) => setCheckedItems(checkedItems.map(() => value))}
value={allChecked}
/> />
</Th> </Th>
<Th> <Th>
@ -148,8 +131,13 @@ const ConfigList = ({ diff, isLoading }) => {
</Thead> </Thead>
<Tbody> <Tbody>
{rows.map((row, index) => ( {rows.map((row, index) => (
<ConfigListRow <ConfigDiff
key={row.configName} key={row.configName}
oldValue={originalConfig}
newValue={newConfig}
configName={cName}
trigger={(
<ConfigListRow
row={row} row={row}
checked={checkedItems[index]} checked={checkedItems[index]}
updateValue={() => { updateValue={() => {
@ -157,6 +145,8 @@ const ConfigList = ({ diff, isLoading }) => {
setCheckedItems([...checkedItems]); setCheckedItems([...checkedItems]);
}} }}
/> />
)}
/>
))} ))}
</Tbody> </Tbody>
</Table> </Table>

View File

@ -10,23 +10,24 @@ import {
Checkbox, Checkbox,
Divider, Divider,
Box, Box,
Field,
} from '@strapi/design-system'; } from '@strapi/design-system';
import { WarningCircle } from '@strapi/icons'; import { WarningCircle } from '@strapi/icons';
const ConfirmModal = ({ isOpen, onClose, onSubmit, type }) => { const ConfirmModal = ({ onClose, onSubmit, type, trigger }) => {
const soft = useSelector((state) => state.getIn(['config', 'appEnv', 'config', 'soft'], false)); const soft = useSelector((state) => state.getIn(['config', 'appEnv', 'config', 'soft'], false));
const [force, setForce] = useState(false); const [force, setForce] = useState(false);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
if (!isOpen) return null;
return ( return (
<Dialog.Root <Dialog.Root>
onClose={onClose} <Dialog.Trigger>
title={formatMessage({ id: "config-sync.popUpWarning.Confirmation" })} {trigger}
isOpen={isOpen} </Dialog.Trigger>
> <Dialog.Content>
<Dialog.Body icon={<WarningCircle />}> <Dialog.Header>{formatMessage({ id: "config-sync.popUpWarning.Confirmation" })}</Dialog.Header>
<Dialog.Body>
<WarningCircle fill="danger600" width="32px" height="32px" />
<Flex size={2}> <Flex size={2}>
<Flex justifyContent="center"> <Flex justifyContent="center">
<Typography variant="omega" id="confirm-description" style={{ textAlign: 'center' }}> <Typography variant="omega" id="confirm-description" style={{ textAlign: 'center' }}>
@ -35,44 +36,43 @@ const ConfirmModal = ({ isOpen, onClose, onSubmit, type }) => {
</Typography> </Typography>
</Flex> </Flex>
</Flex> </Flex>
</Dialog.Body>
{(soft && type === 'import') && ( {(soft && type === 'import') && (
<React.Fragment> <Box width="100%">
<Divider /> <Divider marginTop={4} />
<Box padding={4}> <Box paddingTop={6}>
<Field.Root hint="Check this to ignore the soft setting.">
<Checkbox <Checkbox
onValueChange={(value) => setForce(value)} onValueChange={(value) => setForce(value)}
value={force} value={force}
name="force" name="force"
hint="Check this to ignore the soft setting."
> >
{formatMessage({ id: 'config-sync.popUpWarning.force' })} {formatMessage({ id: 'config-sync.popUpWarning.force' })}
</Checkbox> </Checkbox>
<Field.Hint />
</Field.Root>
</Box>
</Box> </Box>
</React.Fragment>
)} )}
<Dialog.Footer </Dialog.Body>
startAction={( <Dialog.Footer>
<Button <Dialog.Cancel>
onClick={() => { <Button fullWidth variant="tertiary">
onClose();
}}
variant="tertiary"
>
{formatMessage({ id: 'config-sync.popUpWarning.button.cancel' })} {formatMessage({ id: 'config-sync.popUpWarning.button.cancel' })}
</Button> </Button>
)} </Dialog.Cancel>
endAction={( <Dialog.Action>
<Button <Button
fullWidth
variant="secondary" variant="secondary"
onClick={() => { onClick={() => {
onClose();
onSubmit(force); onSubmit(force);
}} }}
> >
{formatMessage({ id: `config-sync.popUpWarning.button.${type}` })} {formatMessage({ id: `config-sync.popUpWarning.button.${type}` })}
</Button> </Button>
)} /> </Dialog.Action>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root> </Dialog.Root>
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { getFetchClient, useNotification } from '@strapi/strapi/admin'; import { getFetchClient, useNotification } from '@strapi/strapi/admin';
@ -13,20 +13,21 @@ const FirstExport = () => {
const { post, get } = getFetchClient(); const { post, get } = getFetchClient();
const { toggleNotification } = useNotification(); const { toggleNotification } = useNotification();
const dispatch = useDispatch(); const dispatch = useDispatch();
const [modalIsOpen, setModalIsOpen] = useState(false);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
return ( return (
<div> <div>
<ConfirmModal
isOpen={modalIsOpen}
onClose={() => setModalIsOpen(false)}
type="export"
onSubmit={() => dispatch(exportAllConfig([], toggleNotification, formatMessage, post, get))}
/>
<EmptyStateLayout <EmptyStateLayout
content={formatMessage({ id: 'config-sync.FirstExport.Message' })} content={formatMessage({ id: 'config-sync.FirstExport.Message' })}
action={<Button onClick={() => setModalIsOpen(true)}>{formatMessage({ id: 'config-sync.FirstExport.Button' })}</Button>} action={(
<ConfirmModal
type="export"
onSubmit={() => dispatch(exportAllConfig([], toggleNotification, formatMessage, post, get))}
trigger={(
<Button>{formatMessage({ id: 'config-sync.FirstExport.Button' })}</Button>
)}
/>
)}
icon={<EmptyDocuments width={160} />} icon={<EmptyDocuments width={160} />}
/> />
</div> </div>

View File

@ -14,12 +14,15 @@
"config-sync": "./bin/config-sync" "config-sync": "./bin/config-sync"
}, },
"scripts": { "scripts": {
"develop": "nodemon -e js,jsx --ignore playground --exec \"yalc publish && yalc push\"",
"build": "yalc push --publish",
"eslint": "eslint --max-warnings=0 './**/*.{js,jsx}'", "eslint": "eslint --max-warnings=0 './**/*.{js,jsx}'",
"eslint:fix": "eslint --fix './**/*.{js,jsx}'", "eslint:fix": "eslint --fix './**/*.{js,jsx}'",
"test:unit": "jest --verbose", "test:unit": "jest --verbose",
"test:integration": "cd playground && node_modules/.bin/jest --verbose --forceExit --detectOpenHandles", "test:integration": "cd playground && node_modules/.bin/jest --verbose --forceExit --detectOpenHandles",
"plugin:install": "yarn install && rm -rf node_modules/@strapi/helper-plugin", "playground:install": "yarn playground:yalc-add-link && cd playground && yarn install",
"playground:install": "cd playground && yarn install", "playground:yalc-add": "cd playground && yalc add strapi-plugin-config-sync",
"playground:yalc-add-link": "cd playground && yalc add --link strapi-plugin-config-sync",
"playground:build": "cd playground && yarn build", "playground:build": "cd playground && yarn build",
"playground:develop": "cd playground && yarn develop" "playground:develop": "cd playground && yarn develop"
}, },
@ -55,13 +58,13 @@
"strapi-server.js" "strapi-server.js"
], ],
"peerDependencies": { "peerDependencies": {
"@strapi/strapi": "^5.0.0-rc.2" "@strapi/strapi": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@strapi/design-system": "2.0.0-rc.7", "@strapi/design-system": "2.0.0-rc.11",
"@strapi/icons": "2.0.0-rc.7", "@strapi/icons": "2.0.0-rc.11",
"@strapi/strapi": "5.0.0-rc.2", "@strapi/strapi": "5.0.4",
"@strapi/utils": "5.0.0-rc.2", "@strapi/utils": "5.0.4",
"babel-eslint": "9.0.0", "babel-eslint": "9.0.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-airbnb": "^18.2.1", "eslint-config-airbnb": "^18.2.1",
@ -78,10 +81,12 @@
"jest-cli": "^29.3.1", "jest-cli": "^29.3.1",
"jest-styled-components": "^7.0.2", "jest-styled-components": "^7.0.2",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"nodemon": "^3.1.7",
"react": "^17.0.2", "react": "^17.0.2",
"react-redux": "^7.2.2", "react-redux": "^7.2.2",
"redux": "^4.0.5", "redux": "^4.0.5",
"styled-components": "^5.2.3" "styled-components": "^5.2.3",
"yalc": "^1.0.0-pre.53"
}, },
"bugs": { "bugs": {
"url": "https://github.com/pluginpal/strapi-plugin-config-sync/issues" "url": "https://github.com/pluginpal/strapi-plugin-config-sync/issues"

View File

@ -114,3 +114,7 @@ exports
*.cache *.cache
build build
.strapi-updater.json .strapi-updater.json
# yalc
.yalc
yalc.lock

View File

@ -2,15 +2,15 @@
* This file was automatically generated by Strapi. * This file was automatically generated by Strapi.
* Any modifications made will be discarded. * Any modifications made will be discarded.
*/ */
import usersPermissions from "@strapi/plugin-users-permissions/strapi-admin";
import strapiCloud from "@strapi/plugin-cloud/strapi-admin"; import strapiCloud from "@strapi/plugin-cloud/strapi-admin";
import usersPermissions from "@strapi/plugin-users-permissions/strapi-admin";
import configSync from "strapi-plugin-config-sync/strapi-admin"; import configSync from "strapi-plugin-config-sync/strapi-admin";
import { renderAdmin } from "@strapi/strapi/admin"; import { renderAdmin } from "@strapi/strapi/admin";
renderAdmin(document.getElementById("strapi"), { renderAdmin(document.getElementById("strapi"), {
plugins: { plugins: {
"users-permissions": usersPermissions,
"strapi-cloud": strapiCloud, "strapi-cloud": strapiCloud,
"users-permissions": usersPermissions,
"config-sync": configSync, "config-sync": configSync,
}, },
}); });

View File

@ -14,4 +14,7 @@ module.exports = ({ env }) => ({
nps: env.bool('FLAG_NPS', true), nps: env.bool('FLAG_NPS', true),
promoteEE: env.bool('FLAG_PROMOTE_EE', true), promoteEE: env.bool('FLAG_PROMOTE_EE', true),
}, },
watchIgnoreFiles: [
'!**/.yalc/**/server/**',
]
}); });

View File

@ -13,17 +13,18 @@
"devDependencies": { "devDependencies": {
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-cli": "^29.7.0", "jest-cli": "^29.7.0",
"supertest": "^6.3.3" "supertest": "^6.3.3",
"yalc": "^1.0.0-pre.53"
}, },
"dependencies": { "dependencies": {
"@strapi/strapi": "5.0.0-rc.2", "@strapi/plugin-cloud": "5.0.4",
"@strapi/plugin-users-permissions": "5.0.0-rc.2", "@strapi/plugin-users-permissions": "5.0.4",
"@strapi/plugin-cloud": "5.0.0-rc.2", "@strapi/strapi": "5.0.4",
"better-sqlite3": "9.4.3", "better-sqlite3": "9.4.3",
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"react-router-dom": "^6.0.0", "react-router-dom": "^6.0.0",
"strapi-plugin-config-sync": "./..", "strapi-plugin-config-sync": "link:.yalc/strapi-plugin-config-sync",
"styled-components": "^6.0.0" "styled-components": "^6.0.0"
}, },
"author": { "author": {

View File

@ -1,5 +1,3 @@
import type { Struct, Schema } from '@strapi/strapi'; /*
* The app doesn't have any components yet.
declare module '@strapi/strapi' { */
export module Public {}
}

View File

@ -22,6 +22,7 @@ export interface ApiHomeHome extends Struct.SingleTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'api::home.home'>;
}; };
} }
@ -45,6 +46,7 @@ export interface ApiPagePage extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'api::page.page'>;
}; };
} }
@ -99,6 +101,10 @@ export interface PluginUploadFile extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::upload.file'
>;
}; };
} }
@ -145,6 +151,10 @@ export interface PluginUploadFolder extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::upload.folder'
>;
}; };
} }
@ -186,6 +196,10 @@ export interface PluginI18NLocale extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::i18n.locale'
>;
}; };
} }
@ -229,6 +243,10 @@ export interface PluginContentReleasesRelease
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::content-releases.release'
>;
}; };
} }
@ -269,6 +287,10 @@ export interface PluginContentReleasesReleaseAction
Schema.Attribute.Private; Schema.Attribute.Private;
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::content-releases.release-action'
>;
}; };
} }
@ -312,6 +334,10 @@ export interface PluginReviewWorkflowsWorkflow
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::review-workflows.workflow'
>;
}; };
} }
@ -353,6 +379,10 @@ export interface PluginReviewWorkflowsWorkflowStage
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::review-workflows.workflow-stage'
>;
}; };
} }
@ -391,6 +421,10 @@ export interface PluginUsersPermissionsPermission
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::users-permissions.permission'
>;
}; };
} }
@ -439,6 +473,10 @@ export interface PluginUsersPermissionsRole
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::users-permissions.role'
>;
}; };
} }
@ -490,6 +528,10 @@ export interface PluginUsersPermissionsUser
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'plugin::users-permissions.user'
>;
}; };
} }
@ -535,6 +577,7 @@ export interface AdminPermission extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::permission'>;
}; };
} }
@ -599,6 +642,7 @@ export interface AdminUser extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::user'>;
}; };
} }
@ -646,6 +690,7 @@ export interface AdminRole extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::role'>;
}; };
} }
@ -704,6 +749,7 @@ export interface AdminApiToken extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::api-token'>;
}; };
} }
@ -742,6 +788,10 @@ export interface AdminApiTokenPermission extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'admin::api-token-permission'
>;
}; };
} }
@ -797,6 +847,10 @@ export interface AdminTransferToken extends Struct.CollectionTypeSchema {
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'admin::transfer-token'
>;
}; };
} }
@ -836,6 +890,10 @@ export interface AdminTransferTokenPermission
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private; Schema.Attribute.Private;
locale: Schema.Attribute.String; locale: Schema.Attribute.String;
localizations: Schema.Attribute.Relation<
'oneToMany',
'admin::transfer-token-permission'
>;
}; };
} }

947
yarn.lock

File diff suppressed because it is too large Load Diff