-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Motivation: We got two feedbacks about UX: - `Delete Project`'s location was inappropriate. > After I click on Project Settings, the button is immediately replaced > with Delete Project, while I'm still hovering over it. - Automatically focus to the project seach box on the welcome page. > would it be possible to add something like auto-focus to the > "Search project..." field when opening the web UI? > Perhaps also supporting the / key would help, for consistency with > the Projects page Modifications: - Create `Danger zone` tab and move `Delete Project` to it. - Miscellaneous) - Remove `repos` segment from all `Breadcrumb` - I felt it was unnecessary to include `repos` since it is assumed to be a repo without additional explanation. - Fix to auto-focus to the search box on the welcome page. - Fix broken APIs in the mock server. Result: Improved usability of the UI.
- Loading branch information
Showing
17 changed files
with
216 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
webapp/src/dogma/common/components/ProjectSearchBox.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { | ||
components, | ||
DropdownIndicatorProps, | ||
GroupBase, | ||
OptionBase, | ||
Select, | ||
SizeProp, | ||
} from 'chakra-react-select'; | ||
import { useEffect, useRef, useState } from 'react'; | ||
import { Kbd, useColorMode } from '@chakra-ui/react'; | ||
import Router from 'next/router'; | ||
import { useGetProjectsQuery } from 'dogma/features/api/apiSlice'; | ||
import { ProjectDto } from 'dogma/features/project/ProjectDto'; | ||
|
||
export interface ProjectSearchBoxProps { | ||
id: string; | ||
size?: SizeProp; | ||
placeholder: string; | ||
autoFocus?: boolean; | ||
} | ||
|
||
export interface ProjectOptionType extends OptionBase { | ||
value: string; | ||
label: string; | ||
} | ||
|
||
const initialState: ProjectOptionType = { | ||
value: '', | ||
label: '', | ||
}; | ||
|
||
const DropdownIndicator = ( | ||
props: JSX.IntrinsicAttributes & DropdownIndicatorProps<unknown, boolean, GroupBase<unknown>>, | ||
) => { | ||
return ( | ||
<components.DropdownIndicator {...props}> | ||
<Kbd>/</Kbd> | ||
</components.DropdownIndicator> | ||
); | ||
}; | ||
|
||
const ProjectSearchBox = ({ id, size, placeholder, autoFocus }: ProjectSearchBoxProps) => { | ||
const { colorMode } = useColorMode(); | ||
const { data, isLoading } = useGetProjectsQuery({ admin: false }); | ||
const projects = data || []; | ||
const projectOptions: ProjectOptionType[] = projects.map((project: ProjectDto) => ({ | ||
value: project.name, | ||
label: project.name, | ||
})); | ||
|
||
const [selectedOption, setSelectedOption] = useState(initialState); | ||
const handleChange = (option: ProjectOptionType) => { | ||
setSelectedOption(option); | ||
}; | ||
|
||
const selectRef = useRef(null); | ||
useEffect(() => { | ||
if (selectedOption?.value) { | ||
selectRef.current.blur(); | ||
Router.push(`/app/projects/${selectedOption.value}`); | ||
} | ||
}, [selectedOption?.value]); | ||
|
||
useEffect(() => { | ||
const handleKeyDown = (e: KeyboardEvent) => { | ||
const target = (e.target as HTMLElement).tagName.toLowerCase(); | ||
if (target == 'textarea' || target == 'input') { | ||
return; | ||
} | ||
if (e.key === '/') { | ||
e.preventDefault(); | ||
selectRef.current.clearValue(); | ||
selectRef.current.focus(); | ||
} else if (e.key === 'Escape') { | ||
selectRef.current.blur(); | ||
} | ||
}; | ||
document.addEventListener('keydown', handleKeyDown); | ||
return () => { | ||
document.removeEventListener('keydown', handleKeyDown); | ||
}; | ||
}, [selectRef]); | ||
|
||
return ( | ||
<Select | ||
size={size} | ||
id={id} | ||
autoFocus={autoFocus} | ||
name="project-search" | ||
options={projectOptions} | ||
value={selectedOption?.value} | ||
onChange={(option: ProjectOptionType) => option && handleChange(option)} | ||
placeholder={placeholder} | ||
closeMenuOnSelect={true} | ||
openMenuOnFocus={!autoFocus} | ||
isClearable={true} | ||
isSearchable={true} | ||
ref={selectRef} | ||
isLoading={isLoading} | ||
components={{ DropdownIndicator }} | ||
chakraStyles={{ | ||
control: (baseStyles) => ({ | ||
...baseStyles, | ||
backgroundColor: colorMode === 'light' ? 'white' : 'whiteAlpha.50', | ||
}), | ||
}} | ||
/> | ||
); | ||
}; | ||
|
||
export default ProjectSearchBox; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
48 changes: 48 additions & 0 deletions
48
webapp/src/pages/api/v1/projects/[projectName]/repos/[repoName]/list/[...fileName].ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { NextApiRequest, NextApiResponse } from 'next'; | ||
import { FileDto, FileType } from 'dogma/features/file/FileDto'; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { faker } from '@faker-js/faker'; | ||
|
||
const newFile = (id: number): FileDto => { | ||
const type: FileType = faker.helpers.arrayElement(['TEXT', 'DIRECTORY', 'JSON', 'YML']); | ||
const extension = type == 'DIRECTORY' ? '' : '.' + type.toLowerCase(); | ||
return { | ||
revision: faker.datatype.number({ | ||
min: 1, | ||
max: 10, | ||
}), | ||
path: `/${id}-${faker.animal.rabbit().replaceAll(' ', '-').toLowerCase()}${extension}`, | ||
type: type, | ||
url: faker.internet.url(), | ||
}; | ||
}; | ||
const fileList: FileDto[] = []; | ||
const makeData = (len: number) => { | ||
for (let i = 0; i < len; i++) { | ||
fileList.push(newFile(i)); | ||
} | ||
}; | ||
makeData(20); | ||
|
||
export default function handler(req: NextApiRequest, res: NextApiResponse) { | ||
const { fileItem } = req.body; | ||
const { query } = req; | ||
const { revision } = query; | ||
const revisionNumber = parseInt(revision as string); | ||
const filtered = isNaN(revisionNumber) | ||
? fileList | ||
: fileList.filter((file: FileDto) => file.revision <= revisionNumber); | ||
switch (req.method) { | ||
case 'GET': | ||
res.status(200).json(filtered); | ||
break; | ||
case 'POST': | ||
fileList.push(fileItem); | ||
res.status(200).json(fileList); | ||
break; | ||
default: | ||
res.setHeader('Allow', ['GET', 'POST']); | ||
res.status(405).end(`Method ${req.method} Not Allowed`); | ||
break; | ||
} | ||
} |
Oops, something went wrong.