mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-13 21:32:18 +00:00
skeleton loading list
This commit is contained in:
1 parent
dffd97633d
commit
313b1fb940
5 files changed
+143
-65
No files matched your search
@@ -11,8 +11,7 @@
|
||||
animation: loading 1.5s infinite;
|
||||
border-radius: 0.25rem;
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
|
||||
@@ -7,7 +7,7 @@ interface SkeletonProps {
|
||||
}
|
||||
|
||||
export default function Skeleton({ type = "full", rounded }: SkeletonProps) {
|
||||
const skeletonClass = `skeleton ${type} ${rounded && "rounded"}`;
|
||||
const skeletonClass = `skeleton ${type} ${rounded ? "rounded" : ""}`;
|
||||
|
||||
return <div className={skeletonClass}></div>;
|
||||
}
|
||||
@@ -17,10 +17,14 @@ import {
|
||||
// InferenceJob,
|
||||
} from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
function VoiceDesignerMainPage({ inferenceJobsByCategory }: { inferenceJobsByCategory: any }) {
|
||||
function VoiceDesignerMainPage({
|
||||
inferenceJobsByCategory,
|
||||
}: {
|
||||
inferenceJobsByCategory: any;
|
||||
}) {
|
||||
const { pathname } = useLocation();
|
||||
const { t } = useLocalize("FaceAnimator");
|
||||
const { datasets, voices } = useVoiceRequests({
|
||||
const { datasets, voices, isFetching } = useVoiceRequests({
|
||||
requestDatasets: true,
|
||||
requestVoices: true,
|
||||
});
|
||||
@@ -135,13 +139,14 @@ function VoiceDesignerMainPage({ inferenceJobsByCategory }: { inferenceJobsByCat
|
||||
};
|
||||
});
|
||||
|
||||
const statusTxt = (status: number, config: any) => [
|
||||
"Voice pending...",
|
||||
"Voice in progress",
|
||||
"Voice failed",
|
||||
"Voice dead",
|
||||
"Voice created successfully"
|
||||
][status];
|
||||
const statusTxt = (status: number, config: any) =>
|
||||
[
|
||||
"Voice pending...",
|
||||
"Voice in progress",
|
||||
"Voice failed",
|
||||
"Voice dead",
|
||||
"Voice created successfully",
|
||||
][status];
|
||||
|
||||
const button = {
|
||||
label: `Create new voice`,
|
||||
@@ -160,11 +165,15 @@ function VoiceDesignerMainPage({ inferenceJobsByCategory }: { inferenceJobsByCat
|
||||
panel={false}
|
||||
imageUrl="/images/header/voice-designer.png"
|
||||
/>
|
||||
<InferenceJobsList {...{
|
||||
t,
|
||||
inferenceJobs: inferenceJobsByCategory.get(FrontendInferenceJobType.VoiceDesignerCreateVoice),
|
||||
statusTxt
|
||||
}}/>
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
t,
|
||||
inferenceJobs: inferenceJobsByCategory.get(
|
||||
FrontendInferenceJobType.VoiceDesignerCreateVoice
|
||||
),
|
||||
statusTxt,
|
||||
}}
|
||||
/>
|
||||
<Panel mb={true}>
|
||||
<nav>
|
||||
<ul className="nav nav-tabs">
|
||||
@@ -192,7 +201,10 @@ function VoiceDesignerMainPage({ inferenceJobsByCategory }: { inferenceJobsByCat
|
||||
</nav>
|
||||
|
||||
<div className="p-3 p-lg-4">
|
||||
<ListItems {...{ data: view ? actionVoices : actionDataSets }} />
|
||||
<ListItems
|
||||
{...{ data: view ? actionVoices : actionDataSets }}
|
||||
isLoading={isFetching}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>
|
||||
|
||||
@@ -4,9 +4,11 @@ import { faMicrophone, faPlus } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import "./ListItems/ListItems.scss";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import Skeleton from "components/common/Skeleton";
|
||||
|
||||
interface ListItemsProps {
|
||||
data: any[];
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
interface ListItem {
|
||||
@@ -79,7 +81,7 @@ const ItemRow = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default function NewList({ data }: ListItemsProps) {
|
||||
export default function NewList({ data, isLoading }: ListItemsProps) {
|
||||
const DataPlaceholder = () => (
|
||||
<div className="d-flex flex-column list-items p-5 align-items-center">
|
||||
<h5 className="fw-semibold mb-3">You haven't created any voices.</h5>
|
||||
@@ -91,6 +93,25 @@ export default function NewList({ data }: ListItemsProps) {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
const loaderView = (
|
||||
<div className="list-items p-3">
|
||||
<h3 className="mb-0">
|
||||
<Skeleton type="medium" rounded />
|
||||
</h3>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column gap-3">
|
||||
{[...Array(2)].map((_, i) => (
|
||||
<React.Fragment key={i}>{loaderView}</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return data.length ? (
|
||||
<div className="d-flex flex-column gap-3">
|
||||
{data.map((item, key) => (
|
||||
|
||||
@@ -3,13 +3,21 @@ import { useEffect, useState } from "react";
|
||||
// voice imports
|
||||
|
||||
import { GetVoice } from "@storyteller/components/src/api/voice_designer/voices/GetVoice";
|
||||
import { CreateVoice, CreateVoiceRequest, CreateVoiceResponse } from "@storyteller/components/src/api/voice_designer/voices/CreateVoice";
|
||||
import { ListVoicesByUser, Voice } from "@storyteller/components/src/api/voice_designer/voices/ListVoicesByUser";
|
||||
import {
|
||||
DeleteVoice,
|
||||
import {
|
||||
CreateVoice,
|
||||
CreateVoiceRequest,
|
||||
CreateVoiceResponse,
|
||||
} from "@storyteller/components/src/api/voice_designer/voices/CreateVoice";
|
||||
import {
|
||||
ListVoicesByUser,
|
||||
Voice,
|
||||
} from "@storyteller/components/src/api/voice_designer/voices/ListVoicesByUser";
|
||||
import {
|
||||
DeleteVoice,
|
||||
// DeleteVoiceRequest, use me somewhere pls
|
||||
DeleteVoiceResponse } from "@storyteller/components/src/api/voice_designer/voices/DeleteVoice";
|
||||
import { UpdateVoice } from "@storyteller/components/src/api/voice_designer/voices/UpdateVoice";
|
||||
DeleteVoiceResponse,
|
||||
} from "@storyteller/components/src/api/voice_designer/voices/DeleteVoice";
|
||||
import { UpdateVoice } from "@storyteller/components/src/api/voice_designer/voices/UpdateVoice";
|
||||
|
||||
// dataset imports
|
||||
|
||||
@@ -18,69 +26,102 @@ import {
|
||||
ListDatasetsByUser,
|
||||
Dataset,
|
||||
} from "@storyteller/components/src/api/voice_designer/voice_datasets/ListDatasetsByUser";
|
||||
import { DeleteDataset, DeleteDatasetResponse } from "@storyteller/components/src/api/voice_designer/voice_datasets/DeleteDataset";
|
||||
import { CreateDataset, CreateDatasetRequest, CreateDatasetResponse } from "@storyteller/components/src/api/voice_designer/voice_datasets/CreateDataset";
|
||||
import { UpdateDataset, UpdateDatasetRequest, UpdateDatasetResponse } from "@storyteller/components/src/api/voice_designer/voice_datasets/UpdateDataset";
|
||||
import {
|
||||
DeleteDataset,
|
||||
DeleteDatasetResponse,
|
||||
} from "@storyteller/components/src/api/voice_designer/voice_datasets/DeleteDataset";
|
||||
import {
|
||||
CreateDataset,
|
||||
CreateDatasetRequest,
|
||||
CreateDatasetResponse,
|
||||
} from "@storyteller/components/src/api/voice_designer/voice_datasets/CreateDataset";
|
||||
import {
|
||||
UpdateDataset,
|
||||
UpdateDatasetRequest,
|
||||
UpdateDatasetResponse,
|
||||
} from "@storyteller/components/src/api/voice_designer/voice_datasets/UpdateDataset";
|
||||
import { EnqueueTts } from "@storyteller/components/src/api/voice_designer/inference/EnqueueTts";
|
||||
import { useSession } from "hooks";
|
||||
|
||||
export default function useVoiceRequests({ requestDatasets = false, requestVoices = false }){
|
||||
export default function useVoiceRequests({
|
||||
requestDatasets = false,
|
||||
requestVoices = false,
|
||||
}) {
|
||||
// this state will be provided as params, triggering the appropriate api call if present
|
||||
const [datasets, datasetsSet] = useState<Dataset[]>([]);
|
||||
const [voices, voicesSet] = useState<Voice[]>([]);
|
||||
|
||||
// this state stays here, fetched states are not success, merely an attempt was made. Each list fetch sets to true. Set to false to retry
|
||||
const [fetchDatasets, fetchDatasetsSet] = useState(requestDatasets);
|
||||
const [fetchVoices,fetchVoicesSet] = useState(requestVoices);
|
||||
const [fetchVoices, fetchVoicesSet] = useState(requestVoices);
|
||||
const [isFetchingVoices, setIsFetchingVoices] = useState(requestVoices);
|
||||
const [isFetchingDatasets, setIsFetchingDatasets] = useState(requestDatasets);
|
||||
const { user } = useSession();
|
||||
// const [timestamp, timestampSet] = useState(Date.now());
|
||||
|
||||
const refreshData = () => { fetchDatasetsSet(true); fetchVoicesSet(true); }; // later we can do refresh per list
|
||||
const refreshData = () => {
|
||||
fetchDatasetsSet(true);
|
||||
fetchVoicesSet(true);
|
||||
}; // later we can do refresh per list
|
||||
|
||||
const createDataset = (urlRouteArgs: string, request: CreateDatasetRequest): Promise<CreateDatasetResponse> =>
|
||||
CreateDataset(urlRouteArgs, request).then(res => {
|
||||
const createDataset = (
|
||||
urlRouteArgs: string,
|
||||
request: CreateDatasetRequest
|
||||
): Promise<CreateDatasetResponse> =>
|
||||
CreateDataset(urlRouteArgs, request).then((res) => {
|
||||
// refreshData(); // not needed because creating a dataset navigates to the upload page with no lists
|
||||
return res;
|
||||
});
|
||||
|
||||
const createVoice = (
|
||||
urlRouteArgs: string,
|
||||
request: CreateVoiceRequest
|
||||
): Promise<CreateVoiceResponse> =>
|
||||
CreateVoice(urlRouteArgs, request).then((res) => {
|
||||
// refreshData(); // not needed because creating a voice navigates to a new page with a new instance of useVoiceRequest
|
||||
return res;
|
||||
});
|
||||
|
||||
const createVoice = (urlRouteArgs: string, request: CreateVoiceRequest): Promise<CreateVoiceResponse> => CreateVoice(urlRouteArgs, request).then(res => {
|
||||
// refreshData(); // not needed because creating a voice navigates to a new page with a new instance of useVoiceRequest
|
||||
return res;
|
||||
});
|
||||
const deleteVoice = (voiceToken: string): Promise<DeleteVoiceResponse> =>
|
||||
DeleteVoice(voiceToken, {
|
||||
set_delete: true,
|
||||
as_mod: false,
|
||||
}).then((res) => {
|
||||
refreshData();
|
||||
return res;
|
||||
// console.log("🏧",res);
|
||||
});
|
||||
|
||||
const deleteVoice = (voiceToken: string): Promise<DeleteVoiceResponse> => DeleteVoice(voiceToken, {
|
||||
set_delete: true,
|
||||
as_mod: false
|
||||
}).then(res => {
|
||||
refreshData();
|
||||
return res;
|
||||
// console.log("🏧",res);
|
||||
});
|
||||
|
||||
const deleteDataset = (voiceToken: string): Promise<DeleteDatasetResponse> => DeleteDataset(voiceToken, {
|
||||
set_delete: true,
|
||||
as_mod: false
|
||||
}).then(res => {
|
||||
refreshData();
|
||||
return res;
|
||||
// console.log("🏧",res);
|
||||
});
|
||||
const deleteDataset = (voiceToken: string): Promise<DeleteDatasetResponse> =>
|
||||
DeleteDataset(voiceToken, {
|
||||
set_delete: true,
|
||||
as_mod: false,
|
||||
}).then((res) => {
|
||||
refreshData();
|
||||
return res;
|
||||
// console.log("🏧",res);
|
||||
});
|
||||
|
||||
const datasetByToken = (datasetToken?: string) =>
|
||||
datasets.filter(
|
||||
({ dataset_token }, i) => datasetToken === dataset_token
|
||||
)[0];
|
||||
|
||||
const editDataSet = (datasetToken: string, request: UpdateDatasetRequest): Promise<UpdateDatasetResponse> => {
|
||||
const editDataSet = (
|
||||
datasetToken: string,
|
||||
request: UpdateDatasetRequest
|
||||
): Promise<UpdateDatasetResponse> => {
|
||||
// console.log("🍄", datasetToken);
|
||||
return UpdateDataset(datasetToken, request).then(res => {
|
||||
return UpdateDataset(datasetToken, request).then((res) => {
|
||||
refreshData();
|
||||
return res;
|
||||
});
|
||||
};
|
||||
|
||||
const listDatasets = () => { fetchDatasetsSet(true); return datasets; }
|
||||
const listDatasets = () => {
|
||||
fetchDatasetsSet(true);
|
||||
return datasets;
|
||||
};
|
||||
|
||||
const languages = [
|
||||
{ value: "en", label: "English" },
|
||||
@@ -93,24 +134,29 @@ export default function useVoiceRequests({ requestDatasets = false, requestVoice
|
||||
{ label: "Hidden", value: "hidden" },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (user && user.username) {
|
||||
if (fetchDatasets) {
|
||||
setIsFetchingDatasets(true);
|
||||
fetchDatasetsSet(false);
|
||||
ListDatasetsByUser(user.username,{}).then(res => {
|
||||
ListDatasetsByUser(user.username, {}).then((res) => {
|
||||
if (res.datasets) datasetsSet(res.datasets);
|
||||
setIsFetchingDatasets(false);
|
||||
});
|
||||
}
|
||||
if (fetchVoices) {
|
||||
setIsFetchingVoices(true);
|
||||
fetchVoicesSet(false);
|
||||
ListVoicesByUser(user.username,{}).then(res => {
|
||||
ListVoicesByUser(user.username, {}).then((res) => {
|
||||
if (res.voices) voicesSet(res.voices);
|
||||
setIsFetchingVoices(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [user, fetchDatasets, fetchVoices]);
|
||||
|
||||
return {
|
||||
isFetching: isFetchingVoices || isFetchingDatasets,
|
||||
datasets: {
|
||||
byToken: datasetByToken,
|
||||
create: createDataset,
|
||||
@@ -119,7 +165,7 @@ export default function useVoiceRequests({ requestDatasets = false, requestVoice
|
||||
get: GetDataset,
|
||||
list: datasets,
|
||||
listDatasets,
|
||||
refresh: refreshData
|
||||
refresh: refreshData,
|
||||
},
|
||||
inference: {
|
||||
enqueue: EnqueueTts,
|
||||
@@ -136,9 +182,9 @@ export default function useVoiceRequests({ requestDatasets = false, requestVoice
|
||||
},
|
||||
inputCtrl:
|
||||
(todo: any) =>
|
||||
({ target }: { target: any }) => {
|
||||
console.log("🌿", target);
|
||||
todo(target.value);
|
||||
},
|
||||
({ target }: { target: any }) => {
|
||||
console.log("🌿", target);
|
||||
todo(target.value);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user