Skip to content
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

Add displayMode: 'count' to relationship field #5630

Merged
merged 2 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/famous-countries-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-next/fields': minor
---

Added `ui.displayMode: 'count'` to `many` relationship fields
4 changes: 4 additions & 0 deletions docs/pages/apis/fields.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ Read our [relationships guide](../guides/relationships) for details on Keystone
- `inlineCreate` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An inline `Create` button will be included in the cards allowing a new related item to be created based on the configured field paths.
- `inlineEdit` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An `Edit` button will be included in each card, allowing the configured fields to be edited for each related item.
- `inlineConnect` (default: `false`): If `true`, an inline `Link existing item` button will be present, allowing existing items of the related list to be connected in this field.
- `ui.displayMode === 'count'` only supports `many` relationships

```typescript
import { config, createSchema, list } from '@keystone-next/keystone/schema';
Expand All @@ -457,6 +458,9 @@ export default config({
inlineCreate: { fields: [...] },
inlineEdit: { fields: [...] },
inlineConnect: true,
// Display mode: 'count'
// requires many: true above
displayMode: 'count',
},
}),
/* ... */
Expand Down
12 changes: 11 additions & 1 deletion packages-next/fields/src/types/relationship/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ type CardsDisplayConfig = {
};
};

type CountDisplayConfig = {
many: true;
ui?: {
// Sets the relationship to display as a count
displayMode: 'count';
};
};

export type RelationshipFieldConfig<
TGeneratedListTypes extends BaseGeneratedListTypes
> = FieldConfig<TGeneratedListTypes> & {
Expand All @@ -45,7 +53,7 @@ export type RelationshipFieldConfig<
};
defaultValue?: FieldDefaultValue<Record<string, unknown>>;
isUnique?: boolean;
} & (SelectDisplayConfig | CardsDisplayConfig);
} & (SelectDisplayConfig | CardsDisplayConfig | CountDisplayConfig);

export const relationship = <TGeneratedListTypes extends BaseGeneratedListTypes>(
config: RelationshipFieldConfig<TGeneratedListTypes>
Expand Down Expand Up @@ -83,6 +91,8 @@ export const relationship = <TGeneratedListTypes extends BaseGeneratedListTypes>
inlineEdit: config.ui.inlineEdit ?? null,
inlineConnect: config.ui.inlineConnect ?? false,
}
: config.ui?.displayMode === 'count'
? { displayMode: 'count' }
: {
displayMode: 'select',
refLabelField: adminMetaRoot.listsByKey[refListKey].labelField,
Expand Down
43 changes: 40 additions & 3 deletions packages-next/fields/src/types/relationship/views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ export const Field = ({
);
}

if (value.kind === 'count') {
return (
<Stack as="fieldset" gap="medium">
<FieldLegend>{field.label}</FieldLegend>
<div>
{value.count === 1
? `There is 1 ${foreignList.singular} `
: `There are ${value.count} ${foreignList.plural} `}
linked to this {localList.singular}
</div>
</Stack>
);
}

return (
<FieldContainer>
<FieldLabel as="legend">{field.label}</FieldLabel>
Expand Down Expand Up @@ -245,11 +259,21 @@ export const Field = ({

export const Cell: CellComponent<typeof controller> = ({ field, item }) => {
const list = useList(field.refListKey);
const { colors } = useTheme();

if (field.display.mode === 'count') {
const count = item[`_${field.path}Meta`]?.count ?? 0;
return (
<CellContainer>
{count} {count === 1 ? list.singular : list.plural}
</CellContainer>
);
}

const data = item[field.path];
const items = (Array.isArray(data) ? data : [data]).filter(item => item);
const displayItems = items.length < 5 ? items : items.slice(0, 3);
const overflow = items.length < 5 ? 0 : items.length - 3;
const { colors } = useTheme();
const styles = {
color: colors.foreground,
textDecoration: 'none',
Expand Down Expand Up @@ -312,9 +336,13 @@ type CardsRelationshipValue = {
initialIds: ReadonlySet<string>;
currentIds: ReadonlySet<string>;
};
type CountRelationshipValue = {
kind: 'count';
count: number;
};

type RelationshipController = FieldController<
ManyRelationshipValue | SingleRelationshipValue | CardsRelationshipValue
ManyRelationshipValue | SingleRelationshipValue | CardsRelationshipValue | CountRelationshipValue
> & {
display:
| {
Expand All @@ -329,7 +357,8 @@ type RelationshipController = FieldController<
inlineCreate: { fields: string[] } | null;
inlineEdit: { fields: string[] } | null;
inlineConnect: boolean;
};
}
| { mode: 'count' };
listKey: string;
refListKey: string;
hideCreate: boolean;
Expand All @@ -356,6 +385,7 @@ export const controller = (
inlineEdit: { fields: string[] } | null;
inlineConnect: boolean;
}
| { displayMode: 'count' }
)
>
): RelationshipController => {
Expand All @@ -375,6 +405,8 @@ export const controller = (
removeMode: config.fieldMeta.removeMode,
inlineConnect: config.fieldMeta.inlineConnect,
}
: config.fieldMeta.displayMode === 'count'
? { mode: 'count' }
: {
mode: 'select',
refLabelField: config.fieldMeta.refLabelField,
Expand All @@ -387,6 +419,8 @@ export const controller = (
${config.path} {
id
}`
: config.fieldMeta.displayMode === 'count'
? `_${config.path}Meta {count}`
: `${config.path} {
id
label: ${config.fieldMeta.refLabelField}
Expand All @@ -400,6 +434,9 @@ export const controller = (
}
: { kind: 'one', value: null, initialValue: null },
deserialize: data => {
if (config.fieldMeta.displayMode === 'count') {
return { kind: 'count', count: data[`_${config.path}Meta`]?.count ?? 0 };
}
if (config.fieldMeta.displayMode === 'cards') {
const initialIds = new Set<string>(
(Array.isArray(data[config.path])
Expand Down