Skip to content

Commit d82e427

Browse files
authored
Merge pull request #161 from pluginpal/feature/60-use-same-collection-with-different-patterns
Feature/60 use same collection with different patterns
2 parents c32aee9 + a187578 commit d82e427

File tree

14 files changed

+579
-450
lines changed

14 files changed

+579
-450
lines changed

.github/workflows/deploy-test-server.yml

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -27,54 +27,54 @@ jobs:
2727
environment:
2828
name: Test
2929
url: https://test.pluginpal.io
30-
steps:
31-
- name: Checkout repository
32-
uses: actions/checkout@v2
30+
# steps:
31+
# - name: Checkout repository
32+
# uses: actions/checkout@v2
3333

34-
- name: Set up Docker
35-
uses: actions/setup-node@v3
36-
with:
37-
node-version: 18
38-
cache: 'yarn'
34+
# - name: Set up Docker
35+
# uses: actions/setup-node@v3
36+
# with:
37+
# node-version: 18
38+
# cache: 'yarn'
3939

40-
- name: Install plugin dependencies
41-
run: yarn install
40+
# - name: Install plugin dependencies
41+
# run: yarn install
4242

43-
- name: Build the packages
44-
run: yarn run build
43+
# - name: Build the packages
44+
# run: yarn run build
4545

46-
- name: Install de playground dependencies
47-
run: yarn playground:install
46+
# - name: Install de playground dependencies
47+
# run: yarn playground:install
4848

49-
- name: Build a Docker image of the playground
50-
run: |
51-
cd playground
52-
docker build \
53-
--build-arg PUBLIC_URL=${{ secrets.TEST_URL }} \
54-
-t strapi-playground:latest .
55-
docker save -o strapi-playground-latest.tar strapi-playground:latest
49+
# - name: Build a Docker image of the playground
50+
# run: |
51+
# cd playground
52+
# docker build \
53+
# --build-arg PUBLIC_URL=${{ secrets.TEST_URL }} \
54+
# -t strapi-playground:latest .
55+
# docker save -o strapi-playground-latest.tar strapi-playground:latest
5656

57-
- name: Transfer the Docker image to the Dokku server
58-
uses: appleboy/[email protected]
59-
with:
60-
host: ${{ secrets.SSH_HOST }}
61-
username: ${{ secrets.SSH_CI_USERNAME }}
62-
password: ${{ secrets.SSH_CI_PASSWORD }}
63-
source: playground/strapi-playground-latest.tar
64-
target: /var/lib/dokku/data/storage/strapi/docker-images
57+
# - name: Transfer the Docker image to the Dokku server
58+
# uses: appleboy/[email protected]
59+
# with:
60+
# host: ${{ secrets.SSH_HOST }}
61+
# username: ${{ secrets.SSH_CI_USERNAME }}
62+
# password: ${{ secrets.SSH_CI_PASSWORD }}
63+
# source: playground/strapi-playground-latest.tar
64+
# target: /var/lib/dokku/data/storage/strapi/docker-images
6565

