Skip to content

Commit

Permalink
feat(gatsby-admin): plugin search (#25903)
Browse files Browse the repository at this point in the history
* Copy plugin search from www into admin

* Move to Combobox search

* Cleanup

* TypeScript cleanup

* add algolia types

* Fix syntax
  • Loading branch information
mxstbr committed Jul 21, 2020
1 parent a0c70d0 commit 0506123
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 84 deletions.
4 changes: 4 additions & 0 deletions packages/gatsby-admin/package.json
Expand Up @@ -15,18 +15,22 @@
"@emotion/styled": "^10.0.27",
"@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.28.0",
"@types/react-instantsearch-dom": "^5.2.6",
"csstype": "^2.6.10",
"formik": "^2.1.4",
"gatsby": "^2.24.7",
"gatsby-interface": "0.0.173",
"gatsby-plugin-typescript": "^2.4.16",
"gatsby-source-graphql": "^2.6.2",
"lodash-es": "^4.17.15",
"ncp": "^2.0.0",
"nodemon": "^2.0.4",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "^6.1.0",
"react-icons": "^3.10.0",
"react-instantsearch-dom": "^5.7.0",
"remove-markdown": "^0.3.0",
"strict-ui": "^0.1.3",
"subscriptions-transport-ws": "^0.9.16",
"theme-ui": "^0.4.0-alpha.3",
Expand Down
106 changes: 106 additions & 0 deletions packages/gatsby-admin/src/components/plugin-search.tsx
@@ -0,0 +1,106 @@
/* @jsx jsx */
import { jsx } from "strict-ui"
import { Spinner } from "theme-ui"
import {
InstantSearch,
Configure,
RefinementList,
ToggleRefinement,
connectAutoComplete,
} from "react-instantsearch-dom"
import {
Combobox,
ComboboxInput,
ComboboxPopover,
ComboboxList,
ComboboxOption,
} from "gatsby-interface"
import { useMutation } from "urql"

const SearchCombobox: React.FC<{
onSelect: (value: string) => void
}> = connectAutoComplete(({ hits, currentRefinement, refine, onSelect }) => (
<Combobox onSelect={onSelect}>
<ComboboxInput
sx={{ width: `20em` }}
aria-labelledby="plugin-search-label"
onChange={(e): void => refine(e.target.value)}
value={currentRefinement}
/>
<ComboboxPopover>
<ComboboxList aria-labelledby="plugin-search-label">
{hits.map(hit => (
<ComboboxOption
key={hit.objectID}
selected={false}
value={hit.name}
></ComboboxOption>
))}
</ComboboxList>
</ComboboxPopover>
</Combobox>
))

// the search bar holds the Search component in the InstantSearch widget
const PluginSearchInput: React.FC<{}> = () => {
const [{ fetching }, installGatbyPlugin] = useMutation(`
mutation installGatsbyPlugin($name: String!) {
createNpmPackage(npmPackage: {
name: $name,
dependencyType: "production"
}) {
id
name
}
createGatsbyPlugin(gatsbyPlugin: {
name: $name
}) {
id
name
}
}
`)

return (
<div>
<InstantSearch
apiKey="ae43b69014c017e05950a1cd4273f404"
appId="OFCNCOG2CU"
indexName="npm-search"
>
<div style={{ display: `none` }}>
<Configure analyticsTags={[`gatsby-plugins`]} />
<RefinementList
attribute="keywords"
transformItems={(items: Array<any>): Array<any> =>
items.map(({ count, ...item }) => {
return {
...item,
count: count || 0,
}
})
}
defaultRefinement={[`gatsby-component`, `gatsby-plugin`]}
/>
<ToggleRefinement
attribute="deprecated"
value={false}
label="No deprecated plugins"
defaultRefinement={true}
/>
</div>
{fetching ? (
<Spinner />
) : (
<SearchCombobox
onSelect={(value): void => {
installGatbyPlugin({ name: value })
}}
/>
)}
</InstantSearch>
</div>
)
}

export default PluginSearchInput
1 change: 1 addition & 0 deletions packages/gatsby-admin/src/components/providers.tsx
Expand Up @@ -28,6 +28,7 @@ const theme = {
"100%": `100%`,
"16px": `16px`,
"15em": `15em`,
"20em": `20em`,
initial: `initial`,
},
}
Expand Down
87 changes: 7 additions & 80 deletions packages/gatsby-admin/src/pages/index.tsx
@@ -1,93 +1,18 @@
/** @jsx jsx */
import React from "react"
import { jsx, Flex, Grid } from "strict-ui"
import { Spinner } from "theme-ui"
import { useQuery, useMutation } from "urql"
import {
Heading,
HeadingProps,
Text,
Button,
InputField,
InputFieldControl,
ButtonProps,
InputFieldLabel,
DropdownMenu,
DropdownMenuButton,
DropdownMenuItem,
DropdownMenuItems,
} from "gatsby-interface"

const SecondaryButton: React.FC<ButtonProps> = props => (
<Button
variant="SECONDARY"
size="S"
sx={{
paddingX: 6,
paddingY: 4,
}}
{...props}
></Button>
)

const InstallInput: React.FC<{ for: string }> = props => {
const inputId = `install-${props.for}`
const [value, setValue] = React.useState(``)

const [{ fetching }, installGatbyPlugin] = useMutation(`
mutation installGatsbyPlugin($name: String!) {
createNpmPackage(npmPackage: {
name: $name,
dependencyType: "production"
}) {
id
name
}
createGatsbyPlugin(gatsbyPlugin: {
name: $name
}) {
id
name
}
}
`)

return (
<form
onSubmit={(evt): void => {
evt.preventDefault()
if (value.indexOf(`gatsby-`) !== 0) return

installGatbyPlugin({
name: value,
})
}}
>
<InputField id={inputId}>
<Flex gap={2} flexDirection="column">
<InputFieldLabel>Install {props.for}:</InputFieldLabel>
<Flex gap={4} alignItems="center">
<InputFieldControl
placeholder={`gatsby-${props.for}-`}
disabled={fetching}
value={value}
onChange={(e): void => setValue(e.target.value)}
sx={{
width: `initial`,
}}
/>
<SecondaryButton
disabled={!value.trim()}
loading={fetching}
loadingLabel="Installing"
>
Install
</SecondaryButton>
</Flex>
</Flex>
</InputField>
</form>
)
}
import PluginSearchBar from "../components/plugin-search"

const SectionHeading: React.FC<HeadingProps> = props => (
<Heading as="h1" sx={{ fontWeight: `500`, fontSize: 5 }} {...props} />
Expand Down Expand Up @@ -181,7 +106,7 @@ const Index: React.FC<{}> = () => {
`,
})

if (fetching) return <p>Loading...</p>
if (fetching) return <Spinner />

if (error) return <p>Oops something went wrong.</p>

Expand All @@ -204,13 +129,15 @@ const Index: React.FC<{}> = () => {
))}
</ul>

<SectionHeading>Installed Plugins</SectionHeading>
<SectionHeading id="plugin-search-label">
Installed Plugins
</SectionHeading>
<Grid gap={6} columns={[1, 1, 1, 2, 3]}>
{data.allGatsbyPlugin.nodes.map(plugin => (
<PluginCard key={plugin.id} plugin={plugin} />
))}
</Grid>
<InstallInput for="plugin" />
<PluginSearchBar />
</Flex>
)
}
Expand Down

0 comments on commit 0506123

Please sign in to comment.