Skip to content

Commit

Permalink
Consider job permissions in UI (#346)
Browse files Browse the repository at this point in the history
* Check user permissions for creating jobs

* Check user permissions for processing captures

* Check user permissions for marking capture as starred

* Check project permissions instead of capture permissions
  • Loading branch information
annavik authored Feb 18, 2024
1 parent 15e73c2 commit 0bfb5cb
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 11 deletions.
4 changes: 4 additions & 0 deletions ui/src/data-services/hooks/jobs/useJobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FetchParams } from 'data-services/types'
import { getFetchUrl } from 'data-services/utils'
import { useMemo } from 'react'
import { useAuthorizedQuery } from '../auth/useAuthorizedQuery'
import { UserPermission } from 'utils/user/types'

const REFETCH_INTERVAL = 10000 // Refetch every 10 second

Expand All @@ -14,6 +15,7 @@ export const useJobs = (
): {
jobs?: Job[]
total: number
userPermissions?: UserPermission[]
isLoading: boolean
isFetching: boolean
error?: unknown
Expand All @@ -22,6 +24,7 @@ export const useJobs = (

const { data, isLoading, isFetching, error } = useAuthorizedQuery<{
results: ServerJob[]
user_permissions?: UserPermission[]
count: number
}>({
queryKey: [API_ROUTES.JOBS, params],
Expand All @@ -34,6 +37,7 @@ export const useJobs = (
return {
jobs,
total: data?.count ?? 0,
userPermissions: data?.user_permissions,
isLoading,
isFetching,
error,
Expand Down
4 changes: 3 additions & 1 deletion ui/src/data-services/hooks/projects/useProjectDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { useAuthorizedQuery } from '../auth/useAuthorizedQuery'
const convertServerRecord = (record: ServerProject) => new Project(record)

export const useProjectDetails = (
projectId: string
projectId: string,
useInternalCache?: boolean
): {
project?: Project
isLoading: boolean
Expand All @@ -16,6 +17,7 @@ export const useProjectDetails = (
const { data, isLoading, isFetching, error } = useAuthorizedQuery<Project>({
queryKey: [API_ROUTES.PROJECTS, projectId],
url: `${API_URL}/${API_ROUTES.PROJECTS}/${projectId}/`,
staleTime: useInternalCache ? Infinity : undefined,
})

const project = useMemo(
Expand Down
19 changes: 13 additions & 6 deletions ui/src/pages/jobs/jobs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ import { STRING, translate } from 'utils/language'
import { usePagination } from 'utils/usePagination'
import { columns } from './jobs-columns'
import styles from './jobs.module.scss'
import { UserPermission } from 'utils/user/types'

export const Jobs = () => {
const { projectId, id } = useParams()
const { pagination, setPage } = usePagination()
const [sort, setSort] = useState<TableSortSettings>()
const { jobs, total, isLoading, isFetching, error } = useJobs({
projectId,
pagination,
sort,
})
const { jobs, userPermissions, total, isLoading, isFetching, error } =
useJobs({
projectId,
pagination,
sort,
})
const canCreate = userPermissions?.includes(UserPermission.Create)

if (!isLoading && error) {
return <Error />
Expand Down Expand Up @@ -55,7 +58,11 @@ export const Jobs = () => {
setPage={setPage}
/>
) : null}
{!isLoading && id ? <JobDetailsDialog id={id} /> : <NewJobDialog />}
{!isLoading && id ? (
<JobDetailsDialog id={id} />
) : canCreate ? (
<NewJobDialog />
) : null}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCreateJob } from 'data-services/hooks/jobs/useCreateJob'
import { useProjectDetails } from 'data-services/hooks/projects/useProjectDetails'
import { CaptureDetails } from 'data-services/models/capture-details'
import { Button, ButtonTheme } from 'design-system/components/button/button'
import { IconType } from 'design-system/components/icon/icon'
Expand All @@ -14,6 +15,7 @@ export const ProcessNow = ({
pipelineId?: string
}) => {
const { projectId } = useParams()
const { project } = useProjectDetails(projectId as string, true)
const { createJob, isLoading, isSuccess } = useCreateJob()
const icon = isSuccess ? IconType.RadixCheck : undefined
const disabled = !capture || capture.hasJobInProgress || !pipelineId
Expand All @@ -30,9 +32,14 @@ export const ProcessNow = ({
)
}

const tooltipContent = project?.canUpdate
? translate(STRING.MESSAGE_PROCESS_NOW_TOOLTIP)
: translate(STRING.MESSAGE_PERMISSIONS_MISSING)

return (
<Tooltip content={translate(STRING.MESSAGE_PROCESS_NOW_TOOLTIP)}>
<Tooltip content={tooltipContent}>
<Button
disabled={!project?.canUpdate}
icon={icon}
label={translate(STRING.PROCESS_NOW)}
loading={isLoading}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useStarCapture } from 'data-services/hooks/captures/useStarCapture'
import { useProjectDetails } from 'data-services/hooks/projects/useProjectDetails'
import { CaptureDetails } from 'data-services/models/capture-details'
import {
IconButton,
IconButtonTheme,
} from 'design-system/components/icon-button/icon-button'
import { IconType } from 'design-system/components/icon/icon'
import { Tooltip } from 'design-system/components/tooltip/tooltip'
import { useParams } from 'react-router-dom'
import { STRING, translate } from 'utils/language'

export const StarButton = ({
Expand All @@ -17,15 +19,21 @@ export const StarButton = ({
captureFetching?: boolean
captureId: string
}) => {
const { projectId } = useParams()
const { project } = useProjectDetails(projectId as string, true)
const isStarred = capture?.isStarred ?? false
const { starCapture, isLoading } = useStarCapture(captureId, isStarred)
const tooltipContent = project?.canUpdate
? isStarred
? translate(STRING.STARRED)
: translate(STRING.STAR)
: translate(STRING.MESSAGE_PERMISSIONS_MISSING)

return (
<Tooltip
content={isStarred ? translate(STRING.STARRED) : translate(STRING.STAR)}
>
<Tooltip content={tooltipContent}>
<IconButton
icon={isStarred ? IconType.HeartFilled : IconType.Heart}
disabled={!project?.canUpdate}
loading={isLoading || captureFetching}
theme={IconButtonTheme.Neutral}
onClick={() => starCapture()}
Expand Down
3 changes: 3 additions & 0 deletions ui/src/utils/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export enum STRING {
MESSAGE_NO_IMAGE,
MESSAGE_NO_RESULTS,
MESSAGE_PASSWORD_FORMAT,
MESSAGE_PERMISSIONS_MISSING,
MESSAGE_PROCESS_NOW_TOOLTIP,
MESSAGE_RESULT_RANGE,
MESSAGE_SIGNED_UP,
Expand Down Expand Up @@ -295,6 +296,8 @@ const ENGLISH_STRINGS: { [key in STRING]: string } = {
[STRING.MESSAGE_NO_RESULTS]: 'No results to show',
[STRING.MESSAGE_PASSWORD_FORMAT]:
'The password must contain at least 8 characters and cannot be entirely numeric.',
[STRING.MESSAGE_PERMISSIONS_MISSING]:
'Permissions missing to perform the action',
[STRING.MESSAGE_PROCESS_NOW_TOOLTIP]:
'Process this single image with presets',
[STRING.MESSAGE_RESULT_RANGE]:
Expand Down

0 comments on commit 0bfb5cb

Please sign in to comment.