66-
- name: Deploy the Dokku app based on the Docker image
67-
uses: appleboy/[email protected]
68-
with:
69-
host: ${{ secrets.SSH_HOST }}
70-
username: ${{ secrets.SSH_CI_USERNAME }}
71-
password: ${{ secrets.SSH_CI_PASSWORD }}
72-
script_stop: true
73-
script: |
74-
sudo docker load -i /var/lib/dokku/data/storage/strapi/docker-images/playground/strapi-playground-latest.tar
75-
STRAPI_LATEST_IMAGE=$(sudo docker images --format "{{.ID}}" strapi-playground:latest)
76-
sudo docker tag strapi-playground:latest strapi-playground:$STRAPI_LATEST_IMAGE
77-
dokku git:from-image strapi strapi-playground:$STRAPI_LATEST_IMAGE
78-
sudo docker system prune --all --force
79-
sudo rm -rf /var/lib/dokku/data/storage/strapi/docker-images/playground/strapi-playground-latest.tar
66+
# - name: Deploy the Dokku app based on the Docker image
67+
# uses: appleboy/[email protected]
68+
# with:
69+
# host: ${{ secrets.SSH_HOST }}
70+
# username: ${{ secrets.SSH_CI_USERNAME }}
71+
# password: ${{ secrets.SSH_CI_PASSWORD }}
72+
# script_stop: true
73+
# script: |
74+
# sudo docker load -i /var/lib/dokku/data/storage/strapi/docker-images/playground/strapi-playground-latest.tar
75+
# STRAPI_LATEST_IMAGE=$(sudo docker images --format "{{.ID}}" strapi-playground:latest)
76+
# sudo docker tag strapi-playground:latest strapi-playground:$STRAPI_LATEST_IMAGE
77+
# dokku git:from-image strapi strapi-playground:$STRAPI_LATEST_IMAGE
78+
# sudo docker system prune --all --force
79+
# sudo rm -rf /var/lib/dokku/data/storage/strapi/docker-images/playground/strapi-playground-latest.tar
8080

packages/core/admin/api/url-alias.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useFetchClient } from '@strapi/helper-plugin';
2+
import { UrlAliasEntity } from '../types/url-aliases';
23

