import React from "react"; import { Link } from "react-router-dom"; import * as GQL from "src/core/generated-graphql"; import NavUtils from "src/utils/navigation"; import TextUtils from "src/utils/text"; import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; import { objectTitle } from "src/core/files"; import { galleryTitle } from "src/core/galleries"; import SceneQueue from "src/models/sceneQueue"; import { RatingSystem } from "../Shared/Rating/RatingSystem"; import { useSceneUpdate } from "src/core/StashService"; import { IColumn, ListTable } from "../List/ListTable"; import { useTableColumns } from "src/hooks/useTableColumns"; interface ISceneListTableProps { scenes: GQL.SlimSceneDataFragment[]; queue?: SceneQueue; selectedIds: Set; onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void; } const TABLE_NAME = "scenes"; export const SceneListTable: React.FC = ( props: ISceneListTableProps ) => { const intl = useIntl(); const [updateScene] = useSceneUpdate(); function setRating(v: number | null, sceneId: string) { if (sceneId) { updateScene({ variables: { input: { id: sceneId, rating100: v, }, }, }); } } const CoverImageCell = (scene: GQL.SlimSceneDataFragment, index: number) => { const title = objectTitle(scene); const sceneLink = props.queue ? props.queue.makeLink(scene.id, { sceneIndex: index }) : `/scenes/${scene.id}`; return ( {title} ); }; const TitleCell = (scene: GQL.SlimSceneDataFragment, index: number) => { const title = objectTitle(scene); const sceneLink = props.queue ? props.queue.makeLink(scene.id, { sceneIndex: index }) : `/scenes/${scene.id}`; return ( {title} ); }; const DateCell = (scene: GQL.SlimSceneDataFragment) => <>{scene.date}; const RatingCell = (scene: GQL.SlimSceneDataFragment) => ( setRating(value, scene.id)} clickToRate /> ); const DurationCell = (scene: GQL.SlimSceneDataFragment) => { const file = scene.files.length > 0 ? scene.files[0] : undefined; return file?.duration && TextUtils.secondsToTimestamp(file.duration); }; const TagCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.tags.map((tag) => (
  • {tag.name}
  • ))}
); const PerformersCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.performers.map((performer) => (
  • {performer.name}
  • ))}
); const StudioCell = (scene: GQL.SlimSceneDataFragment) => { if (scene.studio) { return ( {scene.studio.name} ); } }; const MovieCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.movies.map((sceneMovie) => (
  • {sceneMovie.movie.name}
  • ))}
); const GalleriesCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.galleries.map((gallery) => (
  • {galleryTitle(gallery)}
  • ))}
); const PlayCountCell = (scene: GQL.SlimSceneDataFragment) => ( ); const PlayDurationCell = (scene: GQL.SlimSceneDataFragment) => ( <>{TextUtils.secondsToTimestamp(scene.play_duration ?? 0)} ); const ResolutionCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • {TextUtils.resolution(file?.width, file?.height)}
  • ))}
); function renderFileSize(file: { size: number | undefined }) { const { size, unit } = TextUtils.fileSize(file.size); return ( ); } const FileSizeCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • {renderFileSize(file)}
  • ))}
); const FrameRateCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • ))}
); const BitRateCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • ))}
); const AudioCodecCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • {file.audio_codec}
  • ))}
); const VideoCodecCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • {file.video_codec}
  • ))}
); const PathCell = (scene: GQL.SlimSceneDataFragment) => (
    {scene.files.map((file) => (
  • {file.path}
  • ))}
); interface IColumnSpec { value: string; label: string; defaultShow?: boolean; mandatory?: boolean; render?: ( scene: GQL.SlimSceneDataFragment, index: number ) => React.ReactNode; } const allColumns: IColumnSpec[] = [ { value: "cover_image", label: intl.formatMessage({ id: "cover_image" }), defaultShow: true, render: CoverImageCell, }, { value: "title", label: intl.formatMessage({ id: "title" }), defaultShow: true, mandatory: true, render: TitleCell, }, { value: "date", label: intl.formatMessage({ id: "date" }), defaultShow: true, render: DateCell, }, { value: "rating", label: intl.formatMessage({ id: "rating" }), defaultShow: true, render: RatingCell, }, { value: "scene_code", label: intl.formatMessage({ id: "scene_code" }), render: (s) => <>{s.code}, }, { value: "duration", label: intl.formatMessage({ id: "duration" }), defaultShow: true, render: DurationCell, }, { value: "studio", label: intl.formatMessage({ id: "studio" }), defaultShow: true, render: StudioCell, }, { value: "performers", label: intl.formatMessage({ id: "performers" }), defaultShow: true, render: PerformersCell, }, { value: "tags", label: intl.formatMessage({ id: "tags" }), defaultShow: true, render: TagCell, }, { value: "movies", label: intl.formatMessage({ id: "movies" }), defaultShow: true, render: MovieCell, }, { value: "galleries", label: intl.formatMessage({ id: "galleries" }), defaultShow: true, render: GalleriesCell, }, { value: "play_count", label: intl.formatMessage({ id: "play_count" }), render: PlayCountCell, }, { value: "play_duration", label: intl.formatMessage({ id: "play_duration" }), render: PlayDurationCell, }, { value: "o_counter", label: intl.formatMessage({ id: "o_count" }), render: (s) => <>{s.o_counter}, }, { value: "resolution", label: intl.formatMessage({ id: "resolution" }), render: ResolutionCell, }, { value: "path", label: intl.formatMessage({ id: "path" }), render: PathCell, }, { value: "filesize", label: intl.formatMessage({ id: "filesize" }), render: FileSizeCell, }, { value: "framerate", label: intl.formatMessage({ id: "framerate" }), render: FrameRateCell, }, { value: "bitrate", label: intl.formatMessage({ id: "bitrate" }), render: BitRateCell, }, { value: "video_codec", label: intl.formatMessage({ id: "video_codec" }), render: VideoCodecCell, }, { value: "audio_codec", label: intl.formatMessage({ id: "audio_codec" }), render: AudioCodecCell, }, ]; const defaultColumns = allColumns .filter((col) => col.defaultShow) .map((col) => col.value); const { selectedColumns, saveColumns } = useTableColumns( TABLE_NAME, defaultColumns ); const columnRenderFuncs: Record< string, (scene: GQL.SlimSceneDataFragment, index: number) => React.ReactNode > = {}; allColumns.forEach((col) => { if (col.render) { columnRenderFuncs[col.value] = col.render; } }); function renderCell( column: IColumn, scene: GQL.SlimSceneDataFragment, index: number ) { const render = columnRenderFuncs[column.value]; if (render) return render(scene, index); } return ( saveColumns(c)} selectedIds={props.selectedIds} onSelectChange={props.onSelectChange} renderCell={renderCell} /> ); };