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

Search bar for settings #9887

Open
wants to merge 56 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
1eff4da
WIP: Extract search bar into a React Context
somebody1234 May 6, 2024
cabff0e
Get original search bar behavior back
somebody1234 May 6, 2024
a154d30
Add UI for settings search bar
somebody1234 May 6, 2024
145a19b
WIP: Convert settings to an object so it can be filtered
somebody1234 May 6, 2024
f9b4588
WIP
somebody1234 May 7, 2024
ee94a12
No more errors
somebody1234 May 7, 2024
0c1faa4
Minor CSS changes for keyboard shortcuts table
somebody1234 May 8, 2024
d201f73
Add column numbers
somebody1234 May 8, 2024
383053b
Move SettingsInput out of folder
somebody1234 May 8, 2024
378310d
Fix SettingsInput
somebody1234 May 8, 2024
56654e3
Fix settings tab CSS
somebody1234 May 8, 2024
41051c2
Initial implementation of search!
somebody1234 May 8, 2024
d515396
Switch to react-query to load members
somebody1234 May 8, 2024
3dbf0cf
Fix lints
somebody1234 May 8, 2024
186f2b2
Fix minor bug in search
somebody1234 May 8, 2024
7909803
Prettier
somebody1234 May 8, 2024
e5ca097
Merge branch 'develop' into wip/sb/search-settings
somebody1234 May 9, 2024
62fa8b7
Add back User Groups settings tab
somebody1234 May 9, 2024
f6d9095
Fix lint errors
somebody1234 May 9, 2024
d883348
Merge branch 'develop' into wip/sb/search-settings
somebody1234 May 10, 2024
377e23d
Prettier
somebody1234 May 10, 2024
9fdecaa
Merge branch 'develop' into wip/sb/search-settings
somebody1234 May 30, 2024
1e9ba33
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 10, 2024
37cefb7
Prettier
somebody1234 Jun 10, 2024
53e720c
Only show matching sections from the current page
somebody1234 Jun 11, 2024
568679a
Add `getExtraAliases` for better search results
somebody1234 Jun 11, 2024
9547bcf
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 12, 2024
a5c5e98
Add asset search bar back
somebody1234 Jun 13, 2024
8e4f19e
Add settings search bar back
somebody1234 Jun 13, 2024
7778565
Fix `tertiary` buttons
somebody1234 Jun 13, 2024
737a384
Prettier
somebody1234 Jun 13, 2024
7487521
WIP: Fix type errors
somebody1234 Jun 13, 2024
214fa15
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 18, 2024
5546cd6
Fix type errors
somebody1234 Jun 18, 2024
f373c79
Fix lint errors
somebody1234 Jun 18, 2024
bb455b5
Limit maximum settings search bar width
somebody1234 Jun 18, 2024
6bec065
Fix appearance of "new user group" button
somebody1234 Jun 18, 2024
4bb4d4b
Fall back to first matching tab if the current tab contains no matches
somebody1234 Jun 18, 2024
9dae05f
Fix E2E tests
somebody1234 Jun 19, 2024
3dc414f
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 20, 2024
30f36e5
Fix Activity Log settings screen
somebody1234 Jun 20, 2024
8994fd4
Fix CSS for Activity Log table cells
somebody1234 Jun 20, 2024
462ee0b
Extract styles for `ActivityLogSettingsSection` to their own components
somebody1234 Jun 20, 2024
e464a18
Improve Activity Log filters CSS
somebody1234 Jun 20, 2024
165c139
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 21, 2024
a572ae4
Merge branch 'develop' into wip/sb/search-settings
somebody1234 Jun 21, 2024
6caaba7
Rename `*SettingsTab` to `*SettingsSection`
somebody1234 Jun 21, 2024
49d94ce
Fixes
somebody1234 Jun 21, 2024
d7581f0
Move paywall support into `settingsData.tsx`
somebody1234 Jun 21, 2024
b65e98e
Fix bugs
somebody1234 Jun 21, 2024
f906f36
WIP: input validation
somebody1234 Jun 21, 2024
af796ea
WIP
somebody1234 Jun 21, 2024
21cfc46
Allow logging out when stuck in "set username" screen
somebody1234 Jun 24, 2024
00724df
Fix input validation
somebody1234 Jun 24, 2024
40a5594
Make settings input validation uncontrolled again
somebody1234 Jun 24, 2024
8611ef3
Also show server errors in settings inputs
somebody1234 Jun 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/ide-desktop/lib/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import LoggerProvider from '#/providers/LoggerProvider'
import type * as loggerProvider from '#/providers/LoggerProvider'
import ModalProvider from '#/providers/ModalProvider'
import * as navigator2DProvider from '#/providers/Navigator2DProvider'
import SearchBarProvider from '#/providers/SearchBarProvider'
import SessionProvider from '#/providers/SessionProvider'

