mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
added percentage progress to jobs list, removed filters, job queue
This commit is contained in:
1 parent
8824217421
commit
ea40b09fac
11 files changed
+198
-118
No files matched your search
@@ -2,43 +2,50 @@ import MakeRequest from "../MakeRequest";
|
||||
import { UserDetailsLight } from "../_common/UserDetailsLight";
|
||||
|
||||
export interface RequestDetails {
|
||||
inference_category: string,
|
||||
maybe_model_type?: string,
|
||||
maybe_model_token?: string,
|
||||
maybe_model_title?: string,
|
||||
maybe_raw_inference_text?: string,
|
||||
inference_category: string;
|
||||
maybe_model_type?: string;
|
||||
maybe_model_token?: string;
|
||||
maybe_model_title?: string;
|
||||
maybe_raw_inference_text?: string;
|
||||
}
|
||||
|
||||
export interface StatusDetails {
|
||||
status: string,
|
||||
maybe_extra_status_description?: string,
|
||||
maybe_failure_category?: string,
|
||||
attempt_count: number,
|
||||
status: string;
|
||||
maybe_extra_status_description?: string;
|
||||
maybe_failure_category?: string;
|
||||
attempt_count: number;
|
||||
progress_percentage: number;
|
||||
}
|
||||
|
||||
export interface ResultDetails {
|
||||
entity_type: string,
|
||||
entity_token: string,
|
||||
maybe_public_bucket_media_path?: string,
|
||||
entity_type: string;
|
||||
entity_token: string;
|
||||
maybe_public_bucket_media_path?: string;
|
||||
}
|
||||
|
||||
export interface JobStatus {
|
||||
job_token: string,
|
||||
request: RequestDetails,
|
||||
status: StatusDetails,
|
||||
maybe_result?: ResultDetails,
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
job_token: string;
|
||||
request: RequestDetails;
|
||||
status: StatusDetails;
|
||||
maybe_result?: ResultDetails;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface GetJobStatusRequest {}
|
||||
|
||||
export interface GetJobStatusResponse {
|
||||
success: boolean;
|
||||
state: JobStatus
|
||||
state: JobStatus;
|
||||
}
|
||||
|
||||
export const GetJobStatus = MakeRequest<string,GetJobStatusRequest,GetJobStatusResponse,{}>({
|
||||
export const GetJobStatus = MakeRequest<
|
||||
string,
|
||||
GetJobStatusRequest,
|
||||
GetJobStatusResponse,
|
||||
{}
|
||||
>({
|
||||
method: "GET",
|
||||
routingFunction: (jobToken: string) =>`/v1/model_inference/job_status/${jobToken}`,
|
||||
routingFunction: (jobToken: string) =>
|
||||
`/v1/model_inference/job_status/${jobToken}`,
|
||||
});
|
||||
@@ -1,80 +1,88 @@
|
||||
import { ApiConfig } from "../ApiConfig";
|
||||
|
||||
export interface GetModelInferenceJobStatusSuccessResponse {
|
||||
success: boolean,
|
||||
state: ModelInferenceJobStatus,
|
||||
success: boolean;
|
||||
state: ModelInferenceJobStatus;
|
||||
}
|
||||
|
||||
export interface ModelInferenceJobStatus {
|
||||
// Job primary key
|
||||
job_token: string,
|
||||
job_token: string;
|
||||
|
||||
request: RequestDetails,
|
||||
status: StatusDetails,
|
||||
maybe_result?: ResultDetails,
|
||||
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
request: RequestDetails;
|
||||
status: StatusDetails;
|
||||
maybe_result?: ResultDetails;
|
||||
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface RequestDetails {
|
||||
inference_category: string,
|
||||
inference_category: string;
|
||||
|
||||
maybe_model_type?: string,
|
||||
maybe_model_token?: string,
|
||||
maybe_model_title?: string,
|
||||
maybe_model_type?: string;
|
||||
maybe_model_token?: string;
|
||||
maybe_model_title?: string;
|
||||
|
||||
maybe_raw_inference_text?: string,
|
||||
maybe_raw_inference_text?: string;
|
||||
}
|
||||
|
||||
export interface StatusDetails {
|
||||
status: string,
|
||||
maybe_extra_status_description?: string,
|
||||
maybe_failure_category?: string,
|
||||
attempt_count: number,
|
||||
status: string;
|
||||
maybe_extra_status_description?: string;
|
||||
maybe_failure_category?: string;
|
||||
attempt_count: number;
|
||||
progress_percentage: number;
|
||||
}
|
||||
|
||||
export interface ResultDetails {
|
||||
entity_type: string,
|
||||
entity_token: string,
|
||||
entity_type: string;
|
||||
entity_token: string;
|
||||
|
||||
maybe_public_bucket_media_path?: string,
|
||||
maybe_public_bucket_media_path?: string;
|
||||
}
|
||||
|
||||
export interface GetModelInferenceJobStatusErrorResponse {
|
||||
success: boolean,
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export type GetModelInferenceJobStatusResponse = GetModelInferenceJobStatusSuccessResponse | GetModelInferenceJobStatusErrorResponse;
|
||||
export type GetModelInferenceJobStatusResponse =
|
||||
| GetModelInferenceJobStatusSuccessResponse
|
||||
| GetModelInferenceJobStatusErrorResponse;
|
||||
|
||||
export function GetModelInferenceJobStatusIsOk(response: GetModelInferenceJobStatusResponse): response is GetModelInferenceJobStatusSuccessResponse {
|
||||
export function GetModelInferenceJobStatusIsOk(
|
||||
response: GetModelInferenceJobStatusResponse
|
||||
): response is GetModelInferenceJobStatusSuccessResponse {
|
||||
return response?.success === true;
|
||||
}
|
||||
|
||||
export function GetModelInferenceJobStatusIsError(response: GetModelInferenceJobStatusResponse): response is GetModelInferenceJobStatusErrorResponse {
|
||||
export function GetModelInferenceJobStatusIsError(
|
||||
response: GetModelInferenceJobStatusResponse
|
||||
): response is GetModelInferenceJobStatusErrorResponse {
|
||||
return response?.success === false;
|
||||
}
|
||||
|
||||
export async function GetModelInferenceJobStatus(jobToken: string) : Promise<GetModelInferenceJobStatusResponse>
|
||||
{
|
||||
export async function GetModelInferenceJobStatus(
|
||||
jobToken: string
|
||||
): Promise<GetModelInferenceJobStatusResponse> {
|
||||
const endpoint = new ApiConfig().getModelInferenceJobStatus(jobToken);
|
||||
|
||||
|
||||
return fetch(endpoint, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
Accept: "application/json",
|
||||
},
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res && 'success' in res) {
|
||||
return res;
|
||||
} else {
|
||||
return { success : false };
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
return { success : false };
|
||||
});
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res && "success" in res) {
|
||||
return res;
|
||||
} else {
|
||||
return { success: false };
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
return { success: false };
|
||||
});
|
||||
}
|
||||
@@ -34,6 +34,7 @@ export class InferenceJob {
|
||||
jobState: JobState;
|
||||
maybeExtraStatusDescription: string | null;
|
||||
attemptCount: number;
|
||||
progressPercentage: number;
|
||||
|
||||
// Request
|
||||
maybeModelType?: string;
|
||||
@@ -56,6 +57,7 @@ export class InferenceJob {
|
||||
status: string = "unknown",
|
||||
maybeExtraStatusDescription: string | null = null,
|
||||
attemptCount: number = 0,
|
||||
progressPercentage: number = 0,
|
||||
// Request
|
||||
maybeModelType: string | undefined = undefined,
|
||||
maybeModelToken: string | undefined = undefined,
|
||||
@@ -72,6 +74,7 @@ export class InferenceJob {
|
||||
this.jobState = jobStateFromString(status);
|
||||
this.maybeExtraStatusDescription = maybeExtraStatusDescription;
|
||||
this.attemptCount = attemptCount;
|
||||
this.progressPercentage = progressPercentage;
|
||||
|
||||
if (!!maybeModelType) {
|
||||
this.maybeModelTitle = maybeModelType;
|
||||
@@ -109,6 +112,7 @@ export class InferenceJob {
|
||||
response.status.status,
|
||||
response.status.maybe_extra_status_description || null,
|
||||
response.status.attempt_count || 0,
|
||||
response.status.progress_percentage || 0,
|
||||
response.request.maybe_model_type,
|
||||
response.request.maybe_model_token,
|
||||
response.request.maybe_model_title,
|
||||
|
||||
@@ -87,6 +87,15 @@
|
||||
"STARTED": "Please wait",
|
||||
"UNKNOWN": "Please wait or try again"
|
||||
},
|
||||
"VideoWorkflow": {
|
||||
"ATTEMPT_FAILED": "Video Workflow Atempt Failed",
|
||||
"COMPLETE_FAILURE": "Video Workflow Failed.",
|
||||
"COMPLETE_SUCCESS": "Video Workflow Complete",
|
||||
"PENDING": "Pending Video Workflow ",
|
||||
"STARTED": "Video Workflow In Progress",
|
||||
"UNKNOWN": "Video Workflow Status Uknown",
|
||||
"heading": "Video Workflow Jobs"
|
||||
},
|
||||
"voice_designer": {
|
||||
"ATTEMPT_FAILED": "Face Animation Atempt Failed",
|
||||
"COMPLETE_FAILURE": "Face Animation Failed.",
|
||||
@@ -96,4 +105,4 @@
|
||||
"UNKNOWN": "Voice Designer Status Uknown",
|
||||
"heading": "Voice Designer Jobs"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ const UploadControl = ({ onClick, status }: UploadCtrlProps) => {
|
||||
<WorkIndicator
|
||||
{...{
|
||||
failure,
|
||||
progressPercentage: 100,
|
||||
stage: success ? 2 : 1,
|
||||
success,
|
||||
}}
|
||||
|
||||
@@ -36,9 +36,9 @@ export default function JobsClearButton({
|
||||
{...{
|
||||
icon: faTrash,
|
||||
onClick: clearJobs,
|
||||
tooltip: "Clear completed jobs",
|
||||
label: "Clear completed jobs",
|
||||
variant: "secondary",
|
||||
square: true,
|
||||
// square: true,
|
||||
}}
|
||||
/>
|
||||
</a.div>,
|
||||
|
||||
+25
-1
@@ -25,7 +25,7 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
.fy-clear-jobs-input {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 3rem;
|
||||
// width: 3rem;
|
||||
right: 0;
|
||||
|
||||
.fy-clear-jobs-frame {
|
||||
@@ -81,6 +81,30 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
border-radius: 0.5rem 0 0 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
padding-right: 0;
|
||||
|
||||
.fy-inference-job-indicator-container {
|
||||
// background-color: red;
|
||||
position: relative;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.fy-inference-job-progress {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
// background-color: green;
|
||||
font-size: 0.625rem;
|
||||
line-height: 0.625rem;
|
||||
height: 0.625rem;
|
||||
// height: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
// margin: auto;
|
||||
// display: inline-block;
|
||||
// vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.fy-inference-job-action-frame {
|
||||
border-radius: 0 0.5rem 0.5rem 0;
|
||||
|
||||
@@ -10,13 +10,17 @@ import {
|
||||
CancelJobResponse,
|
||||
} from "@storyteller/components/src/api/jobs/CancelJob";
|
||||
import { useHover, useSlides } from "hooks";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import {
|
||||
JobState,
|
||||
jobStateCanChange,
|
||||
} from "@storyteller/components/src/jobs/JobStates";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
interface JobListItem extends InferenceJob {
|
||||
failures: (fail: string) => string;
|
||||
jobStatusDescription?: any;
|
||||
onSelect?: any;
|
||||
progressPercentage: number;
|
||||
resultPaths: { [key: string]: string };
|
||||
t?: any;
|
||||
}
|
||||
@@ -54,11 +58,13 @@ export default function JobItem({
|
||||
maybeModelTitle,
|
||||
maybeResultToken,
|
||||
onSelect,
|
||||
progressPercentage,
|
||||
jobToken,
|
||||
jobState,
|
||||
jobStatusDescription,
|
||||
resultPaths,
|
||||
t,
|
||||
...rest
|
||||
}: JobListItem) {
|
||||
const history = useHistory();
|
||||
const [hover, hoverSet = {}] = useHover({});
|
||||
@@ -118,6 +124,8 @@ export default function JobItem({
|
||||
}
|
||||
};
|
||||
|
||||
const jobIsAlive = jobStateCanChange(jobState);
|
||||
|
||||
const makeBounce = (amount = 0, delay = 0) => ({
|
||||
delay,
|
||||
config: { tension: 250, friction: 12 },
|
||||
@@ -125,6 +133,9 @@ export default function JobItem({
|
||||
});
|
||||
const headingBounce = useSpring(makeBounce(8));
|
||||
const subtitleBounce = useSpring(makeBounce(6, 30));
|
||||
const percentFade = useSpring({
|
||||
opacity: jobIsAlive ? 1 : 0,
|
||||
});
|
||||
const subtitle = maybeFailureCategory
|
||||
? `${failures(maybeFailureCategory)}`
|
||||
: t(`subtitles.${jobStatus}`);
|
||||
@@ -174,7 +185,16 @@ export default function JobItem({
|
||||
return (
|
||||
<>
|
||||
<div {...{ ...outerProps("fy-inference-job-indicator"), ...hoverSet }}>
|
||||
<WorkIndicator {...{ failure, stage: dashStatus(), success }} />
|
||||
<div {...{ className: "fy-inference-job-indicator-container" }}>
|
||||
<a.div
|
||||
{...{ className: "fy-inference-job-progress", style: percentFade }}
|
||||
>
|
||||
{progressPercentage}%
|
||||
</a.div>
|
||||
<WorkIndicator
|
||||
{...{ failure, progressPercentage, stage: dashStatus(), success }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div {...{ ...outerProps("fy-inference-job-details"), ...hoverSet }}>
|
||||
<a.h6 {...{ style: headingBounce }}>
|
||||
|
||||
+5
-25
@@ -1,10 +1,9 @@
|
||||
import React, { useState } from "react"; // useState
|
||||
import React from "react"; // useState
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { TempSelect as Select, JobsClearButton } from "components/common";
|
||||
import { enumToKeyArr } from "resources";
|
||||
import { JobsClearButton } from "components/common";
|
||||
import ModalHeader from "../ModalHeader";
|
||||
import { useInferenceJobs, useLocalize, useSession } from "hooks";
|
||||
import { useInferenceJobs, useLocalize } from "hooks";
|
||||
|
||||
interface Props {
|
||||
handleClose?: any;
|
||||
@@ -18,19 +17,9 @@ export default function InferenceJobsModal({
|
||||
showModalHeader = true,
|
||||
...rest
|
||||
}: Props) {
|
||||
const { canAccessStudio } = useSession();
|
||||
const { clearJobs, clearJobsStatus, someJobsAreDone } = useInferenceJobs();
|
||||
const presetFilter = enumToKeyArr(FrontendInferenceJobType)[inJobType];
|
||||
const [jobType, jobTypeSet] = useState(inJobType > -1 ? presetFilter : "All");
|
||||
const typeObj = ["All", ...Object.values(FrontendInferenceJobType)];
|
||||
const options = typeObj
|
||||
.filter(val => isNaN(Number(val)))
|
||||
.map(value => {
|
||||
if (typeof value === "string") return { value, label: value };
|
||||
return { label: "", value: "" };
|
||||
});
|
||||
const { t } = useLocalize("InferenceJobs");
|
||||
const selectedType = typeObj.indexOf(jobType) - 1;
|
||||
const selectedType = 0;
|
||||
const failures = (fail = "") => {
|
||||
switch (fail) {
|
||||
default:
|
||||
@@ -47,15 +36,6 @@ export default function InferenceJobsModal({
|
||||
/>
|
||||
</ModalHeader>
|
||||
)}
|
||||
{canAccessStudio() && (
|
||||
<Select
|
||||
{...{
|
||||
onChange: ({ target }: { target: any }) => jobTypeSet(target.value),
|
||||
options,
|
||||
value: jobType,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
@@ -64,7 +44,7 @@ export default function InferenceJobsModal({
|
||||
},
|
||||
...(selectedType > -1 ? { jobType: selectedType } : {}),
|
||||
showHeader: false,
|
||||
showJobQueue: true,
|
||||
showJobQueue: false,
|
||||
showNoJobs: true,
|
||||
panel: false,
|
||||
...rest,
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { a, useSpring } from "@react-spring/web";
|
||||
import { circle } from "../sharedSVGProps";
|
||||
|
||||
interface Props {
|
||||
className?: string,
|
||||
stage: number
|
||||
className?: string;
|
||||
progressPercentage: number;
|
||||
stage: number;
|
||||
}
|
||||
|
||||
export default function DashedCircle({ className = "", stage = 0 }: Props) {
|
||||
const dashes = [ // the arity (amount of numbers) must remain the same or react-spring will freakout
|
||||
"1 7 1 7 1 70", // UKNOWN / PENDING - 3x 1pt strokes with 7 point gaps, then a big 70pt gap
|
||||
"6 0 6 0 6 70", // STARTED / ATTEMPT_FAILED - 6pt strokes with 0pt gaps to appear as one, big gap
|
||||
"0 0 50 0 0 0" // COMPLETE_SUCCESS / COMPLETE_FAILURE / DEAD - One big 50pt stroke
|
||||
export default function DashedCircle({
|
||||
className = "",
|
||||
progressPercentage,
|
||||
stage = 0,
|
||||
}: Props) {
|
||||
const max = 87;
|
||||
const progressBar = (max - 16) * (progressPercentage / 100);
|
||||
const progressSegment = progressBar / 3;
|
||||
|
||||
const dashes = [
|
||||
// the arity (amount of numbers) must remain the same or react-spring will freakout
|
||||
`1 7 1 7 1 70`, // UKNOWN / PENDING - 3x 1pt strokes with 7 point gaps, then a big 70pt gap
|
||||
`${progressSegment} 0 ${progressSegment} 0 ${progressSegment} ${
|
||||
max - progressBar
|
||||
}`, // STARTED / ATTEMPT_FAILED - 6pt strokes with 0pt gaps to appear as one, big gap
|
||||
`0 0 ${max} 0 0 0`, // COMPLETE_SUCCESS / COMPLETE_FAILURE / DEAD - One big 50pt stroke
|
||||
];
|
||||
const style = useSpring({
|
||||
config: { tension: 280, friction: 60 },
|
||||
opacity: [.5,1,1][stage],
|
||||
strokeDasharray: dashes[stage]
|
||||
opacity: [0.5, 1, 1][stage],
|
||||
strokeDasharray: dashes[stage],
|
||||
});
|
||||
|
||||
return <a.circle {...{ ...circle, className, style }} />;
|
||||
};
|
||||
}
|
||||
@@ -1,19 +1,34 @@
|
||||
import React from 'react';
|
||||
import { AniX, Check, DashedCircle } from 'components/svg';
|
||||
import React from "react";
|
||||
import { AniX, Check, DashedCircle } from "components/svg";
|
||||
import { circle } from "../sharedSVGProps";
|
||||
import "./WorkIndicator.scss";
|
||||
|
||||
interface Props {
|
||||
failure: boolean,
|
||||
stage: number,
|
||||
success: boolean
|
||||
failure: boolean;
|
||||
progressPercentage: number;
|
||||
stage: number;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export default function WorkIndicator({ failure = false, stage = 0, success = false, ...rest }: Props) {
|
||||
return <svg {...{ className: "work-indicator", ...rest }}>
|
||||
<circle {...{ ...circle, className: "work-indicator-circle-track" }} />
|
||||
<DashedCircle {...{ className: "work-indicator-circle-marker", stage }}/>
|
||||
<AniX {...{ checked: failure }}/>
|
||||
<Check {...{ checked: success }}/>
|
||||
</svg>;
|
||||
};
|
||||
export default function WorkIndicator({
|
||||
failure = false,
|
||||
progressPercentage,
|
||||
stage = 0,
|
||||
success = false,
|
||||
...rest
|
||||
}: Props) {
|
||||
return (
|
||||
<svg {...{ className: "work-indicator", ...rest }}>
|
||||
<circle {...{ ...circle, className: "work-indicator-circle-track" }} />
|
||||
<DashedCircle
|
||||
{...{
|
||||
className: "work-indicator-circle-marker",
|
||||
progressPercentage,
|
||||
stage,
|
||||
}}
|
||||
/>
|
||||
<AniX {...{ checked: failure }} />
|
||||
<Check {...{ checked: success }} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user