-
-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEAT] Allow for queries/filters on collections when generating the sitemap #109
base: master
Are you sure you want to change the base?
Changes from all commits
18069b9
d9b5a24
bcd835e
b8c374d
2dad9f3
8d5673c
55cd2f5
42d8743
c8b400b
9c86986
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import * as React from 'react'; | ||
|
||
import { | ||
Grid, | ||
Typography, | ||
Flex, | ||
Button, | ||
} from '@strapi/design-system'; | ||
import { useIntl } from 'react-intl'; | ||
import { useDispatch } from 'react-redux'; | ||
|
||
import SelectConditional from '../../../SelectConditional'; | ||
import { onChangeContentTypes } from '../../../../state/actions/Sitemap'; | ||
|
||
// eslint-disable-next-line arrow-body-style | ||
const Filters = (props) => { | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
const { formatMessage } = useIntl(); | ||
const dispatch = useDispatch(); | ||
const [conditionCount, setConditionCount] = React.useState(0); | ||
const { | ||
modifiedState, | ||
uid, | ||
langcode, | ||
contentTypes, | ||
} = props; | ||
|
||
console.log(modifiedState); | ||
|
||
React.useEffect(() => { | ||
// get the initial condition count | ||
const count = Object.keys(modifiedState.getIn([uid, 'filters'], [])).length; | ||
setConditionCount(count); | ||
}, [uid, langcode]); | ||
|
||
const handleRemoveCondition = () => { | ||
dispatch(onChangeContentTypes(uid, null, ['filters', conditionCount, 'field'], '')); | ||
dispatch(onChangeContentTypes(uid, null, ['filters', conditionCount, 'operator'], '')); | ||
dispatch(onChangeContentTypes(uid, null, ['filters', conditionCount, 'value'], '')); | ||
setConditionCount(conditionCount - 1); | ||
}; | ||
return ( | ||
<div> | ||
{conditionCount === 0 ? ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this condition can be optimized. The only thing that should/shouldn't show for this ternary is the list of conditions. Though this ternary is used to render the entire component leaving duplicate code below (e.g. the add/remove buttons). If we use the ternary just for the conditions list this would be resolved. |
||
<Flex direction="column" alignItems="stretch"> | ||
<Flex direction="row" justifyContent="space-between"> | ||
<Flex direction="column" justifyContent="center" alignItems="flex-start"> | ||
<Typography variant="pi" fontWeight="bold"> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Label', defaultMessage: 'Conditional Filtering' })} | ||
</Typography> | ||
<Typography> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Description', defaultMessage: 'Only include URLs that match the following condition.' })} | ||
</Typography> | ||
</Flex> | ||
<Flex direction="row" alignItems="center" gap={2}> | ||
<Button onClick={() => setConditionCount(conditionCount + 1)}> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Add', defaultMessage: 'Add' })} | ||
</Button> | ||
<Button variant="secondary" onClick={() => handleRemoveCondition()}> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Remove', defaultMessage: 'Remove' })} | ||
</Button> | ||
</Flex> | ||
</Flex> | ||
</Flex> | ||
) : ( | ||
<Flex direction="column" alignItems="stretch"> | ||
<Flex direction="row" justifyContent="space-between" style={{ marginBottom: '2rem' }}> | ||
<Flex direction="column" justifyContent="center" alignItems="flex-start"> | ||
<Typography variant="pi" fontWeight="bold"> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Label', defaultMessage: 'Conditional Filtering' })} | ||
</Typography> | ||
<Typography> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Description', defaultMessage: 'Only include URLs that match the following conditions.' })} | ||
</Typography> | ||
</Flex> | ||
<Flex direction="row" alignItems="center" gap={2}> | ||
<Button onClick={() => setConditionCount(conditionCount + 1)}> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Add', defaultMessage: 'Add' })} | ||
</Button> | ||
<Button variant="secondary" onClick={() => handleRemoveCondition()}> | ||
{formatMessage({ id: 'sitemap.Settings.Field.Condition.Remove', defaultMessage: 'Remove' })} | ||
</Button> | ||
</Flex> | ||
</Flex> | ||
{Array.from(Array(conditionCount).keys()).map((i) => ( | ||
<Grid gap={4} style={{ marginBottom: '1rem' }}> | ||
<SelectConditional | ||
disabled={!uid || (contentTypes[uid].locales && !langcode)} | ||
contentType={contentTypes[uid]} | ||
onConditionChange={(value) => dispatch(onChangeContentTypes(uid, null, ['filters', String(i), 'field'], value))} | ||
onOperatorChange={(value) => dispatch(onChangeContentTypes(uid, null, ['filters', String(i), 'operator'], value))} | ||
onValueChange={(value) => dispatch(onChangeContentTypes(uid, null, ['filters', String(i), 'value'], value))} | ||
condition={modifiedState.getIn([uid, 'filters', String(i), 'field'], '')} | ||
conditionOperator={modifiedState.getIn([uid, 'filters', String(i), 'operator'], '')} | ||
conditionValue={modifiedState.getIn([uid, 'filters', String(i), 'value'], '')} | ||
/> | ||
</Grid> | ||
))} | ||
</Flex> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Filters; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React from 'react'; | ||
import { Select, Option, TextInput, GridItem } from '@strapi/design-system'; | ||
import { useIntl } from 'react-intl'; | ||
|
||
const operators = [ | ||
'$not', | ||
'$eq', | ||
'$eqi', | ||
'$ne', | ||
'$in', | ||
'$notIn', | ||
'$lt', | ||
'$lte', | ||
'$gt', | ||
'$gte', | ||
'$between', | ||
'$contains', | ||
'$notContains', | ||
'$containsi', | ||
'$notContainsi', | ||
'$startsWith', | ||
'$endsWith', | ||
'$null', | ||
'$notNull', | ||
]; | ||
|
||
const SelectConditional = (props) => { | ||
const { formatMessage } = useIntl(); | ||
|
||
const { | ||
contentType, | ||
disabled, | ||
onConditionChange, | ||
onOperatorChange, | ||
onValueChange, | ||
condition, | ||
conditionOperator, | ||
conditionValue, | ||
} = props; | ||
|
||
return ( | ||
<> | ||
<GridItem col={4}> | ||
<Select | ||
name="select" | ||
label={formatMessage({ id: 'sitemap.Settings.Field.SelectConditional.Label', defaultMessage: 'Attribute' })} | ||
hint={formatMessage({ id: 'sitemap.Settings.Field.SelectConditional.Description', defaultMessage: 'Select an attribute' })} | ||
disabled={disabled} | ||
onChange={(condition) => onConditionChange(condition)} | ||
value={condition} | ||
> | ||
{contentType && contentType.attributes.map((attribute) => { | ||
return <Option value={attribute} key={attribute}>{attribute}</Option>; | ||
})} | ||
</Select> | ||
</GridItem> | ||
<GridItem col={2}> | ||
<Select | ||
name="select" | ||
label={formatMessage({ id: 'sitemap.Settings.Field.SelectOperator.Label', defaultMessage: 'Operator' })} | ||
hint={formatMessage({ id: 'sitemap.Settings.Field.SelectOperator.Description', defaultMessage: 'Select an operator' })} | ||
disabled={disabled} | ||
onChange={(operator) => onOperatorChange(operator)} | ||
value={conditionOperator} | ||
> | ||
{operators.map((operator) => { | ||
return <Option value={operator} key={operator}>{operator}</Option>; | ||
})} | ||
</Select> | ||
</GridItem> | ||
<GridItem col={6}> | ||
<TextInput | ||
disabled={disabled} | ||
label={formatMessage({ id: 'sitemap.Settings.Field.SelectConditionValue.Label', defaultMessage: 'Value' })} | ||
name="conditionValue" | ||
hint={formatMessage({ id: 'sitemap.Settings.Field.SelectConditionValue.Description', defaultMessage: '"Text", true, 2, etc' })} | ||
onChange={(e) => onValueChange(e.target.value)} | ||
value={conditionValue} | ||
/> | ||
</GridItem> | ||
</> | ||
); | ||
}; | ||
|
||
export default SelectConditional; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/* | ||
/*/ | ||
!.gitignore |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
'use strict'; | ||
|
||
module.exports = () => { | ||
// destroy phase | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const { promises: fs } = require("fs"); | ||
Check warning on line 1 in server/utils/copyPublicFolder.js
|
||
const path = require("path"); | ||
Check warning on line 2 in server/utils/copyPublicFolder.js
|
||
|
||
const copyPublicFolder = async (src, dest) => { | ||
await fs.mkdir(dest, { recursive: true }); | ||
const entries = await fs.readdir(src, { withFileTypes: true }); | ||
|
||
entries.map(async (entry) => { | ||
const srcPath = path.join(src, entry.name); | ||
|
||
let destPath = ''; | ||
if (entry.name === '.gitignore.example') { | ||
destPath = path.join(dest, '.gitignore'); | ||
} else { | ||
destPath = path.join(dest, entry.name); | ||
} | ||
|
||
if (entry.isDirectory()) { | ||
await copyPublicFolder(srcPath, destPath); | ||
} else { | ||
await fs.copyFile(srcPath, destPath); | ||
} | ||
}); | ||
}; | ||
|
||
module.exports = copyPublicFolder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
handleRemoveCondition
function always removes the last filter. It would be neat if we can specify the filter we want to remove. Giving the end user more control on the filters interface.