Skip to content

Commit

Permalink
First pass of field selection in new interfaces (#3753)
Browse files Browse the repository at this point in the history
* First pass of field selection in new interfaces

* manypkg fix

* Revert a change

* linting
  • Loading branch information
emmatown authored Sep 23, 2020
1 parent bd539f9 commit b319c4a
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 32 deletions.
99 changes: 83 additions & 16 deletions packages-next/admin-ui/src/pages/ListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import { useQuery, gql } from '../apollo';
import { jsx } from '@keystone-ui/core';
import Link from 'next/link';
import { useMemo } from 'react';

import { Fragment, useMemo } from 'react';
import { LinkIcon } from '@keystone-ui/icons/icons/LinkIcon';
import { PageContainer } from '../components/PageContainer';
import { useList } from '../KeystoneContext';
import { useRouter, Link } from '../router';

type ListPageProps = {
listKey: string;
Expand All @@ -15,9 +15,32 @@ type ListPageProps = {
export const ListPage = ({ listKey }: ListPageProps) => {
const list = useList(listKey);

const { query } = useRouter();
const selectedFieldsFromUrl = query.fields || '';
const selectedFields = useMemo(() => {
if (!query.fields) {
return {
includeLabel: true,
fields: list.initialColumns,
};
}
let includeLabel = false;
let fields = (selectedFieldsFromUrl as string).split(',').filter(field => {
if (field === '_label_') {
includeLabel = true;
return false;
}
return true;
});
return {
fields,
includeLabel,
};
}, [list.initialColumns, selectedFieldsFromUrl]);

let { data, error } = useQuery(
useMemo(() => {
let selectedFields = Object.keys(list.fields)
let selectedGqlFields = selectedFields.fields
.map(fieldPath => {
return list.fields[fieldPath].controller.graphqlSelection;
})
Expand All @@ -26,25 +49,45 @@ export const ListPage = ({ listKey }: ListPageProps) => {
query {
items: ${list.gqlNames.listQueryName} {
id
_label_
${selectedFields}
${selectedFields.includeLabel ? '_label_' : ''}
${selectedGqlFields}
}
}
`;
}, [list])
}, [list, selectedFields])
);

const shouldShowNonCellLink =
!selectedFields.includeLabel &&
!list.fields[selectedFields.fields[0]].views.Cell.supportsLinkTo;

return (
<PageContainer>
<h2>List: {list.label}</h2>
<p>
{data
? (() => {
const selectedFieldCount =
selectedFields.fields.length + Number(selectedFields.includeLabel);
return (
<Fragment>
Showing {data.items.length}{' '}
{data.items.length === 1 ? list.singular : list.plural} with {selectedFieldCount}{' '}
column{selectedFieldCount === 1 ? '' : 's'}
</Fragment>
);
})()
: ' '}
</p>
{error ? (
'Error...'
) : data ? (
<table>
<thead>
<tr>
<th>Label</th>
{Object.keys(list.fields).map(key => {
{selectedFields.includeLabel && <th>Label</th>}
{shouldShowNonCellLink && <th />}
{selectedFields.fields.map(key => {
return <th key={key}>{list.fields[key].label}</th>;
})}
</tr>
Expand All @@ -53,16 +96,40 @@ export const ListPage = ({ listKey }: ListPageProps) => {
{data.items.map((item: any) => {
return (
<tr key={item.id}>
<td>
<Link href={`/${list.path}/[id]`} as={`/${list.path}/${item.id}`}>
<a>{item._label_}</a>
</Link>
</td>
{Object.keys(list.fields).map(fieldKey => {
{selectedFields.includeLabel && (
<td>
<Link href={`/${list.path}/[id]`} as={`/${list.path}/${item.id}`}>
{item._label_}
</Link>
</td>
)}
{shouldShowNonCellLink && (
<td>
<Link
css={{ textDecoration: 'none' }}
href={`/${list.path}/[id]`}
as={`/${list.path}/${item.id}`}
>
<LinkIcon aria-label="Go to item" />
</Link>
</td>
)}
{selectedFields.fields.map((fieldKey, i) => {
let { Cell } = list.fields[fieldKey].views;
return (
<td key={fieldKey}>
<Cell item={item} path={fieldKey} />
<Cell
item={item}
path={fieldKey}
linkTo={
i === 0 && !selectedFields.includeLabel && Cell.supportsLinkTo
? {
href: `/${list.path}/[id]`,
as: `/${list.path}/${item.id}`,
}
: undefined
}
/>
</td>
);
})}
Expand Down
20 changes: 20 additions & 0 deletions packages-next/admin-ui/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,23 @@
*/

export * from 'next/router';
import NextLink, { LinkProps as NextLinkProps } from 'next/link';
import React, { AnchorHTMLAttributes } from 'react';

export type LinkProps = Omit<NextLinkProps, 'passHref'> &
Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>;

export const Link = ({ href, as, replace, scroll, shallow, prefetch, ...props }: LinkProps) => {
return (
<NextLink
href={href}
as={as}
replace={replace}
scroll={scroll}
shallow={shallow}
prefetch={prefetch}
>
<a {...props} />
</NextLink>
);
};
1 change: 1 addition & 0 deletions packages-next/admin-ui/src/utils/useAdminMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export function useAdminMeta(
Object.keys(adminMeta.lists).forEach(key => {
const list = adminMeta.lists[key];
runtimeAdminMeta.lists[key] = {
initialColumns: list.initialColumns,
gqlNames: list.gqlNames,
key,
fields: {},
Expand Down
1 change: 1 addition & 0 deletions packages-next/fields/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"@babel/runtime": "^7.11.2",
"@emotion/core": "^10.0.35",
"@keystone-spike/admin-ui": "*",
"@keystone-spike/types": "*",
"@keystone-ui/core": "*",
"@keystone-ui/fields": "*",
Expand Down
7 changes: 4 additions & 3 deletions packages-next/fields/src/types/checkbox/views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import { jsx, useTheme } from '@keystone-ui/core';
import { FieldContainer, Checkbox } from '@keystone-ui/fields';
import { CellProps, FieldProps, makeController } from '@keystone-spike/types';
import { CellComponent, FieldProps, makeController } from '@keystone-spike/types';
import { Fragment } from 'react';

export const Field = ({ field, value, onChange }: FieldProps<typeof controller>) => {
const { fields, typography } = useTheme();
Expand All @@ -22,8 +23,8 @@ export const Field = ({ field, value, onChange }: FieldProps<typeof controller>)
);
};

export const Cell = ({ item, path }: CellProps) => {
return item[path] + '';
export const Cell: CellComponent = ({ item, path }) => {
return <Fragment>{item[path] + ''}</Fragment>;
};

export const controller = makeController(config => {
Expand Down
7 changes: 4 additions & 3 deletions packages-next/fields/src/types/password/views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import { jsx } from '@keystone-ui/core';
import { FieldContainer, FieldLabel, TextInput } from '@keystone-ui/fields';

import { CellProps, FieldProps, makeController } from '@keystone-spike/types';
import { CellComponent, FieldProps, makeController } from '@keystone-spike/types';
import { Fragment } from 'react';

export const Field = ({ field, value, onChange }: FieldProps<typeof controller>) => (
<FieldContainer>
Expand All @@ -18,8 +19,8 @@ export const Field = ({ field, value, onChange }: FieldProps<typeof controller>)
</FieldContainer>
);

export const Cell = ({ item, path }: CellProps) => {
return item[`${path}_is_set`] ? 'Is set' : 'Is not set';
export const Cell: CellComponent = ({ item, path }) => {
return <Fragment>{item[`${path}_is_set`] ? 'Is set' : 'Is not set'}</Fragment>;
};

export const controller = makeController(config => {
Expand Down
10 changes: 7 additions & 3 deletions packages-next/fields/src/types/text/views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { jsx } from '@keystone-ui/core';
import { FieldContainer, FieldLabel, TextInput, TextArea } from '@keystone-ui/fields';

import {
CellProps,
CellComponent,
FieldControllerConfig,
FieldProps,
makeController,
} from '@keystone-spike/types';
import { Link } from '@keystone-spike/admin-ui/router';
import { Fragment } from 'react';

export const Field = ({ field, value, onChange }: FieldProps<typeof controller>) => (
<FieldContainer>
Expand All @@ -31,9 +33,11 @@ export const Field = ({ field, value, onChange }: FieldProps<typeof controller>)
</FieldContainer>
);

export const Cell = ({ item, path }: CellProps) => {
return item[path] + '';
export const Cell: CellComponent = ({ item, path, linkTo }) => {
let value = item[path] + '';
return linkTo ? <Link {...linkTo}>{value}</Link> : <Fragment>{value}</Fragment>;
};
Cell.supportsLinkTo = true;

type Config = FieldControllerConfig<{ isMultiline: boolean }>;

Expand Down
6 changes: 3 additions & 3 deletions packages-next/keystone/src/classes/Keystone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ export function createKeystone(config: KeystoneConfig): Keystone {
} as any) as any;
adminMeta.lists[key] = {
key,
// TODO: This should look for the admin description, not the graphQL description...
// This really all needs to be reviewed.
description: listConfig.graphql?.description ?? listConfig.description,
description: listConfig.admin?.description ?? listConfig.description,
label: list.adminUILabels.label,
singular: list.adminUILabels.singular,
plural: list.adminUILabels.plural,
path: list.adminUILabels.path,
fields: {},
gqlNames: list.gqlNames,
initialColumns:
listConfig.admin?.listView?.initialColumns ?? Object.keys(listConfig.fields).slice(0, 2),
};
for (const fieldKey of Object.keys(listConfig.fields)) {
const field = listConfig.fields[fieldKey];
Expand Down
14 changes: 10 additions & 4 deletions packages-next/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@ export type KeystoneConfig = {
admin?: KeystoneAdminConfig;
} & SchemaConfig;

export type CellProps = {
item: Record<string, any>;
path: string;
export type CellComponent = {
(props: {
item: Record<string, any>;
path: string;
linkTo: { href: string; as: string } | undefined;
}): ReactElement;

supportsLinkTo?: boolean;
};

type AllModes = 'edit' | 'read' | 'hidden';
Expand Down Expand Up @@ -166,6 +171,7 @@ type BaseListMeta = {
plural: string;
description?: string;
gqlNames: GqlNames;
initialColumns: string[];
};

export type SerializedListMeta = BaseListMeta & {
Expand Down Expand Up @@ -223,7 +229,7 @@ export type Keystone = {
export type FieldViews = {
[type: string]: {
Field: (props: FieldProps<any>) => ReactElement;
Cell: (props: CellProps) => ReactElement;
Cell: CellComponent;
controller: (args: FieldControllerConfig<any>) => FieldController<unknown>;
};
};
Expand Down

0 comments on commit b319c4a

Please sign in to comment.