Merge branch 'develop' of github.com:strapi/strapi into fix/single-types-issues

Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
HichamELBSI 2020-04-23 15:07:55 +02:00
commit 7a4a87fa68
19 changed files with 241 additions and 178 deletions

View File

@ -263,6 +263,10 @@ query {
To simplify and automate the build of the GraphQL schema, we introduced the Shadow CRUD feature. It automatically generates the type definition, queries, mutations and resolvers based on your models. The feature also lets you make complex query with many arguments such as `limit`, `sort`, `start` and `where`.
::: tip NOTE
If you use a local plugin, the controller methods of your plugin are not created by default. In order for the Shadow CRUD to work you have to define them in your controllers for each of your models. You can find examples of controllers `findOne`, `find`, `create`, `update` and `delete` there : [Core controllers](../concepts/controllers.html#core-controllers).
:::
### Example
If you've generated an API called `Restaurant` using the CLI `strapi generate:api restaurant` or the administration panel, your model looks like this:
@ -517,7 +521,7 @@ module.exports = {
`,
mutation: `
attachRestaurantToChef(id: ID, chefID: ID): Restaurant!
`
`,
resolver: {
Query: {
restaurant: {

View File

@ -14,7 +14,8 @@
},
"slug": {
"type": "uid",
"targetField": "title"
"targetField": "title",
"required": true
},
"single": {
"model": "file",

View File

@ -3,6 +3,9 @@ import styled from 'styled-components';
const SearchButton = styled.button`
padding: 0 10px;
line-height: normal;
&:focus {
outline: 0;
}
`;
export default SearchButton;

View File

@ -3,6 +3,7 @@ import styled from 'styled-components';
const LeftMenuListLink = styled.div`
max-height: 180px;
margin-bottom: 19px;
margin-right: 28px;
overflow: auto;
`;

View File

@ -60,7 +60,7 @@ exports[`Admin | containers | EditView should match the snapshot 1`] = `
.c5 {
height: 30px;
padding: 0 15px;
padding: 0 14px;
font-weight: 500;
font-size: 1.3rem;
line-height: normal;
@ -96,7 +96,7 @@ exports[`Admin | containers | EditView should match the snapshot 1`] = `
.c7 {
height: 30px;
padding: 0 15px;
padding: 0 14px;
font-weight: 500;
font-size: 1.3rem;
line-height: normal;
@ -140,7 +140,7 @@ exports[`Admin | containers | EditView should match the snapshot 1`] = `
.c8 {
height: 30px;
padding: 0 15px;
padding: 0 14px;
font-weight: 500;
font-size: 1.3rem;
line-height: normal;

View File

@ -36,7 +36,7 @@ exports[`Admin | containers | ListView should match the snapshot 1`] = `
.c4 {
height: 30px;
padding: 0 15px;
padding: 0 14px;
font-weight: 500;
font-size: 1.3rem;
line-height: normal;

View File

@ -22,12 +22,12 @@
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.4.3",
"@buffetjs/core": "3.0.5",
"@buffetjs/custom": "3.0.5",
"@buffetjs/hooks": "3.0.5",
"@buffetjs/icons": "3.0.5",
"@buffetjs/styles": "3.0.5",
"@buffetjs/utils": "3.0.5",
"@buffetjs/core": "3.0.6",
"@buffetjs/custom": "3.0.6",
"@buffetjs/hooks": "3.0.6",
"@buffetjs/icons": "3.0.6",
"@buffetjs/styles": "3.0.6",
"@buffetjs/utils": "3.0.6",
"@fortawesome/fontawesome-free": "^5.11.2",
"@fortawesome/fontawesome-svg-core": "^1.2.25",
"@fortawesome/free-brands-svg-icons": "^5.11.2",
@ -116,4 +116,4 @@
},
"license": "MIT",
"gitHead": "c85658a19b8fef0f3164c19693a45db305dc07a9"
}
}

View File

@ -6,7 +6,17 @@ const List = styled.ul`
margin-bottom: 0;
padding-left: 0;
max-height: 178px;
overflow-y: scroll;
overflow-y: auto;
::-webkit-scrollbar {
background: transparent;
}
::-webkit-scrollbar-track {
background: transparent;
&:hover {
background: transparent;
}
}
li {
position: relative;
margin-bottom: 2px;

View File

@ -7,7 +7,7 @@ import { useDebounce, useClickAwayListener } from '@buffetjs/hooks';
import styled from 'styled-components';
import { request, LoadingIndicator } from 'strapi-helper-plugin';
import { FormattedMessage } from 'react-intl';
import { isEmpty } from 'lodash';
import { get } from 'lodash';
import pluginId from '../../pluginId';
import getRequestUrl from '../../utils/getRequestUrl';
@ -42,13 +42,12 @@ const InputUID = ({
error: inputError,
name,
onChange,
required,
validations,
value,
editable,
...inputProps
}) => {
const { modifiedData, initialData } = useDataManager();
const { modifiedData, initialData, layout } = useDataManager();
const [isLoading, setIsLoading] = useState(false);
const [availability, setAvailability] = useState(null);
const [isSuggestionOpen, setIsSuggestionOpen] = useState(true);
@ -59,9 +58,10 @@ const InputUID = ({
const wrapperRef = useRef(null);
const generateUid = useRef();
const initialValue = initialData[name];
const isCreation = isEmpty(initialData);
const createdAtName = get(layout, ['schema', 'options', 'timestamps'], ['created_at'])[0];
const isCreation = !initialData[createdAtName];
generateUid.current = async (changeInitialData = false) => {
generateUid.current = async (shouldSetInitialValue = false) => {
setIsLoading(true);
const requestURL = getRequestUrl('explorer/uid/generate');
try {
@ -74,7 +74,7 @@ const InputUID = ({
},
});
onChange({ target: { name, value: data, type: 'text' } }, changeInitialData);
onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
setIsLoading(false);
} catch (err) {
console.error({ err });
@ -107,7 +107,7 @@ const InputUID = ({
};
useEffect(() => {
if (!value && required) {
if (!value && validations.required) {
generateUid.current(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -144,9 +144,15 @@ const InputUID = ({
}, [availability]);
useEffect(() => {
if (!isCustomized && isCreation && debouncedTargetFieldValue) {
generateUid.current();
if (
!isCustomized &&
isCreation &&
debouncedTargetFieldValue &&
modifiedData[attribute.targetField]
) {
generateUid.current(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedTargetFieldValue, isCustomized, isCreation]);
useClickAwayListener(wrapperRef, () => setIsSuggestionOpen(false));
@ -221,7 +227,7 @@ const InputUID = ({
<RegenerateButton
onMouseEnter={handleGenerateMouseEnter}
onMouseLeave={handleGenerateMouseLeave}
onClick={generateUid.current}
onClick={() => generateUid.current()}
>
{isLoading ? (
<LoadingIndicator small />

View File

@ -184,7 +184,6 @@ function Inputs({ autoFocus, keys, layout, name, onBlur }) {
validations={validations}
value={inputValue}
withDefaultValue={false}
required={isRequired}
/>
);
}}

View File

@ -3,7 +3,6 @@ import styled from 'styled-components';
const Wrapper = styled.div`
position: relative;
margin-bottom: 27px;
label {
width: 100%;
overflow: hidden;

View File

@ -98,7 +98,7 @@ const Header = () => {
title: {
label: headerTitle && headerTitle.toString(),
},
content: isSingleType ? `${formatMessage({ id: `${pluginId}.api.id` })} : ${layout.apiID}` : '',
content: `${formatMessage({ id: `${pluginId}.api.id` })} : ${layout.apiID}`,
actions: getHeaderActions(),
};

View File

@ -182,7 +182,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
});
};
const handleChange = ({ target: { name, value, type } }, initialValue = false) => {
const handleChange = ({ target: { name, value, type } }, shouldSetInitialValue = false) => {
let inputValue = value;
// Empty string is not a valid date,
@ -214,7 +214,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
type: 'ON_CHANGE',
keys: name.split('.'),
value: inputValue,
initialValue,
shouldSetInitialValue,
});
};

View File

@ -139,7 +139,7 @@ const reducer = (state, action) => {
// that needs an asynchronous initial value like the UID field
// This is just a temporary patch.
// TODO : Refactor the default form creation (workflow) to accept async default values.
if (action.initialValue) {
if (action.shouldSetInitialValue) {
newState = state.updateIn(['initialData', ...action.keys], () => {
return action.value;
});

View File

@ -7,8 +7,15 @@
const _ = require('lodash');
const compose = require('koa-compose');
const { convertToParams, convertToQuery, amountLimiting } = require('./utils');
const { policy: policyUtils } = require('strapi-utils');
const {
convertToParams,
convertToQuery,
amountLimiting,
getAction,
getActionDetails,
isResolvablePath,
} = require('./utils');
const buildMutation = (mutationName, config) => {
const { resolver, resolverOf, transformOutput = _.identity } = config;
@ -147,70 +154,9 @@ const buildQueryContext = ({ options, graphqlContext }) => {
return { ctx, opts };
};
const getAction = resolver => {
if (!_.isString(resolver)) {
throw new Error(`Error building query. Expected a string, got ${resolver}`);
}
const actionDetails = getActionDetails(resolver);
const actionFn = getActionFn(actionDetails);
if (!actionFn) {
throw new Error(
`[GraphQL] Cannot find action "${resolver}". Check your graphql configurations.`
);
}
return actionFn;
};
const getActionFn = details => {
const { controller, action, plugin, api } = details;
if (plugin) {
return _.get(strapi.plugins, [_.toLower(plugin), 'controllers', _.toLower(controller), action]);
}
return _.get(strapi.api, [_.toLower(api), 'controllers', _.toLower(controller), action]);
};
const getActionDetails = resolver => {
if (resolver.startsWith('plugins::')) {
const [, path] = resolver.split('::');
const [plugin, controller, action] = path.split('.');
return { plugin, controller, action };
}
if (resolver.startsWith('application::')) {
const [, path] = resolver.split('::');
const [api, controller, action] = path.split('.');
return { api, controller, action };
}
const args = resolver.split('.');
if (args.length === 3) {
const [api, controller, action] = args;
return { api, controller, action };
}
// if direct api access
if (args.length === 2) {
const [controller, action] = args;
return { api: controller, controller, action };
}
throw new Error(
`[GraphQL] Could not find action for resolver "${resolver}". Check your graphql configurations.`
);
};
/**
* Checks if a resolverPath (resolver or resovlerOf) might be resolved
*/
const isResolvablePath = path => _.isString(path) && !_.isEmpty(path);
const getPolicies = config => {
const { resolver, policies = [], resolverOf } = config;

View File

@ -16,13 +16,14 @@ const { mergeSchemas, convertToParams, convertToQuery, amountLimiting } = requir
const { toSDL, getTypeDescription } = require('./schema-definitions');
const { toSingular, toPlural } = require('./naming');
const { buildQuery, buildMutation } = require('./resolvers-builder');
const { actionExists } = require('./utils');
const isQueryEnabled = (schema, name) => {
return _.get(schema, ['resolver', 'Query', name]) !== false;
return _.get(schema, `resolver.Query.${name}`) !== false;
};
const isMutationEnabled = (schema, name) => {
return _.get(schema, ['resolver', 'Mutation', name]) !== false;
return _.get(schema, `resolver.Mutation.${name}`) !== false;
};
const buildTypeDefObj = model => {
@ -172,7 +173,7 @@ const buildAssocResolvers = model => {
if (association.type === 'model') {
params[targetModel.primaryKey] = _.get(
obj,
[association.alias, targetModel.primaryKey],
`${association.alias}.${targetModel.primaryKey}`,
obj[association.alias]
);
} else {
@ -289,7 +290,7 @@ const buildSingleType = model => {
const _schema = _.cloneDeep(_.get(strapi.plugins, 'graphql.config._schema.graphql', {}));
const globalType = _.get(_schema, ['type', model.globalId], {});
const globalType = _.get(_schema, `type.${model.globalId}`, {});
const localSchema = buildModelDefinition(model, globalType);
@ -308,7 +309,7 @@ const buildSingleType = model => {
Query: {
[singularName]: buildQuery(singularName, {
resolver: `${uid}.find`,
..._.get(_schema, ['resolver', 'Query', singularName], {}),
..._.get(_schema, `resolver.Query.${singularName}`, {}),
}),
},
},
@ -320,9 +321,9 @@ const buildSingleType = model => {
// build every mutation
['update', 'delete'].forEach(action => {
const mutationScheam = buildMutationTypeDef({ model, action }, { _schema });
const mutationSchema = buildMutationTypeDef({ model, action }, { _schema });
mergeSchemas(localSchema, mutationScheam);
mergeSchemas(localSchema, mutationSchema);
});
return localSchema;
@ -336,7 +337,7 @@ const buildCollectionType = model => {
const _schema = _.cloneDeep(_.get(strapi.plugins, 'graphql.config._schema.graphql', {}));
const globalType = _.get(_schema, ['type', model.globalId], {});
const globalType = _.get(_schema, `type.${model.globalId}`, {});
const localSchema = {
definition: '',
@ -370,50 +371,52 @@ const buildCollectionType = model => {
}
if (isQueryEnabled(_schema, singularName)) {
_.merge(localSchema, {
query: {
[`${singularName}(id: ID!)`]: model.globalId,
},
resolvers: {
Query: {
[singularName]: buildQuery(singularName, {
resolver: `${uid}.findOne`,
..._.get(_schema, ['resolver', 'Query', singularName], {}),
}),
const resolverOpts = {
resolver: `${uid}.findOne`,
..._.get(_schema, `resolver.Query.${pluralName}`, {}),
};
if (actionExists(resolverOpts)) {
_.merge(localSchema, {
query: {
[`${singularName}(id: ID!)`]: model.globalId,
},
},
});
resolvers: {
Query: {
[singularName]: buildQuery(singularName, resolverOpts),
},
},
});
}
}
if (isQueryEnabled(_schema, pluralName)) {
const resolverOpts = {
resolver: `${uid}.find`,
..._.get(_schema, ['resolver', 'Query', pluralName], {}),
..._.get(_schema, `resolver.Query.${pluralName}`, {}),
};
const resolverFn = buildQuery(pluralName, resolverOpts);
_.merge(localSchema, {
query: {
[`${pluralName}(sort: String, limit: Int, start: Int, where: JSON)`]: `[${model.globalId}]`,
},
resolvers: {
Query: {
[pluralName]: resolverFn,
if (actionExists(resolverOpts)) {
_.merge(localSchema, {
query: {
[`${pluralName}(sort: String, limit: Int, start: Int, where: JSON)`]: `[${model.globalId}]`,
},
},
});
resolvers: {
Query: {
[pluralName]: buildQuery(pluralName, resolverOpts),
},
},
});
// Generation the aggregation for the given model
const aggregationSchema = formatModelConnectionsGQL({
fields: typeDefObj,
model,
name: modelName,
resolver: resolverOpts,
plugin,
});
// Generate the aggregation for the given model
const aggregationSchema = formatModelConnectionsGQL({
fields: typeDefObj,
model,
name: modelName,
resolver: resolverOpts,
plugin,
});
mergeSchemas(localSchema, aggregationSchema);
mergeSchemas(localSchema, aggregationSchema);
}
}
// Add model Input definition.
@ -421,9 +424,8 @@ const buildCollectionType = model => {
// build every mutation
['create', 'update', 'delete'].forEach(action => {
const mutationScheam = buildMutationTypeDef({ model, action }, { _schema });
mergeSchemas(localSchema, mutationScheam);
const mutationSchema = buildMutationTypeDef({ model, action }, { _schema });
mergeSchemas(localSchema, mutationSchema);
});
return localSchema;
@ -433,10 +435,19 @@ const buildCollectionType = model => {
// - Implement batch methods (need to update the content-manager as well).
// - Implement nested transactional methods (create/update).
const buildMutationTypeDef = ({ model, action }, { _schema }) => {
const { uid } = model;
const capitalizedName = _.upperFirst(toSingular(model.modelName));
const mutationName = `${action}${capitalizedName}`;
const resolverOpts = {
resolver: `${model.uid}.${action}`,
transformOutput: result => ({ [toSingular(model.modelName)]: result }),
..._.get(_schema, `resolver.Mutation.${mutationName}`, {}),
};
if (!actionExists(resolverOpts)) {
return {};
}
const definition = types.generateInputPayloadArguments({
model,
name: model.modelName,
@ -465,13 +476,7 @@ const buildMutationTypeDef = ({ model, action }, { _schema }) => {
},
resolvers: {
Mutation: {
[mutationName]: buildMutation(mutationName, {
resolver: `${uid}.${action}`,
transformOutput: result => ({
[toSingular(model.modelName)]: result,
}),
..._.get(_schema, ['resolver', 'Mutation', mutationName], {}),
}),
[mutationName]: buildMutation(mutationName, resolverOpts),
},
},
};

View File

@ -87,6 +87,85 @@ const amountLimiting = (params = {}) => {
const nonRequired = type => type.replace('!', '');
const actionExists = ({ resolver, resolverOf }) => {
if (isResolvablePath(resolverOf)) {
return true;
} else if (_.isFunction(resolver)) {
return true;
} else if (_.isString(resolver)) {
return _.isFunction(getActionFn(getActionDetails(resolver)));
} else {
throw new Error(
`Error building query. Expected \`resolver\` as string or a function, or \`resolverOf\` as a string. got ${{
resolver,
resolverOf,
}}`
);
}
};
const getAction = resolver => {
if (!_.isString(resolver)) {
throw new Error(`Error building query. Expected a string, got ${resolver}`);
}
const actionDetails = getActionDetails(resolver);
const actionFn = getActionFn(actionDetails);
if (!actionFn) {
throw new Error(
`[GraphQL] Cannot find action "${resolver}". Check your graphql configurations.`
);
}
return actionFn;
};
const getActionFn = details => {
const { controller, action, plugin, api } = details;
if (plugin) {
return _.get(strapi.plugins, [_.toLower(plugin), 'controllers', _.toLower(controller), action]);
}
return _.get(strapi.api, [_.toLower(api), 'controllers', _.toLower(controller), action]);
};
const getActionDetails = resolver => {
if (resolver.startsWith('plugins::')) {
const [, path] = resolver.split('::');
const [plugin, controller, action] = path.split('.');
return { plugin, controller, action };
}
if (resolver.startsWith('application::')) {
const [, path] = resolver.split('::');
const [api, controller, action] = path.split('.');
return { api, controller, action };
}
const args = resolver.split('.');
if (args.length === 3) {
const [api, controller, action] = args;
return { api, controller, action };
}
// if direct api access
if (args.length === 2) {
const [controller, action] = args;
return { api: controller, controller, action };
}
throw new Error(
`[GraphQL] Could not find action for resolver "${resolver}". Check your graphql configurations.`
);
};
const isResolvablePath = path => _.isString(path) && !_.isEmpty(path);
module.exports = {
diffResolvers,
mergeSchemas,
@ -95,4 +174,9 @@ module.exports = {
convertToQuery,
amountLimiting,
nonRequired,
actionExists,
getAction,
getActionDetails,
getActionFn,
isResolvablePath,
};

View File

@ -104,9 +104,11 @@ module.exports = {
description: 'Update an existing role',
resolverOf: 'plugins::users-permissions.userspermissions.updateRole',
resolver: async (obj, options, { context }) => {
context.params = { ...context.params, ...options.input };
context.params.role = context.params.id;
await strapi.plugins['users-permissions'].controllers.userspermissions.updateRole(
context.params,
context.body
context
);
return { ok: true };
@ -116,6 +118,9 @@ module.exports = {
description: 'Delete an existing role',
resolverOf: 'plugins::users-permissions.userspermissions.deleteRole',
resolver: async (obj, options, { context }) => {
context.params = { ...context.params, ...options.input };
context.params.role = context.params.id;
await strapi.plugins['users-permissions'].controllers.userspermissions.deleteRole(
context
);

View File

@ -844,15 +844,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@buffetjs/core@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/core/-/core-3.0.5.tgz#52b7f38603814c761bf3382159b769590d8306e6"
integrity sha512-xY5xIi8b6QRFdYjGoPjWr6LmTV35wlsG6o3LeopkDViBVKtiVkmifv7mq64TcrHfuR8haolG8UsdE46Gy8HPoQ==
"@buffetjs/core@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/core/-/core-3.0.6.tgz#1a95540d76ba24bfa7881bbdfb673ca2925e717d"
integrity sha512-tT+SuKnnli9L7G2Bkyj79X6AERfT+tAjhCUMQcu2pTxKQTVDFYL/cqbtxWh43sikqfjnPxi+MjKBMrVo0Yp38g==
dependencies:
"@buffetjs/hooks" "3.0.5"
"@buffetjs/icons" "3.0.5"
"@buffetjs/styles" "3.0.5"
"@buffetjs/utils" "3.0.5"
"@buffetjs/hooks" "3.0.6"
"@buffetjs/icons" "3.0.6"
"@buffetjs/styles" "3.0.6"
"@buffetjs/utils" "3.0.6"
"@fortawesome/fontawesome-svg-core" "^1.2.25"
"@fortawesome/free-regular-svg-icons" "^5.11.2"
"@fortawesome/free-solid-svg-icons" "^5.11.2"
@ -863,31 +863,31 @@
react-dates "^21.5.1"
react-moment-proptypes "^1.7.0"
"@buffetjs/custom@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/custom/-/custom-3.0.5.tgz#ead4e52220b6254737717f9cb549e73ae46d17bc"
integrity sha512-VvzZtmngFVBxWj+3cd4nZ6ccWzis8SEb8ClzYV5n+EhMRLBiYDRJ8sjIIYSbDtu4HQv87p7Hh1MkFKy1FMbpjg==
"@buffetjs/custom@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/custom/-/custom-3.0.6.tgz#8d29fc69088ef11b82308142e8ca606de24f13c3"
integrity sha512-skzUI9jhC+9oy9i2LOqOUpigAabA81nhONz8AjV2TRzwMo0Mpav8jWGWVmILasziNCJwHIX7BxisgNWC8/C36Q==
dependencies:
"@buffetjs/core" "3.0.5"
"@buffetjs/styles" "3.0.5"
"@buffetjs/utils" "3.0.5"
"@buffetjs/core" "3.0.6"
"@buffetjs/styles" "3.0.6"
"@buffetjs/utils" "3.0.6"
moment "^2.24.0"
react-moment-proptypes "^1.7.0"
"@buffetjs/hooks@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/hooks/-/hooks-3.0.5.tgz#b48301102ec69c0ebc10d83eb8ace70adb0a2a58"
integrity sha512-6NSETsJ3EfPzLXRGHAcsRAImCTrzm6oAc3V8ijqSTajf0e70UPhntfCbcN+l0vpDVlqut3YArLQmfVznva2xsw==
"@buffetjs/hooks@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/hooks/-/hooks-3.0.6.tgz#98b3780fa005193a06f32af2b23e0782358ce5a6"
integrity sha512-boxLYVT/4RauTQmgLkdZWrwdMPS624/91rk4TqWARRmnXeP4+99MErHwqz5z3Bk8aBa3yNWpayu1p25fdoti6A==
"@buffetjs/icons@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/icons/-/icons-3.0.5.tgz#6784c60026e4ed1b7633c5d59dd0193e7c9467c8"
integrity sha512-GZgYLMJ7nkDhAiczK3vRj9OEkjw2pLMaHNVfQxeBgZk2JdWrMXFSPxeJrw4BLGExO7m1L6F9aEuLsw2R/OBR5w==
"@buffetjs/icons@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/icons/-/icons-3.0.6.tgz#162a103b0ee02a10de5d1eceb21ce72dd383e228"
integrity sha512-lvFJfyhbTnXJmnf6QBm7ZimkLpSZ7Uo5vJYmUJY2FpJbVlVgmWrsyEgwe78MglDjz8ONrdZDLw8lPvUfXsTRzg==
"@buffetjs/styles@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/styles/-/styles-3.0.5.tgz#102b3aa25bad017657dd3e87bf59c7cc979892f0"
integrity sha512-c4OFX/SBnevMZNofjiboxU/Ixx3eHS2Fb4dqVrKvHYAdTQhHVzcoECCqz2RZcRfUNpaLuJKhE9EeRGj2lmgHVA==
"@buffetjs/styles@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/styles/-/styles-3.0.6.tgz#bfa8d128fdd6e4bfb3a1317c609833c82aa2be49"
integrity sha512-4/FMUNUCmGPTJmbe0t9TaO26SiOGbvDuxZdefAtrHWwkvdFvjaofNquONBeSEag5gxlSZN/UKlTbiAq29v0b3Q==
dependencies:
"@fortawesome/fontawesome-free" "^5.12.0"
"@fortawesome/fontawesome-svg-core" "^1.2.22"
@ -896,10 +896,10 @@
"@fortawesome/react-fontawesome" "^0.1.4"
react-dates "^21.1.0"
"@buffetjs/utils@3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@buffetjs/utils/-/utils-3.0.5.tgz#24bd3f3c6f30a9f7d0851a7741dae5c70f8272ea"
integrity sha512-HFhqBBi8N8MTOkTa1/AuET26gET2tI8El1d10aCscLFx5mT7O94LUbspL6RwqTd62SkEli528aV/gBA5fHdTjA==
"@buffetjs/utils@3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@buffetjs/utils/-/utils-3.0.6.tgz#87f7e0822d907397ae62b4764edcddc516e3ad27"
integrity sha512-DfYrHtmta2KXTc8iy892uGzbs1ygZ37hiXLAYmSWZfJNNk8pamAqnRLcfjVDA/SgTQIVO8unmaPxi3141xfe/Q==
dependencies:
yup "^0.27.0"