import ConfirmRegistration from '#/pages/authentication/ConfirmRegistration'
Expand Down Expand Up @@ -408,6 +409,7 @@ function AppRouter(props: AppRouterProps) {
</router.Routes>
)
let result = routes
result = <SearchBarProvider>{result}</SearchBarProvider>
result = <InputBindingsProvider inputBindings={inputBindings}>{result}</InputBindingsProvider>
result = <ModalProvider>{result}</ModalProvider>
result = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import * as permissionsModule from '#/utilities/permissions'
export interface PermissionDisplayProps extends Readonly<React.PropsWithChildren> {
readonly action: permissionsModule.PermissionAction
readonly className?: string
readonly onPress?: (event: aria.PressEvent) => void
readonly onPress?: ((event: aria.PressEvent) => void) | null
}

/** Colored border around icons and text indicating permissions. */
Expand Down Expand Up @@ -44,6 +44,7 @@ export default function PermissionDisplay(props: PermissionDisplayProps) {
case permissionsModule.Permission.view: {
return (
<UnstyledButton
isDisabled={!onPress}
className={`relative inline-block whitespace-nowrap rounded-full ${className ?? ''}`}
onPress={onPress ?? (() => {})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import * as uniqueString from '#/utilities/uniqueString'

/** The type of the `state` prop of a {@link SharedWithColumn}. */
interface SharedWithColumnStateProp
extends Pick<column.AssetColumnProps['state'], 'category' | 'dispatchAssetEvent' | 'setQuery'> {}
extends Pick<column.AssetColumnProps['state'], 'category' | 'dispatchAssetEvent'> {
readonly setQuery: column.AssetColumnProps['state']['setQuery'] | null
}

/** Props for a {@link SharedWithColumn}. */
interface SharedWithColumnPropsInternal extends Pick<column.AssetColumnProps, 'item' | 'setItem'> {
Expand Down Expand Up @@ -67,11 +69,20 @@ export default function SharedWithColumn(props: SharedWithColumnPropsInternal) {
<PermissionDisplay
key={otherUser.user.userId}
action={otherUser.permission}
onPress={event => {
setQuery(oldQuery =>
oldQuery.withToggled('owners', 'negativeOwners', otherUser.user.name, event.shiftKey)
)
}}
onPress={
setQuery == null
? null
: event => {
setQuery(oldQuery =>
oldQuery.withToggled(
'owners',
'negativeOwners',
otherUser.user.name,
event.shiftKey
)
)
}
}
>
{otherUser.user.name}
</PermissionDisplay>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import SvgMask from '#/components/SvgMask'

/** Props for an {@link SettingsInput}. */
export interface SettingsInputProps {
readonly isDisabled?: boolean
readonly type?: string
readonly placeholder?: string
readonly autoComplete?: React.HTMLInputAutoCompleteAttribute
Expand All @@ -25,7 +26,7 @@ export interface SettingsInputProps {

/** A styled input specific to settings pages. */
function SettingsInput(props: SettingsInputProps, ref: React.ForwardedRef<HTMLInputElement>) {
const { type, placeholder, autoComplete, onChange, onSubmit } = props
const { isDisabled = false, type, placeholder, autoComplete, onChange, onSubmit } = props
const focusChildProps = focusHooks.useFocusChild()
// This is SAFE. The value of this context is never a `SlottedContext`.
// eslint-disable-next-line no-restricted-syntax
Expand Down Expand Up @@ -71,6 +72,7 @@ function SettingsInput(props: SettingsInputProps, ref: React.ForwardedRef<HTMLIn
className:
'settings-value w-full rounded-full bg-transparent font-bold placeholder-black/30 transition-colors invalid:border invalid:border-red-700 hover:bg-selected-frame focus:bg-selected-frame',
...(type == null ? {} : { type: isShowingPassword ? 'text' : type }),
disabled: isDisabled,
size: 1,
autoComplete,
placeholder,
Expand Down

This file was deleted.

This file was deleted.

7 changes: 7 additions & 0 deletions app/ide-desktop/lib/dashboard/src/hooks/toastAndLogHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import * as textProvider from '#/providers/TextProvider'

import * as errorModule from '#/utilities/error'

// ===========================
// === ToastAndLogCallback ===
// ===========================

/** The type of the `toastAndLog` function returned by {@link useToastAndLog}. */
export type ToastAndLogCallback = ReturnType<typeof useToastAndLog>

// ======================
// === useToastAndLog ===
// ======================
Expand Down
13 changes: 1 addition & 12 deletions app/ide-desktop/lib/dashboard/src/layouts/AssetPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import UnstyledButton from '#/components/UnstyledButton'
import * as backend from '#/services/Backend'

import * as array from '#/utilities/array'
import type AssetQuery from '#/utilities/AssetQuery'
import type * as assetTreeNode from '#/utilities/AssetTreeNode'
import LocalStorage from '#/utilities/LocalStorage'

Expand Down Expand Up @@ -58,23 +57,14 @@ export interface AssetPanelRequiredProps {
/** Props for an {@link AssetPanel}. */
export interface AssetPanelProps extends AssetPanelRequiredProps {
readonly isReadonly?: boolean
readonly setQuery: React.Dispatch<React.SetStateAction<AssetQuery>>
readonly category: Category
readonly labels: backend.Label[]
readonly dispatchAssetEvent: (event: assetEvent.AssetEvent) => void
}

/** A panel containing the description and settings for an asset. */
export default function AssetPanel(props: AssetPanelProps) {
const {
item,
setItem,
setQuery,
category,
labels,
dispatchAssetEvent,
isReadonly = false,
} = props
const { item, setItem, category, labels, dispatchAssetEvent, isReadonly = false } = props

const { getText } = textProvider.useText()
const { localStorage } = localStorageProvider.useLocalStorage()
Expand Down Expand Up @@ -149,7 +139,6 @@ export default function AssetPanel(props: AssetPanelProps) {
setItem={setItem}
category={category}
labels={labels}
setQuery={setQuery}
dispatchAssetEvent={dispatchAssetEvent}
/>
)}
Expand Down
13 changes: 2 additions & 11 deletions app/ide-desktop/lib/dashboard/src/layouts/AssetProperties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import UnstyledButton from '#/components/UnstyledButton'

import * as backendModule from '#/services/Backend'

import type AssetQuery from '#/utilities/AssetQuery'
import type * as assetTreeNode from '#/utilities/AssetTreeNode'
import * as object from '#/utilities/object'
import * as permissions from '#/utilities/permissions'
Expand All @@ -40,21 +39,13 @@ export interface AssetPropertiesProps {
readonly setItem: React.Dispatch<React.SetStateAction<assetTreeNode.AnyAssetTreeNode>>
readonly category: Category
readonly labels: backendModule.Label[]
readonly setQuery: React.Dispatch<React.SetStateAction<AssetQuery>>
readonly dispatchAssetEvent: (event: assetEvent.AssetEvent) => void
readonly isReadonly?: boolean
}

/** Display and modify the properties of an asset. */
export default function AssetProperties(props: AssetPropertiesProps) {
const {
item: itemRaw,
setItem: setItemRaw,
category,
labels,
setQuery,
isReadonly = false,
} = props
const { item: itemRaw, setItem: setItemRaw, category, labels, isReadonly = false } = props
const { dispatchAssetEvent } = props

const { user } = authProvider.useNonPartialUserSession()
Expand Down Expand Up @@ -215,7 +206,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
isReadonly={isReadonly}
item={item}
setItem={setItem}
state={{ category, dispatchAssetEvent, setQuery }}
state={{ category, dispatchAssetEvent, setQuery: () => {} }}
/>
</td>
</tr>
Expand Down
42 changes: 39 additions & 3 deletions app/ide-desktop/lib/dashboard/src/layouts/AssetsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as inputBindingsProvider from '#/providers/InputBindingsProvider'
import * as localStorageProvider from '#/providers/LocalStorageProvider'
import * as modalProvider from '#/providers/ModalProvider'
import * as navigator2DProvider from '#/providers/Navigator2DProvider'
import * as searchBarProvider from '#/providers/SearchBarProvider'
import * as textProvider from '#/providers/TextProvider'

import type * as assetEvent from '#/events/assetEvent'
Expand All @@ -23,8 +24,10 @@ import AssetListEventType from '#/events/AssetListEventType'

import type * as assetPanel from '#/layouts/AssetPanel'
import type * as assetSearchBar from '#/layouts/AssetSearchBar'
import AssetSearchBar from '#/layouts/AssetSearchBar'
import AssetsTableContextMenu from '#/layouts/AssetsTableContextMenu'
import Category from '#/layouts/CategorySwitcher/Category'
import * as pageSwitcher from '#/layouts/PageSwitcher'

import * as aria from '#/components/aria'
import type * as assetRow from '#/components/dashboard/AssetRow'
Expand Down Expand Up @@ -349,8 +352,8 @@ export interface AssetsTableProps {
readonly setQuery: React.Dispatch<React.SetStateAction<AssetQuery>>
readonly setCanDownload: (canDownload: boolean) => void
readonly category: Category
readonly page: pageSwitcher.Page
readonly allLabels: Map<backendModule.LabelName, backendModule.Label>
readonly setSuggestions: (suggestions: assetSearchBar.Suggestion[]) => void
readonly initialProjectName: string | null
readonly projectStartupInfo: backendModule.ProjectStartupInfo | null
readonly deletedLabelNames: Set<backendModule.LabelName>
Expand All @@ -375,8 +378,8 @@ export interface AssetsTableProps {

/** The table of project assets. */
export default function AssetsTable(props: AssetsTableProps) {
const { hidden, hideRows, query, setQuery, setCanDownload, category, allLabels } = props
const { setSuggestions, deletedLabelNames, initialProjectName, projectStartupInfo } = props
const { hidden, hideRows, query, setQuery, setCanDownload, category, page, allLabels } = props
const { deletedLabelNames, initialProjectName, projectStartupInfo } = props
const { queuedAssetEvents: rawQueuedAssetEvents } = props
const { assetListEvents, dispatchAssetListEvent, assetEvents, dispatchAssetEvent } = props
const { setAssetPanelProps, doOpenEditor, doCloseEditor: rawDoCloseEditor, doCreateLabel } = props
Expand All @@ -385,6 +388,7 @@ export default function AssetsTable(props: AssetsTableProps) {
const { user, accessToken } = authProvider.useNonPartialUserSession()
const { backend } = backendProvider.useBackend()
const { setModal, unsetModal } = modalProvider.useSetModal()
const { setSearchBar, unsetSearchBar } = searchBarProvider.useSetSearchBar('AssetsTable')
const { localStorage } = localStorageProvider.useLocalStorage()
const { getText } = textProvider.useText()
const inputBindings = inputBindingsProvider.useInputBindings()
Expand All @@ -393,6 +397,7 @@ export default function AssetsTable(props: AssetsTableProps) {
const [initialized, setInitialized] = React.useState(false)
const [isLoading, setIsLoading] = React.useState(true)
const [enabledColumns, setEnabledColumns] = React.useState(columnUtils.DEFAULT_ENABLED_COLUMNS)
const [suggestions, setSuggestions] = React.useState<assetSearchBar.Suggestion[]>([])
const [sortInfo, setSortInfo] =
React.useState<sorting.SortInfo<columnUtils.SortableColumn> | null>(null)
const [selectedKeys, setSelectedKeysRaw] = React.useState<ReadonlySet<backendModule.AssetId>>(
Expand Down Expand Up @@ -644,6 +649,37 @@ export default function AssetsTable(props: AssetsTableProps) {
}
}, [targetDirectoryNodeRef, selectedKeys])

React.useEffect(() => {
return () => {
unsetSearchBar()
}
}, [/* should never change */ unsetSearchBar])

React.useEffect(() => {
if (page === pageSwitcher.Page.drive || page === pageSwitcher.Page.home) {
setSearchBar(
<AssetSearchBar
isCloud={isCloud}
query={query}
setQuery={setQuery}
labels={[...allLabels.values()]}
suggestions={suggestions}
/>
)
} else {
unsetSearchBar()
}
}, [
page,
isCloud,
query,
setQuery,
allLabels,
suggestions,
/* should never change */ setSearchBar,
/* should never change */ unsetSearchBar,
])

React.useEffect(() => {
const nodeToSuggestion = (
node: assetTreeNode.AnyAssetTreeNode,
Expand Down