34
export const useCreateUrlAlias = () => {
45
const { post } = useFetchClient();
56

67
const createUrlAlias = async (body: { id: number }, slug: string) => {
7-
return post('/webtools/url-alias/create', {
8+
return post<UrlAliasEntity>('/webtools/url-alias/create', {
89
data: {
910
...body,
1011
contenttype: slug,
@@ -17,19 +18,19 @@ export const useCreateUrlAlias = () => {
1718

1819
export const useUpdateUrlAlias = () => {
1920
const { put } = useFetchClient();
20-
21-
const updateUrlAlias = async (body: { id: number }, slug: string) => {
22-
return put(`/webtools/url-alias/update/${body.id}`, {
21+
const updateUrlAliases = async (body: { id: number }, slug: string) => {
22+
return put<UrlAliasEntity>(`/webtools/url-alias/update/${body.id}`, {
2323
data: {
2424
...body,
2525
contenttype: slug,
2626
},
2727
});
2828
};
2929

30-
return { updateUrlAlias };
30+
return { updateUrlAliases };
3131
};
3232

33+
3334
export const useDeleteUrlAlias = () => {
3435
const { post } = useFetchClient();
3536

packages/core/admin/components/EditForm/index.tsx

Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,64 +9,88 @@ import {
99
TextInput,
1010
Checkbox,
1111
Link,
12+
Accordion,
13+
AccordionToggle,
14+
AccordionContent,
1215
} from '@strapi/design-system';
1316

1417
import getTrad from '../../helpers/getTrad';
1518
import { UrlAliasEntity } from '../../types/url-aliases';
1619

1720
const EditForm = () => {
1821
const { modifiedData, onChange } = useCMEditViewDataManager();
19-
const modifiedDataUrlAlias = modifiedData.url_alias as UrlAliasEntity;
22+
const modifiedDataUrlAliases =
23+
(modifiedData.url_alias as UrlAliasEntity[])?.length
24+
? modifiedData.url_alias as UrlAliasEntity[]
25+
: [{
26+
generated: true,
27+
}] as UrlAliasEntity[];
2028
const { formatMessage } = useIntl();
2129

22-
const updateValue = (name: string, value: string | number) => {
23-
onChange({ target: { name: `url_alias.${name}`, value, type: 'text' } });
30+
const updateValue = (index: number, name: string, value: string | number) => {
31+
const updatedUrlAliases = [...modifiedDataUrlAliases];
32+
33+
updatedUrlAliases[index] = {
34+
...updatedUrlAliases[index],
35+
[name]: value,
36+
};
37+
onChange({ target: { name: 'url_alias', value: updatedUrlAliases, type: 'array' } });
2438
};
2539

40+
const [expanded, setExpanded] = React.useState<number>(0);
41+
// eslint-disable-next-line max-len
42+
const toggle = (index: number) => setExpanded((prevExpanded) => (prevExpanded === index ? null : index));
43+
2644
return (
2745
<Stack size={2}>
28-
<Box>
29-
<Box>
30-
<Checkbox
31-
onValueChange={(value: string) => {
32-
updateValue('generated', value);
33-
}}
34-
value={
35-
modifiedDataUrlAlias?.generated !== undefined
36-
? modifiedDataUrlAlias?.generated
37-
: true
38-
}
39-
name="generated"
40-
hint="Uncheck this to create a custom alias below."
46+
{modifiedDataUrlAliases?.map((alias, index) => (
47+
<Accordion
48+
key={alias.id}
49+
value={`acc-${alias.id}`}
50+
expanded={expanded === index}
51+
onToggle={() => toggle(index)}
52+
variant="secondary"
53+
size="S"
54+
>
55+
<AccordionToggle
56+
description={alias.url_path ? alias.url_path : 'Initial URL alias'}
4157
>
42-
{formatMessage({
43-
id: getTrad('EditView.ExcludeFromSitemap'),
44-
defaultMessage: ' Generate automatic URL alias',
45-
})}
46-
</Checkbox>
47-
<Link to="/plugins/webtools/patterns">
48-
Configure URL alias patterns.
49-
</Link>
50-
</Box>
51-
<Box paddingTop={4}>
52-
<TextInput
53-
label="URL alias"
54-
name="path"
55-
hint='Specify a path by which this data can be accessed in the browser. For example, type "/about" when writing an about page.'
56-
disabled={
57-
modifiedDataUrlAlias?.generated !== undefined
58-
? modifiedDataUrlAlias?.generated
59-
: true
60-
}
61-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
62-
if (e.target.value.match(/^[A-Za-z0-9-_.~[\]/]*$/)) {
63-
updateValue('url_path', e.target.value);
64-
}
65-
}}
66-
value={modifiedDataUrlAlias?.url_path}
67-
/>
68-
</Box>
69-
</Box>
58+
{`Alias #${index + 1}`}
59+
</AccordionToggle>
60+
<AccordionContent padding="12px">
61+
<Box>
62+
<Checkbox
63+
onValueChange={(value: string) => {
64+
updateValue(index, 'generated', value);
65+
}}
66+
value={alias.generated !== undefined ? alias.generated : true}
67+
name={`generated-${index}`}
68+
hint="Uncheck this to create a custom alias below."
69+
>
70+
{formatMessage({
71+
id: getTrad('EditView.ExcludeFromSitemap'),
72+
defaultMessage: ' Generate automatic URL alias',
73+
})}
74+
</Checkbox>
75+
<Link to="/plugins/webtools/patterns">Configure URL alias patterns.</Link>
76+
</Box>
77+
<Box paddingTop={4}>
78+
<TextInput
79+
label="URL alias"
80+
name={`path-${index}`}
81+
hint='Specify a path by which this data can be accessed in the browser. For example, type "/about" when writing an about page.'
82+
disabled={alias.generated !== undefined ? alias.generated : true}
83+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
84+
if (e.target.value.match(/^[A-Za-z0-9-_.~[\]/]*$/)) {
85+
updateValue(index, 'url_path', e.target.value);
86+
}
87+
}}
88+
value={alias.url_path}
89+
/>
90+
</Box>
91+
</AccordionContent>
92+
</Accordion>
93+
))}
7094
</Stack>
7195
);
7296
};

packages/core/admin/components/EditView/index.tsx

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,54 @@ const EditView = () => {
2020
slug,
2121
} = useCMEditViewDataManager();
2222

23-
const modifiedDataUrlAlias = modifiedData.url_alias as UrlAliasEntity;
23+
24+
const modifiedDataUrlAliases = modifiedData.url_alias as UrlAliasEntity[];
2425
const i18nLang = new URLSearchParams(window.location.search).get('plugins[i18n][locale]');
2526

2627
useEffect(() => {
2728
// Early return for when the i18n plugin is not enabled.
2829
if (!i18nLang) return;
2930

31+
// Map through all url_aliases and clear those that do not match the current i18n language
3032
// If the URL alias is not the same language as the entity,
3133
// we should clear it. This happens when you're copying content
3234
// from a different locale.
33-
if (modifiedDataUrlAlias?.locale !== i18nLang) {
34-
onChange({ target: { name: 'url_alias', value: null, type: 'text' } });
35+
const updatedUrlAliases = modifiedDataUrlAliases?.map((alias) => {
36+
if (alias?.locale !== i18nLang) {
37+
return { ...alias, locale: null }; // Clear the alias if the locale doesn't match
38+
}
39+
return alias;
40+
});
41+
42+
// If the URL aliases have changed, update the form data
43+
// We fire the onChange here because we don't want unnecessary re-renders
44+
if (JSON.stringify(updatedUrlAliases) !== JSON.stringify(modifiedDataUrlAliases)) {
45+
onChange({ target: { name: 'url_alias', value: updatedUrlAliases, type: 'array' } });
3546
}
36-
}, [modifiedDataUrlAlias, onChange, i18nLang]);
47+
}, [modifiedDataUrlAliases, onChange, i18nLang]);
3748

3849
const { createUrlAlias } = useCreateUrlAlias();
39-
const { updateUrlAlias } = useUpdateUrlAlias();
50+
const { updateUrlAliases } = useUpdateUrlAlias();
4051

4152
if (!allLayoutData.contentType) return null;
4253

4354
if (!isContentTypeEnabled(allLayoutData.contentType)) return null;
44-
const modifiedUrlAlias = modifiedData.url_alias as UrlAliasEntity;
45-
const initialUrlAlias = initialData.url_alias as UrlAliasEntity;
55+
const modifiedUrlAliases = modifiedData.url_alias as UrlAliasEntity[];
56+
const initialUrlAliases = initialData.url_alias as UrlAliasEntity[];
4657

4758
const onSubmit = async () => {
48-
if (!initialUrlAlias) {
49-
const urlAlias = await createUrlAlias(modifiedUrlAlias, slug);
50-
onChange({ target: { name: 'url_alias', value: urlAlias, type: 'text' } });
59+
if (!initialUrlAliases || initialUrlAliases?.length === 0) {
60+
// Create new URL aliases
61+
const newAliases = await Promise.all(
62+
modifiedUrlAliases.map(async (alias) => (await createUrlAlias(alias, slug)).data),
63+
);
64+
65+
onChange({ target: { name: 'url_alias', value: newAliases, type: 'array' } });
5166
} else {
52-
await updateUrlAlias(modifiedUrlAlias, slug);
67+
// Update existing URL aliases
68+
await Promise.all(
69+
modifiedUrlAliases.map((alias) => updateUrlAliases(alias, slug)),
70+
);
5371
}
5472
};
5573

@@ -62,17 +80,19 @@ const EditView = () => {
6280
})}
6381
onSubmit={onSubmit}
6482
onCancel={() => {
65-
if (initialUrlAlias) {
66-
onChange({ target: { name: 'url_alias', value: initialUrlAlias, type: 'text' } });
83+
if (modifiedUrlAliases?.length > 0) {
84+
onChange({ target: { name: 'url_alias', value: modifiedUrlAliases, type: 'array' } });
85+
} else if (initialUrlAliases?.length > 0) {
86+
onChange({ target: { name: 'url_alias', value: initialUrlAliases, type: 'array' } });
6787
} else {
68-
onChange({ target: { name: 'url_alias', value: null, type: 'text' } });
88+
onChange({ target: { name: 'url_alias', value: null, type: 'array' } });
6989
}
7090
}}
7191
>
7292
<EditForm />
7393
</SidebarModal>
7494
<Permalink
75-
path={modifiedUrlAlias?.url_path}
95+
path={modifiedUrlAliases?.length > 0 ? modifiedUrlAliases[0].url_path : ''}
7696
/>
7797
</CheckPermissions>
7898
);

0 commit comments

Comments
 (0)