Skip to content

Commit

Permalink
Merge branch 'main' of github.com:RolnickLab/ami-platform into feat/p…
Browse files Browse the repository at this point in the history
…roduction-environment
  • Loading branch information
mihow committed Feb 16, 2024
2 parents ff4200a + 2c63b7e commit f7ce6c8
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 77 deletions.
10 changes: 10 additions & 0 deletions ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
<link rel="preload" href="/index.css" as="style" />
<link rel="stylesheet" href="/index.css" />
</head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-EX26RXX0YT"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', 'G-EX26RXX0YT');
</script>
<!-- End Google tag (gtag.js) -->
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
Expand Down
135 changes: 83 additions & 52 deletions ui/src/design-system/components/image-carousel/image-carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,66 @@ import {
IconButtonTheme,
} from 'design-system/components/icon-button/icon-button'
import { Icon, IconTheme, IconType } from 'design-system/components/icon/icon'
import { useEffect, useRef, useState } from 'react'
import { ReactNode, useEffect, useRef, useState } from 'react'
import styles from './image-carousel.module.scss'
import { CarouselTheme } from './types'
import { getImageBoxStyles, getPlaceholderStyles } from './utils'
import { Link } from 'react-router-dom'

interface ImageCarouselProps {
autoPlay?: boolean
images: {
src: string
alt?: string
}[]
theme?: CarouselTheme
autoPlay?: boolean
size?: {
width: string | number
ratio: number
}
theme?: CarouselTheme
to?: string
}

export const ImageCarousel = ({
images,
theme = CarouselTheme.Default,
autoPlay,
images,
size,
theme = CarouselTheme.Default,
to,
}: ImageCarouselProps) => {
if (images.length <= 1) {
return <BasicImageCarousel image={images[0]} theme={theme} size={size} />
return (
<BasicImageCarousel image={images[0]} size={size} theme={theme} to={to} />
)
}

return (
<MultiImageCarousel
images={images}
theme={theme}
autoPlay={autoPlay}
images={images}
size={size}
theme={theme}
to={to}
/>
)
}

