Skip to content

Commit dad531b

Browse files
authored
Drafts Skeleton (#3960)
* drafts * remove elements
1 parent e12dfcb commit dad531b

File tree

10 files changed

+375
-0
lines changed

10 files changed

+375
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { Element, Checkbox, Text } from '@codesandbox/components';
3+
4+
interface Props {
5+
color: string;
6+
id: string;
7+
style?: React.CSSProperties;
8+
niceName: string;
9+
selected: boolean;
10+
toggleTemplate: (name: string, selected: boolean) => void;
11+
}
12+
13+
export const Option = ({
14+
color,
15+
id,
16+
style,
17+
niceName,
18+
selected,
19+
toggleTemplate,
20+
}: Props) => {
21+
const checkBoxName = `${id}-checkbox`;
22+
return (
23+
<Element
24+
// selected={selected}
25+
onClick={e => {
26+
e.preventDefault();
27+
toggleTemplate(id, !selected);
28+
}}
29+
onMouseDown={e => {
30+
e.preventDefault();
31+
}}
32+
style={style}
33+
>
34+
<label htmlFor={checkBoxName} style={{ display: 'none' }}>
35+
{checkBoxName}
36+
</label>
37+
<Checkbox id={checkBoxName} color={color} checked={selected} />
38+
<Text>{niceName}</Text>
39+
</Element>
40+
);
41+
};
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { orderBy } from 'lodash-es';
2+
import React, { FunctionComponent } from 'react';
3+
4+
import { useOvermind } from 'app/overmind';
5+
import { Overlay as OverlayComponent } from 'app/components/Overlay';
6+
import { Element, Text } from '@codesandbox/components';
7+
import { Option } from './Option';
8+
9+
type Template = {
10+
id: string;
11+
name: string;
12+
color: string;
13+
niceName: string;
14+
};
15+
type Props = {
16+
possibleTemplates?: Template[];
17+
};
18+
export const FilterOptions: FunctionComponent<Props> = ({
19+
possibleTemplates = [],
20+
}) => {
21+
const {
22+
actions: {
23+
dashboard: {
24+
blacklistedTemplateAdded,
25+
blacklistedTemplateRemoved,
26+
blacklistedTemplatesChanged,
27+
blacklistedTemplatesCleared,
28+
},
29+
},
30+
state: {
31+
dashboard: {
32+
filters: { blacklistedTemplates },
33+
isTemplateSelected,
34+
},
35+
},
36+
} = useOvermind();
37+
38+
const toggleTemplate = (name: string, select: boolean) =>
39+
select ? blacklistedTemplateRemoved(name) : blacklistedTemplateAdded(name);
40+
const allSelected = possibleTemplates.every(({ id }) =>
41+
isTemplateSelected(id)
42+
);
43+
44+
const Overlay = () => (
45+
<Element>
46+
{possibleTemplates.length > 0 ? (
47+
<>
48+
{orderBy(possibleTemplates, 'niceName').map(
49+
({ color, id, name, niceName }) => {
50+
const selected = isTemplateSelected(id);
51+
52+
return (
53+
<Option
54+
color={color}
55+
id={id}
56+
key={name}
57+
niceName={niceName || name}
58+
selected={selected}
59+
toggleTemplate={toggleTemplate}
60+
/>
61+
);
62+
}
63+
)}
64+
65+
<Option
66+
color="#374140"
67+
id="all"
68+
niceName="Select All"
69+
selected={allSelected}
70+
style={{ marginTop: '1rem' }}
71+
toggleTemplate={() => {
72+
if (allSelected) {
73+
return blacklistedTemplatesChanged(
74+
possibleTemplates.map(({ id }) => id)
75+
);
76+
}
77+
78+
return blacklistedTemplatesCleared();
79+
}}
80+
/>
81+
</>
82+
) : (
83+
'No environments found'
84+
)}
85+
</Element>
86+
);
87+
88+
const templateCount = possibleTemplates.length - blacklistedTemplates.length;
89+
const templateMessage =
90+
templateCount === possibleTemplates.length && templateCount > 0
91+
? 'all environments'
92+
: `${Math.max(0, templateCount)} ${
93+
templateCount === 1 ? 'environment' : 'environments'
94+
}`;
95+
96+
return (
97+
<OverlayComponent
98+
width={200}
99+
content={Overlay}
100+
event="Dashboard - Order By"
101+
>
102+
{open => (
103+
<Element>
104+
Showing <Text onClick={open}>{templateMessage}</Text>
105+
</Element>
106+
)}
107+
</OverlayComponent>
108+
);
109+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const FIELD_TO_NAME = {
2+
insertedAt: 'Last Created',
3+
updatedAt: 'Last Modified',
4+
title: 'Name',
5+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React, { FunctionComponent } from 'react';
2+
import Check from 'react-icons/lib/md/check';
3+
import { Element } from '@codesandbox/components';
4+
5+
type Props = {
6+
currentField: string;
7+
field: string;
8+
name: string;
9+
setField: (field: string) => void;
10+
};
11+
export const Option: FunctionComponent<Props> = ({
12+
currentField,
13+
field,
14+
name,
15+
setField,
16+
}) => {
17+
const selected = field === currentField;
18+
19+
return (
20+
<Element
21+
onClick={() => setField(field)}
22+
// selected={selected}
23+
>
24+
<Element>{selected && <Check />}</Element> {name}
25+
</Element>
26+
);
27+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, { FunctionComponent } from 'react';
2+
3+
import { useOvermind } from 'app/overmind';
4+
import { Element } from '@codesandbox/components';
5+
import { FIELD_TO_NAME } from '../FieldToName';
6+
import { Option } from './Option';
7+
8+
export const Overlay: FunctionComponent = () => {
9+
const {
10+
actions: {
11+
dashboard: { orderByChanged },
12+
},
13+
state: {
14+
dashboard: {
15+
orderBy: { field: currentField, order },
16+
},
17+
},
18+
} = useOvermind();
19+
20+
const setField = (field: string) => orderByChanged({ field, order });
21+
22+
return (
23+
<Element>
24+
<Option
25+
currentField={currentField}
26+
field="title"
27+
name={FIELD_TO_NAME.title}
28+
setField={setField}
29+
/>
30+
31+
<Option
32+
currentField={currentField}
33+
field="insertedAt"
34+
name={FIELD_TO_NAME.insertedAt}
35+
setField={setField}
36+
/>
37+
38+
<Option
39+
currentField={currentField}
40+
field="updatedAt"
41+
name={FIELD_TO_NAME.updatedAt}
42+
setField={setField}
43+
/>
44+
</Element>
45+
);
46+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, { FunctionComponent } from 'react';
2+
import ArrowDown from 'react-icons/lib/md/arrow-downward';
3+
import ArrowUp from 'react-icons/lib/md/arrow-upward';
4+
import { Overlay as OverlayComponent } from 'app/components/Overlay';
5+
import { useOvermind } from 'app/overmind';
6+
import { Element, Button } from '@codesandbox/components';
7+
import css from '@styled-system/css';
8+
import { FIELD_TO_NAME } from './FieldToName';
9+
import { Overlay } from './Overlay';
10+
11+
export const SortOptions: FunctionComponent = () => {
12+
const {
13+
actions: {
14+
dashboard: { orderByChanged },
15+
},
16+
state: {
17+
dashboard: {
18+
orderBy: { field, order },
19+
},
20+
},
21+
} = useOvermind();
22+
23+
const toggleSort = event => {
24+
event.preventDefault();
25+
26+
orderByChanged({
27+
field,
28+
order: order === 'asc' ? 'desc' : 'asc',
29+
});
30+
};
31+
32+
return (
33+
<OverlayComponent
34+
width={200}
35+
content={Overlay}
36+
event="Dashboard - Order By"
37+
>
38+
{open => (
39+
<Element>
40+
Sort by <Element onClick={open}>{FIELD_TO_NAME[field]}</Element>
41+
<Button
42+
variant="link"
43+
css={css({
44+
width: 'auto',
45+
})}
46+
onClick={toggleSort}
47+
>
48+
{order === 'desc' ? <ArrowDown /> : <ArrowUp />}
49+
</Button>
50+
</Element>
51+
)}
52+
</OverlayComponent>
53+
);
54+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import { Element } from '@codesandbox/components';
3+
import { FilterOptions } from './FilterOptions';
4+
import { SortOptions } from './SortOptions';
5+
6+
export const Filters = ({ possibleTemplates }) => (
7+
<Element>
8+
<FilterOptions possibleTemplates={possibleTemplates} />
9+
10+
<SortOptions />
11+
</Element>
12+
);

packages/app/src/app/pages/NewDashboard/Content/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import css from '@styled-system/css';
1313
import { StartSandboxes } from './routes/StartSandboxes';
1414
import { Templates } from './routes/Templates';
1515
import { Deleted } from './routes/Deleted';
16+
import { Drafts } from './routes/Drafts';
1617

1718
const ContentComponent = () => (
1819
<Element
@@ -28,6 +29,7 @@ const ContentComponent = () => (
2829
<Route path="/new-dashboard/start" component={StartSandboxes} />
2930
<Route path="/new-dashboard/templates" component={Templates} />
3031
<Route path="/new-dashboard/deleted" component={Deleted} />
32+
<Route path="/new-dashboard/drafts" component={Drafts} />
3133
{/* <Route path="/dashboard/trash" component={DeletedSandboxes} />
3234
<Route path="/dashboard/templates" exact component={Templates} />
3335
<Route path="/dashboard/sandboxes/:path*" component={PathedSandboxes} />
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import { Element, Text } from '@codesandbox/components';
3+
import { useQuery } from '@apollo/react-hooks';
4+
import {
5+
PathedSandboxesQueryVariables,
6+
PathedSandboxesQuery,
7+
} from 'app/graphql/types';
8+
import { PATHED_SANDBOXES_CONTENT_QUERY } from 'app/pages/NewDashboard/queries';
9+
10+
import css from '@styled-system/css';
11+
import { Filters } from 'app/pages/NewDashboard/Components/Filters';
12+
import { useOvermind } from 'app/overmind';
13+
import { getPossibleTemplates } from '../../utils';
14+
import { SandboxCard } from '../../../Components/SandboxCard';
15+
16+
export const Drafts = () => {
17+
const { state } = useOvermind();
18+
const { loading, error, data } = useQuery<
19+
PathedSandboxesQuery,
20+
PathedSandboxesQueryVariables
21+
>(PATHED_SANDBOXES_CONTENT_QUERY, {
22+
variables: { path: '/', teamId: null },
23+
});
24+
25+
if (error) {
26+
return <Text>Error</Text>;
27+
}
28+
29+
if (loading) {
30+
return <Text>loading</Text>;
31+
}
32+
33+
const sandboxes = data && data.me && data.me.collection.sandboxes;
34+
const possibleTemplates = getPossibleTemplates(sandboxes);
35+
const noTemplateSandboxes = sandboxes.filter(s => !s.customTemplate);
36+
const orderedSandboxes = state.dashboard.getFilteredSandboxes(
37+
// @ts-ignore
38+
noTemplateSandboxes
39+
);
40+
41+
return (
42+
<Element>
43+
<Text marginBottom={4} block>
44+
Drafts
45+
</Text>
46+
<Filters possibleTemplates={possibleTemplates} />
47+
<Element
48+
css={css({
49+
display: 'grid',
50+
gridTemplateColumns: 'repeat(4,1fr)',
51+
gridGap: 6,
52+
})}
53+
>
54+
{orderedSandboxes.map(sandbox => (
55+
<SandboxCard sandbox={sandbox} key={sandbox.id} />
56+
))}
57+
</Element>
58+
</Element>
59+
);
60+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { uniqBy } from 'lodash-es';
2+
import getDefinition from '@codesandbox/common/lib/templates';
3+
4+
export function getPossibleTemplates(sandboxes: any[]) {
5+
return uniqBy(
6+
sandboxes.map(x => {
7+
const templateId = x.source?.template;
8+
const template = getDefinition(templateId);
9+
10+
return {
11+
id: templateId,
12+
color: template.color,
13+
name: template.name,
14+
niceName: template.niceName,
15+
};
16+
}),
17+
template => template.id
18+
);
19+
}

0 commit comments

Comments
 (0)