diff --git a/web/components/CustomFormSelect/BranchSelector/BranchSelectorQuery.tsx b/web/components/CustomFormSelect/BranchSelector/BranchSelectorQuery.tsx index 5d015390..cdae33f6 100644 --- a/web/components/CustomFormSelect/BranchSelector/BranchSelectorQuery.tsx +++ b/web/components/CustomFormSelect/BranchSelector/BranchSelectorQuery.tsx @@ -1,4 +1,5 @@ import QueryHandler from "@components/util/QueryHandler"; +import { Maybe } from "@dolthub/web-utils"; import { useBranchesForSelectorQuery } from "@gen/graphql-types"; import useDefaultBranch from "@hooks/useDefaultBranch"; import { database } from "@lib/urls"; @@ -16,7 +17,8 @@ export default function BranchSelectorQuery(props: BranchSelectorForRepoProps) { }); const router = useRouter(); - const handleChangeBranch = async (branchName: string) => { + const handleChangeBranch = async (branchName: Maybe) => { + if (!branchName) return; const { href, as } = props.routeRefChangeTo ? props.routeRefChangeTo({ ...props.params, diff --git a/web/components/CustomFormSelect/BranchSelector/BranchSelectorWithTableQuery.tsx b/web/components/CustomFormSelect/BranchSelector/BranchSelectorWithTableQuery.tsx index 510a36f8..0a36fb88 100644 --- a/web/components/CustomFormSelect/BranchSelector/BranchSelectorWithTableQuery.tsx +++ b/web/components/CustomFormSelect/BranchSelector/BranchSelectorWithTableQuery.tsx @@ -1,4 +1,5 @@ import QueryHandler from "@components/util/QueryHandler"; +import { Maybe } from "@dolthub/web-utils"; import { useBranchesForSelectorQuery, useTableNamesLazyQuery, @@ -23,7 +24,8 @@ export default function BranchSelectorWithTableQuery( }); const router = useRouter(); - const handleChangeBranch = async (branchName: string) => { + const handleChangeBranch = async (branchName: Maybe) => { + if (!branchName) return; const variables = { databaseName: props.params.databaseName, refName: branchName, diff --git a/web/components/CustomFormSelect/BranchSelector/index.tsx b/web/components/CustomFormSelect/BranchSelector/index.tsx index c26c31ea..686fd6cf 100644 --- a/web/components/CustomFormSelect/BranchSelector/index.tsx +++ b/web/components/CustomFormSelect/BranchSelector/index.tsx @@ -1,4 +1,5 @@ import QueryHandler from "@components/util/QueryHandler"; +import { Maybe } from "@dolthub/web-utils"; import { useBranchesForSelectorQuery } from "@gen/graphql-types"; import useDefaultBranch from "@hooks/useDefaultBranch"; import { RefUrl } from "@lib/urls"; @@ -18,7 +19,7 @@ export function BranchSelector(props: BranchSelectorForRepoProps) { } type CustomProps = BranchSelectorForRepoProps & { - onChangeValue: (e: string) => void; + onChangeValue: (e: Maybe) => void; routeRefChangeTo?: RefUrl; }; diff --git a/web/components/CustomFormSelect/BranchSelector/types.ts b/web/components/CustomFormSelect/BranchSelector/types.ts index a9af9886..9e7e4fb1 100644 --- a/web/components/CustomFormSelect/BranchSelector/types.ts +++ b/web/components/CustomFormSelect/BranchSelector/types.ts @@ -1,3 +1,4 @@ +import { Maybe } from "@dolthub/web-utils"; import { BranchForBranchSelectorFragment } from "@gen/graphql-types"; import { OptionalRefParams, TableParams } from "@lib/params"; import { RefUrl } from "@lib/urls"; @@ -12,7 +13,7 @@ export type BranchSelectorForRepoProps = BaseFormSelectorProps & { export type BranchSelectorProps = BranchSelectorForRepoProps & { - onChangeValue: (e: string) => void; + onChangeValue: (e: Maybe) => void; branches: B[]; }; diff --git a/web/components/CustomFormSelect/CommitSelector.tsx b/web/components/CustomFormSelect/CommitSelector.tsx index 7804e715..264e3119 100644 --- a/web/components/CustomFormSelect/CommitSelector.tsx +++ b/web/components/CustomFormSelect/CommitSelector.tsx @@ -1,7 +1,9 @@ import QueryHandler from "@components/util/QueryHandler"; +import { Maybe } from "@dolthub/web-utils"; import { CommitForHistoryFragment } from "@gen/graphql-types"; import { useCommitListForBranch } from "@hooks/useCommitListForBranch"; import { RefParams } from "@lib/params"; +import { commitLog } from "@lib/urls"; import Selector from "./component"; import { BaseFormSelectorProps, Tab } from "./types"; import { getCommitLabel } from "./utils"; @@ -9,7 +11,7 @@ import { getCommitLabel } from "./utils"; type Props = BaseFormSelectorProps & { params: RefParams; tabs: Tab[]; - onChangeValue: (e: string) => void; + onChangeValue: (e: Maybe) => void; }; type InnerProps = { @@ -34,10 +36,10 @@ function Inner({ commits, ...props }: InnerProps) { label: getCommitLabel(c), }; })} - // footerLink={{ - // urlString: "View all commits", - // urlParams: commitLog(props.params), - // }} + footerLink={{ + urlString: "View all commits", + urlParams: commitLog(props.params), + }} /> ); diff --git a/web/components/CustomFormSelect/ForBranchesAndCommits.tsx b/web/components/CustomFormSelect/ForBranchesAndCommits.tsx index 347a4a69..9cfc9051 100644 --- a/web/components/CustomFormSelect/ForBranchesAndCommits.tsx +++ b/web/components/CustomFormSelect/ForBranchesAndCommits.tsx @@ -1,4 +1,5 @@ import { useEffectOnMount } from "@dolthub/react-hooks"; +import { Maybe } from "@dolthub/web-utils"; import useDefaultBranch from "@hooks/useDefaultBranch"; import { OptionalRefParams } from "@lib/params"; import { useEffect, useState } from "react"; @@ -8,8 +9,8 @@ import TabWrapper from "./TabWrapper"; type Props = { params: OptionalRefParams; - selectedValue: string; - onChangeValue: (s: string) => void; + selectedValue: Maybe; + onChangeValue: (s: Maybe) => void; }; export default function ForBranchesAndCommits(props: Props) { diff --git a/web/components/CustomFormSelect/TagSelector.tsx b/web/components/CustomFormSelect/TagSelector.tsx index ef91eadf..6daa48c1 100644 --- a/web/components/CustomFormSelect/TagSelector.tsx +++ b/web/components/CustomFormSelect/TagSelector.tsx @@ -1,6 +1,7 @@ +import { Maybe } from "@dolthub/web-utils"; import { TagForListFragment } from "@gen/graphql-types"; import { DatabaseParams } from "@lib/params"; -import { RefUrl, database } from "@lib/urls"; +import { RefUrl, database, releases } from "@lib/urls"; import { useRouter } from "next/router"; import Selector from "./component"; import { BaseFormSelectorProps, Tab } from "./types"; @@ -15,7 +16,8 @@ type Props = BaseFormSelectorProps & { export default function TagSelector(props: Props) { const router = useRouter(); - const handleChangeRef = async (refName: string) => { + const handleChangeRef = async (refName: Maybe) => { + if (!refName) return; const { href, as } = props.routeRefChangeTo ? props.routeRefChangeTo({ ...props.params, @@ -41,10 +43,10 @@ export default function TagSelector(props: Props) { label: t.tagName, }; })} - // footerLink={{ - // urlString: "View all tags", - // urlParams: releases(props.params), - // }} + footerLink={{ + urlString: "View all tags", + urlParams: releases(props.params), + }} /> ); diff --git a/web/components/CustomFormSelect/component.tsx b/web/components/CustomFormSelect/component.tsx index e52990b4..b8965718 100644 --- a/web/components/CustomFormSelect/component.tsx +++ b/web/components/CustomFormSelect/component.tsx @@ -1,4 +1,4 @@ -import FormSelect from "@components/FormSelect"; +import { FormSelect } from "@dolthub/react-components"; import cx from "classnames"; import DoltDisabledSelector from "./DoltDisabledSelector"; import css from "./index.module.css"; diff --git a/web/components/CustomFormSelect/selectorComponents.tsx b/web/components/CustomFormSelect/selectorComponents.tsx index e1548af3..d177a62f 100644 --- a/web/components/CustomFormSelect/selectorComponents.tsx +++ b/web/components/CustomFormSelect/selectorComponents.tsx @@ -1,17 +1,19 @@ -import { Option } from "@components/FormSelect"; import Link from "@components/links/Link"; -import { FiCheck } from "@react-icons/all-files/fi/FiCheck"; -import cx from "classnames"; import { + FormSelectTypes, MenuProps, OptionProps, SingleValueProps, components, -} from "react-select"; +} from "@dolthub/react-components"; +import { FiCheck } from "@react-icons/all-files/fi/FiCheck"; +import cx from "classnames"; import SelectTabs from "./SelectTabs"; import css from "./index.module.css"; import { FooterProps, FormSelectorProps } from "./types"; +type Option = FormSelectTypes.Option; + function SingleValueComponent( props: SingleValueProps, ): JSX.Element { diff --git a/web/components/CustomFormSelect/types.ts b/web/components/CustomFormSelect/types.ts index 53e123dd..03879b69 100644 --- a/web/components/CustomFormSelect/types.ts +++ b/web/components/CustomFormSelect/types.ts @@ -1,4 +1,4 @@ -import { Option } from "@components/FormSelect"; +import { FormSelectTypes } from "@dolthub/react-components"; import { Maybe, Route } from "@dolthub/web-utils"; export type Tab = { @@ -27,9 +27,9 @@ export type FooterProps = { }; export type FormSelectorProps = BaseFormSelectorProps & { - onChangeValue: (e: string) => void; - val?: Maybe; - options: Option[]; + onChangeValue: (e: Maybe) => void; + val: Maybe; + options: Array>; label: string; dataCySuffix?: string; noneFoundMsg?: string; diff --git a/web/components/DatabaseHeaderAndNav/Full.tsx b/web/components/DatabaseHeaderAndNav/Full.tsx index ebcf05e4..1f45482b 100644 --- a/web/components/DatabaseHeaderAndNav/Full.tsx +++ b/web/components/DatabaseHeaderAndNav/Full.tsx @@ -34,7 +34,7 @@ export default function Full(props: Props) { {...props} onMenuClick={() => props.setShowSmall(true)} /> - + diff --git a/web/components/DatabaseHeaderAndNav/MobileHeaderSelector.tsx b/web/components/DatabaseHeaderAndNav/MobileHeaderSelector.tsx index 6eac8fcb..92c40205 100644 --- a/web/components/DatabaseHeaderAndNav/MobileHeaderSelector.tsx +++ b/web/components/DatabaseHeaderAndNav/MobileHeaderSelector.tsx @@ -1,71 +1,39 @@ -import FormSelect from "@components/FormSelect"; -import { Option } from "@components/FormSelect/types"; +import { FormSelect, FormSelectTypes } from "@dolthub/react-components"; +import { Maybe } from "@dolthub/web-utils"; import useDatabaseDetails from "@hooks/useDatabaseDetails"; import { getDatabasePageName, getDatabasePageRedirectInfo, } from "@lib/mobileUtils"; import { OptionalRefParams } from "@lib/params"; -import { colors } from "@lib/tailwind"; import { useRouter } from "next/router"; -import { GroupBase, StylesConfig } from "react-select"; +import css from "./index.module.css"; type Props = { params: OptionalRefParams; - className?: string; title?: string; }; -const getTabOptions = (isDolt: boolean, hideDoltFeature: boolean): Option[] => { +const getTabOptions = ( + isDolt: boolean, + hideDoltFeature: boolean, +): Array> => { if (hideDoltFeature) return [{ value: "ref", label: "Database" }]; return [ { value: "ref", label: "Database" }, { value: "about", label: "About", isDisabled: !isDolt }, { value: "commitLog", label: "Commit Log", isDisabled: !isDolt }, { value: "releases", label: "Releases", isDisabled: !isDolt }, - // { value: "pulls", label: "Pull Requests", isDisabled: !isDolt }, + { value: "pulls", label: "Pull Requests", isDisabled: !isDolt }, ]; }; -const mobileSelectorStyle: StylesConfig> = { - placeholder: styles => { - return { - ...styles, - color: "#FFFFFFE5", - }; - }, - control: styles => { - return { - ...styles, - backgroundColor: "rgba(255, 255, 255, 0.1)", - borderColor: "rgba(255, 255, 255, 0.1)", - marginTop: "1rem", - }; - }, - menu: styles => { - return { - ...styles, - color: colors["ld-darkergrey"], - }; - }, - singleValue: styles => { - return { - ...styles, - color: "#FFFFFFE5", - }; - }, - dropdownIndicator: styles => { - return { - ...styles, - }; - }, -}; - export default function MobileHeaderSelector(props: Props) { const res = useDatabaseDetails(); const router = useRouter(); - const handleChangeTab = (pageName: string) => { + const handleChangeTab = (pageName: Maybe) => { + if (!pageName) return; const { href, as } = getDatabasePageRedirectInfo(pageName, props.params); router.push(href, as).catch(console.error); }; @@ -77,9 +45,8 @@ export default function MobileHeaderSelector(props: Props) { options={getTabOptions(res.isDolt, res.hideDoltFeature)} val={pageName} hideSelectedOptions - styles={mobileSelectorStyle} - className={props.className} - isMobile + outerClassName={css.mobileSelector} + forMobile /> ); } diff --git a/web/components/DiffSelector/ForBranch.tsx b/web/components/DiffSelector/ForBranch.tsx index 1564ee97..12db58c1 100644 --- a/web/components/DiffSelector/ForBranch.tsx +++ b/web/components/DiffSelector/ForBranch.tsx @@ -1,5 +1,6 @@ -import FormSelect from "@components/FormSelect"; import QueryHandler from "@components/util/QueryHandler"; +import { FormSelect } from "@dolthub/react-components"; +import { Maybe } from "@dolthub/web-utils"; import { CommitListForDiffSelectorFragment, useCommitsForDiffSelectorQuery, @@ -32,8 +33,8 @@ function Inner(props: InnerProps) { }; }); - const setFromCommitId = (id?: string) => { - const diffPaths = diff({ ...props.params, fromCommitId: id }); + const setFromCommitId = (id: Maybe) => { + const diffPaths = diff({ ...props.params, fromCommitId: id ?? undefined }); router.push(diffPaths.href, diffPaths.as).catch(console.error); }; diff --git a/web/components/DiffTable/DataDiff/FilterByType.tsx b/web/components/DiffTable/DataDiff/FilterByType.tsx index 893ec20b..0b7be752 100644 --- a/web/components/DiffTable/DataDiff/FilterByType.tsx +++ b/web/components/DiffTable/DataDiff/FilterByType.tsx @@ -1,33 +1,33 @@ +import { FormSelect } from "@dolthub/react-components"; +import { Maybe } from "@dolthub/web-utils"; import { DiffRowType } from "@gen/graphql-types"; -import FormSelect from "@components/FormSelect"; import css from "./index.module.css"; type Props = { - filter?: DiffRowType; - setFilter: (f?: DiffRowType) => void; + filter: Maybe; + setFilter: (f: Maybe) => void; }; export default function FilterByType(props: Props) { return ( -
- Filter by -
- -
-
+ ); } diff --git a/web/components/DiffTable/DataDiff/index.module.css b/web/components/DiffTable/DataDiff/index.module.css index ddaa8f69..56d0ffea 100644 --- a/web/components/DiffTable/DataDiff/index.module.css +++ b/web/components/DiffTable/DataDiff/index.module.css @@ -164,7 +164,7 @@ @apply absolute mb-6 right-2 ml-14 hidden -top-20; @screen lg { - @apply flex -top-10; + @apply flex items-center -top-10; } a { @@ -172,16 +172,12 @@ } } -.filterContainer { - @apply flex ml-4; - - > span { - @apply mr-4 mt-0.5; - } +.filterLabel { + @apply font-normal ml-4; } .filterSelect { - @apply w-40; + @apply w-36; } .err { diff --git a/web/components/DiffTable/DataDiff/index.tsx b/web/components/DiffTable/DataDiff/index.tsx index f255703c..d4769632 100644 --- a/web/components/DiffTable/DataDiff/index.tsx +++ b/web/components/DiffTable/DataDiff/index.tsx @@ -5,6 +5,7 @@ import { useDataTableContext } from "@contexts/dataTable"; import { useDiffContext } from "@contexts/diff"; import { Button, Loader } from "@dolthub/react-components"; import { useFocus } from "@dolthub/react-hooks"; +import { Maybe } from "@dolthub/web-utils"; import { DiffRowType } from "@gen/graphql-types"; import { ApolloErrorType } from "@lib/errors/types"; import { RequiredRefsParams } from "@lib/params"; @@ -32,7 +33,7 @@ type Props = { type InnerProps = Props & { fetchMore: () => Promise; - setFilter: (d: DiffRowType | undefined) => void; + setFilter: (d: Maybe) => void; state: RowDiffState; hasMore: boolean; error?: ApolloErrorType; diff --git a/web/components/DiffTable/DataDiff/state.ts b/web/components/DiffTable/DataDiff/state.ts index cf0a2206..99319587 100644 --- a/web/components/DiffTable/DataDiff/state.ts +++ b/web/components/DiffTable/DataDiff/state.ts @@ -11,7 +11,7 @@ export const defaultState = { offset: undefined as Maybe, rowDiffs: [] as RowDiffForTableListFragment[], cols: [] as ColumnForDiffTableListFragment[], - filter: undefined as DiffRowType | undefined, + filter: null as Maybe, }; export type RowDiffState = typeof defaultState; diff --git a/web/components/DiffTable/DataDiff/useRowDiffs.ts b/web/components/DiffTable/DataDiff/useRowDiffs.ts index 92920502..b54cd3c6 100644 --- a/web/components/DiffTable/DataDiff/useRowDiffs.ts +++ b/web/components/DiffTable/DataDiff/useRowDiffs.ts @@ -18,7 +18,7 @@ import { RowDiffState, getDefaultState } from "./state"; type ReturnType = { fetchMore: () => Promise; - setFilter: (d: DiffRowType | undefined) => void; + setFilter: (d: Maybe) => void; state: RowDiffState; hasMore: boolean; loading: boolean; @@ -48,7 +48,7 @@ export default function useRowDiffs( const handleQuery = async ( setRowDiffs: (rd: RowDiffForTableListFragment[]) => void, offset: Maybe, - filterByRowType?: DiffRowType, + filterByRowType: Maybe, ) => { if (err) setErr(undefined); if (offset === undefined || offset === null) { @@ -74,7 +74,7 @@ export default function useRowDiffs( }; // Changes diff row filter, starts with first page diffs - const setFilter = async (rowType?: DiffRowType) => { + const setFilter = async (rowType: Maybe) => { setState({ filter: rowType }); const setRowDiffs = (rd: RowDiffForTableListFragment[]) => setState({ rowDiffs: rd }); diff --git a/web/components/EditCellInput/Input.tsx b/web/components/EditCellInput/Input.tsx index 5e662654..4e1375b8 100644 --- a/web/components/EditCellInput/Input.tsx +++ b/web/components/EditCellInput/Input.tsx @@ -1,4 +1,4 @@ -import FormSelect from "@components/FormSelect"; +import { FormSelect } from "@dolthub/react-components"; import { splitEnumOptions } from "@lib/dataTable"; import cx from "classnames"; import css from "./index.module.css"; @@ -43,9 +43,18 @@ export default function Input(props: Props) { value: t, }; })} - onChangeValue={props.setNewValue} - className={css.editSelect} + onChangeValue={v => props.setNewValue(v ?? "")} + outerClassName={css.editSelect} mono + small + customStyles={s => { + return { + ...s, + singleValue: styles => { + return { ...styles, marginBottom: "6px" }; + }, + }; + }} /> ); } diff --git a/web/components/FormSelect/customComponents.tsx b/web/components/FormSelect/customComponents.tsx deleted file mode 100644 index a94fdef3..00000000 --- a/web/components/FormSelect/customComponents.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { AiFillCaretDown } from "@react-icons/all-files/ai/AiFillCaretDown"; -import { GroupBase, SelectComponentsConfig } from "react-select"; -import css from "./index.module.css"; - -function Dropdown() { - return ; -} - -type Components = - | Partial>> - | undefined; - -export function getComponents( - components?: Components, -): Components { - return { - ...components, - IndicatorSeparator: () => null, - DropdownIndicator: Dropdown, - }; -} diff --git a/web/components/FormSelect/index.module.css b/web/components/FormSelect/index.module.css deleted file mode 100644 index efc65642..00000000 --- a/web/components/FormSelect/index.module.css +++ /dev/null @@ -1,15 +0,0 @@ -.horizontal { - @apply flex items-center; -} - -.label { - @apply font-semibold text-primary mb-2; -} - -.horizontalLabel { - @apply mr-3 mb-0; -} - -.dropdownIndicator { - @apply mr-3; -} diff --git a/web/components/FormSelect/index.test.tsx b/web/components/FormSelect/index.test.tsx deleted file mode 100644 index e01a20b9..00000000 --- a/web/components/FormSelect/index.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { randomArrayItem } from "@dolthub/web-utils"; -import { - fireEvent, - queryByAttribute, - render, - screen, -} from "@testing-library/react"; -import selectEvent from "react-select-event"; -import FormSelect from "./index"; -import { Option } from "./types"; - -const optionWithoutIconPath: Option[] = [...Array(5).keys()].map(i => { - return { - label: `test${i}`, - value: `test${i}`, - }; -}); - -const mocks = [{ options: optionWithoutIconPath }]; - -describe("test FormSelect", () => { - mocks.forEach(mock => { - it("it renders component and is clickable", async () => { - const onChangeValue = jest.fn(); - render( - , - ); - - // expand the options - fireEvent.mouseDown(screen.getByRole("combobox")); - mock.options.forEach(option => { - expect(screen.getByText(option.value)).toBeVisible(); - }); - - // click new value - await selectEvent.select( - screen.getByText(mock.options[0].value), - mock.options[1].value, - ); - - // check that onChangeValue has been called - expect(onChangeValue).toHaveBeenCalled(); - fireEvent.mouseDown(screen.getByRole("combobox")); - }); - - it("shows the selected option first if selectedOptionFirst is true", async () => { - const selected = randomArrayItem(mock.options); - const { container } = render( - {}} - />, - ); - - // expand the options - fireEvent.mouseDown(screen.getByRole("combobox")); - - // Difficult to get the inner MenuList by anything else - const menuList = queryByAttribute("class", container, /MenuList/); - if (!menuList) { - throw Error("MenuList not found"); - } - expect(menuList.firstChild).toHaveTextContent(selected.value); - }); - }); -}); diff --git a/web/components/FormSelect/index.tsx b/web/components/FormSelect/index.tsx deleted file mode 100644 index 1267ca23..00000000 --- a/web/components/FormSelect/index.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import customStyles from "@lib/selectStyles"; -import cx from "classnames"; -import React from "react"; -import Select from "react-select"; -import { getComponents } from "./customComponents"; -import css from "./index.module.css"; -import { Option, OptionWithDetails, Props } from "./types"; -import { - getOnChange, - getValue, - getValueForOptions, - moveSelectedToTop, -} from "./utils"; - -/* -This custom FormSelect component is simplified to accept values/onChange arguments that represent the `value` field on an `OptionType`. - -For example, instead of using the full OptionType as a value (i.e. value={ value: "Taylor", label: "Name" }) we can just use the string "Taylor" and the `getValueForOptions` finds the matching `OptionType` within the provided `options`. A custom `getValueForOptions` function can be provided using the `getValFunc` prop. - -It has also been adjusted to accept values other than strings, like numbers, enums, etc. -*/ -export default function FormSelect({ - mono = false, - light = false, - small = false, - horizontal = false, - selectedOptionFirst: selectedFirst = false, - pill = false, - transparentBorder = false, - ...props -}: Props