const BasicImageCarousel = ({
image,
theme,
size,
theme,
to,
}: {
image?: {
src: string
alt?: string
}
theme: CarouselTheme
size?: {
width: string | number
ratio: number
}
theme: CarouselTheme
to?: string
}) => (
<div className={styles.container}>
<div
Expand All @@ -66,28 +74,31 @@ const BasicImageCarousel = ({
style={getImageBoxStyles(size?.width)}
>
<div style={getPlaceholderStyles(size?.ratio)} />
<div className={classNames(styles.slide, styles.visible)}>
{image ? (
<img src={image.src} alt={image.alt} className={styles.image} />
) : (
<Icon
type={IconType.Photograph}
theme={IconTheme.Neutral}
size={16}
/>
)}
</div>
<ConditionalLink to={to}>
<div className={classNames(styles.slide, styles.visible)}>
{image ? (
<img src={image.src} alt={image.alt} className={styles.image} />
) : (
<Icon
type={IconType.Photograph}
theme={IconTheme.Neutral}
size={16}
/>
)}
</div>
</ConditionalLink>
</div>
</div>
)

const DURATION = 10000 // Change image every 10 second

const MultiImageCarousel = ({
images,
theme,
autoPlay,
images,
size,
theme,
to,
}: ImageCarouselProps) => {
const [paused, setPaused] = useState(false)
const [slideIndex, setSlideIndex] = useState(0)
Expand Down Expand Up @@ -154,35 +165,41 @@ const MultiImageCarousel = ({
onClick={() => showPrev(slideIndex)}
/>
</div>
<div
className={classNames(styles.imageBox, {
[styles.light]: theme === CarouselTheme.Light,
})}
style={getImageBoxStyles(size?.width)}
>
<div style={getPlaceholderStyles(size?.ratio)} />
{images.map((image, index) => {
const render =
index === 0 || // Always render first slide
index === images.length - 1 || // Always render last image
Math.abs(index - slideIndex) <= 1 // Render nearby slides

if (!render) {
return
}

return (
<div
key={index}
className={classNames(styles.slide, {
[styles.visible]: index === slideIndex,
})}
>
<img src={image.src} alt={image.alt} className={styles.image} />
</div>
)
})}
</div>
<ConditionalLink to={to}>
<div
className={classNames(styles.imageBox, {
[styles.light]: theme === CarouselTheme.Light,
})}
style={getImageBoxStyles(size?.width)}
>
<div style={getPlaceholderStyles(size?.ratio)} />
{images.map((image, index) => {
const render =
index === 0 || // Always render first slide
index === images.length - 1 || // Always render last image
Math.abs(index - slideIndex) <= 1 // Render nearby slides

if (!render) {
return
}

return (
<div
key={index}
className={classNames(styles.slide, {
[styles.visible]: index === slideIndex,
})}
>
<img
src={image.src}
alt={image.alt}
className={styles.image}
/>
</div>
)
})}
</div>
</ConditionalLink>
<div
className={classNames(styles.control, {
[styles.visible]: paused,
Expand Down Expand Up @@ -211,3 +228,17 @@ const MultiImageCarousel = ({
</div>
)
}

const ConditionalLink = ({
to,
children,
}: {
to?: string
children: ReactNode
}) => {
if (!to) {
return <>{children}</>
}

return <Link to={to}>{children}</Link>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { ImageCellTheme } from '../types'
import styles from './image-table-cell.module.scss'

interface ImageTableCellProps {
autoPlay?: boolean
images: {
src: string
alt?: string
}[]
theme?: ImageCellTheme
autoPlay?: boolean
to?: string
}

export const ImageTableCell = (props: ImageTableCellProps) => (
Expand Down
30 changes: 14 additions & 16 deletions ui/src/pages/collection-details/capture-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,22 @@ export const columns: (projectId: string) => TableColumn<Capture>[] = (
name: translate(STRING.FIELD_LABEL_THUMBNAIL),
renderCell: (item: Capture, rowIndex: number) => {
const isOddRow = rowIndex % 2 == 0
const detailsRoute = getAppRoute({
to: APP_ROUTES.SESSION_DETAILS({
projectId: projectId,
sessionId: item.sessionId,
}),
filters: {
capture: item.id,
},
})

return (
<Link
to={getAppRoute({
to: APP_ROUTES.SESSION_DETAILS({
projectId: projectId,
sessionId: item.sessionId,
}),
filters: {
capture: item.id,
},
})}
>
<ImageTableCell
images={[{ src: item.src }]}
theme={isOddRow ? ImageCellTheme.Default : ImageCellTheme.Light}
/>
</Link>
<ImageTableCell
images={[{ src: item.src }]}
theme={isOddRow ? ImageCellTheme.Default : ImageCellTheme.Light}
to={detailsRoute}
/>
)
},
},
Expand Down
10 changes: 9 additions & 1 deletion ui/src/pages/occurrences/occurrence-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,19 @@ export const columns: (projectId: string) => TableColumn<Occurrence>[] = (
},
renderCell: (item: Occurrence, rowIndex: number) => {
const isOddRow = rowIndex % 2 == 0
const detailsRoute = getAppRoute({
to: APP_ROUTES.OCCURRENCE_DETAILS({
projectId,
occurrenceId: item.id,
}),
keepSearchParams: true,
})

return (
<ImageTableCell
images={item.images}
theme={isOddRow ? ImageCellTheme.Default : ImageCellTheme.Light}
to={detailsRoute}
/>
)
},
Expand Down Expand Up @@ -73,7 +81,7 @@ export const columns: (projectId: string) => TableColumn<Occurrence>[] = (
name: translate(STRING.FIELD_LABEL_SESSION),
sortField: 'event',
renderCell: (item: Occurrence) => (
<Link to={APP_ROUTES.SESSION_DETAILS({ projectId, sessionId: item.id })}>
<Link to={APP_ROUTES.SESSION_DETAILS({ projectId, sessionId: item.sessionId })}>
<BasicTableCell value={item.sessionLabel} theme={CellTheme.Primary} />
</Link>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import { useState } from 'react'
import { useThreshold } from 'utils/threshold/thresholdContext'
import { CaptureInfo } from '../capture-info/capture-info'
import { CaptureJob } from '../capture-job/capture-job'
import { useActiveCaptureId } from '../useActiveCapture'
import { PipelinesPicker } from './pipelines-picker'
import styles from './playback-controls.module.scss'
import { StarButton } from './star-button'

export const PlaybackControls = () => {
const { activeCaptureId } = useActiveCaptureId()
export const PlaybackControls = ({
activeCaptureId,
}: {
activeCaptureId: string
}) => {
const { capture, isFetching } = useCaptureDetails(activeCaptureId as string)
const { defaultThreshold, threshold, setThreshold } = useThreshold()
const [showDetails, setShowDetails] = useState(false)
Expand Down
7 changes: 5 additions & 2 deletions ui/src/pages/session-details/playback/playback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CapturePicker } from './capture-picker/capture-picker'
import { Frame } from './frame/frame'
import { PlaybackControls } from './playback-controls/playback-controls'
import styles from './playback.module.scss'
import { useActiveCapture } from './useActiveCapture'
import { useActiveCapture, useActiveCaptureId } from './useActiveCapture'

export const Playback = ({ session }: { session: SessionDetails }) => {
const { threshold } = useThreshold()
Expand All @@ -21,6 +21,7 @@ export const Playback = ({ session }: { session: SessionDetails }) => {
} = useInfiniteCaptures(session.id, session.captureOffset, threshold)
const { activeCapture, setActiveCapture } = useActiveCapture(captures)
const [showOverlay, setShowOverlay] = useState(false)
const { activeCaptureId } = useActiveCaptureId()

if (!session.firstCapture) {
return null
Expand All @@ -41,7 +42,9 @@ export const Playback = ({ session }: { session: SessionDetails }) => {
showOverlay={showOverlay}
/>
</div>
<PlaybackControls />
{activeCaptureId && (
<PlaybackControls activeCaptureId={activeCaptureId} />
)}
</div>

<div className={styles.capturePicker}>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/pages/session-details/playback/useActiveCapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useActiveCaptureId = () => {
const setActiveCaptureId = (captureId: string) => {
searchParams.delete(SEARCH_PARAM_KEY)
searchParams.set(SEARCH_PARAM_KEY, captureId)
setSearchParams(searchParams)
setSearchParams(searchParams, { replace: true })
}

return { activeCaptureId, setActiveCaptureId }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const useActiveOccurrences = () => {
(occurrences: string[]) => {
searchParams.delete(SEARCH_PARAM_KEY)
occurrences.forEach((o) => searchParams.append(SEARCH_PARAM_KEY, o))
setSearchParams(searchParams)
setSearchParams(searchParams, { replace: true })
},
[searchParams, setSearchParams]
)
Expand Down
2 changes: 2 additions & 0 deletions ui/src/pages/sessions/session-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ export const columns: (projectId: string) => TableColumn<Session>[] = (
},
renderCell: (item: Session, rowIndex: number) => {
const isOddRow = rowIndex % 2 == 0
const detailsRoute = APP_ROUTES.SESSION_DETAILS({ projectId, sessionId: item.id })

return (
<ImageTableCell
images={item.exampleCaptures}
to={detailsRoute}
theme={isOddRow ? ImageCellTheme.Default : ImageCellTheme.Light}
/>
)
Expand Down
Loading

0 comments on commit f7ce6c8

Please sign in to comment.