skeleton loading list

This commit is contained in:
BFlat committed 2023-11-17 15:58:37 +07:00
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);
},
};
}