mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-12 21:02:14 +00:00
Merge pull request #335 from storytold/olivicmic-fy-voice-designer-consume-api-react
new ListItems component on VoiceDesigner, useVoiceRequest, & DeleteDataset implementation
This commit is contained in:
5 files changed
+171
-33
No files matched your search
@@ -1,15 +1,15 @@
|
||||
import MakeRequest from "../../MakeRequest";
|
||||
|
||||
export interface DreateVoiceRequest {
|
||||
export interface DeleteVoiceRequest {
|
||||
set_delete: boolean;
|
||||
as_mod: boolean;
|
||||
}
|
||||
|
||||
export interface DreateVoiceResponse {
|
||||
export interface DeleteVoiceResponse {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
export const DeleteVoice = MakeRequest<string, DreateVoiceRequest, DreateVoiceResponse>({
|
||||
export const DeleteDataset = MakeRequest<string, DeleteVoiceRequest, DeleteVoiceResponse>({
|
||||
method: "DELETE",
|
||||
routingFunction: (voiceToken: string) => `/v1/voice_designer/dataset/${ voiceToken }/delete`,
|
||||
});
|
||||
@@ -4,14 +4,18 @@ import { faTrashAlt } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useSpring, a } from "@react-spring/web";
|
||||
|
||||
|
||||
|
||||
interface ModalProps {
|
||||
show: boolean;
|
||||
handleClose: () => void;
|
||||
onCancel?: (e: React.MouseEvent<HTMLElement>) => any;
|
||||
onConfirm?: (e: React.MouseEvent<HTMLElement>) => any;
|
||||
title: string;
|
||||
content: React.ReactNode;
|
||||
}
|
||||
|
||||
const Modal: React.FC<ModalProps> = ({ show, handleClose, title, content }) => {
|
||||
const Modal: React.FC<ModalProps> = ({ show, handleClose, onCancel: cancelEvent, onConfirm: confirmEvent, title, content }) => {
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const fadeIn = useSpring({
|
||||
@@ -22,6 +26,16 @@ const Modal: React.FC<ModalProps> = ({ show, handleClose, title, content }) => {
|
||||
},
|
||||
});
|
||||
|
||||
const onCancel = (e: React.MouseEvent<HTMLElement>) => {
|
||||
if (cancelEvent) cancelEvent(e);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const onConfirm = (e: React.MouseEvent<HTMLElement>) => {
|
||||
if (confirmEvent) confirmEvent(e);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
@@ -70,9 +84,9 @@ const Modal: React.FC<ModalProps> = ({ show, handleClose, title, content }) => {
|
||||
<Button
|
||||
variant="secondary"
|
||||
label="Cancel"
|
||||
onClick={handleClose}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
<Button variant="danger" label="Delete" onClick={handleClose} />
|
||||
<Button variant="danger" label="Delete" onClick={onConfirm} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { faPlus, faWaveform } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
// import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import Panel from "components/common/Panel";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
import Container from "components/common/Container";
|
||||
import { Route, NavLink, Switch, Redirect } from "react-router-dom";
|
||||
import ListItems from "./components/ListItems/ListItems";
|
||||
import ListItems from "./components/NewList";
|
||||
import Modal from "components/common/Modal";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { ListDatasetsByUser, Dataset } from "@storyteller/components/src/api/voice_designer/voice_datasets/ListDatasetsByUser";
|
||||
import { faMicrophone } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import useVoiceRequests from "./useVoiceRequests";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
}
|
||||
|
||||
function VoiceDesignerMainPage({ sessionWrapper }: Props) {
|
||||
const { user } = sessionWrapper.sessionStateResponse || {};
|
||||
const [datasets,datasetsSet] = useState<Dataset[]>([]);
|
||||
|
||||
|
||||
usePrefixedDocumentTitle("Voice Designer");
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!datasets.length && user) {
|
||||
ListDatasetsByUser("hanashi",{}).then(res => {
|
||||
if (res.datasets) datasetsSet(res.datasets);
|
||||
});
|
||||
}
|
||||
|
||||
},[user,datasets]);
|
||||
const { datasets, deleteDataSet } = useVoiceRequests({ sessionWrapper });
|
||||
|
||||
const [isDeleteVoiceModalOpen, setIsDeleteVoiceModalOpen] = useState(false);
|
||||
const [isDeleteDatasetModalOpen, setIsDeleteDatasetModalOpen] =
|
||||
@@ -52,23 +42,51 @@ function VoiceDesignerMainPage({ sessionWrapper }: Props) {
|
||||
setIsDeleteDatasetModalOpen(false);
|
||||
};
|
||||
|
||||
const voicesList = [
|
||||
const DataBadge = () => <span className="dataset-badge mb-0">Dataset</span>;
|
||||
const VoiceBadge = () => <FontAwesomeIcon icon={faMicrophone} className="me-2 me-lg-3" />;
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
const navToEdit = (token: string) => { history.push(`/voice-designer/voice/${token}/edit`) }
|
||||
|
||||
const rowClick = (todo: any) => ({ target }: { target: any }) => {
|
||||
let datasetToken = datasets[target.name.split(",")[0].split(":")[1]].dataset_token;
|
||||
todo(datasetToken);
|
||||
};
|
||||
|
||||
const actionDataSets = datasets.map((dataset,i) => {
|
||||
return {
|
||||
...dataset,
|
||||
badge: DataBadge,
|
||||
buttons: [{
|
||||
label: "Edit",
|
||||
small: true,
|
||||
variant: "secondary",
|
||||
onClick: rowClick(navToEdit)
|
||||
},{
|
||||
label: "Delete",
|
||||
small: true,
|
||||
variant: "danger",
|
||||
onClick: rowClick(deleteDataSet)
|
||||
}],
|
||||
name: dataset.title
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
const voicesList = [
|
||||
{
|
||||
badge: VoiceBadge,
|
||||
name: "Donald Trump (45th US President)",
|
||||
modelToken: "TM:z7x37sbvb8vc",
|
||||
isCreating: true,
|
||||
},
|
||||
{
|
||||
badge: VoiceBadge,
|
||||
name: "Spongebob Squarepants (Season 1)",
|
||||
modelToken: "TM:z7x37sbvb8vc",
|
||||
},
|
||||
];
|
||||
// const datasetList = [
|
||||
// {
|
||||
// name: "Donald Trump (45th US President)",
|
||||
// modelToken: "dummyToken",
|
||||
// },
|
||||
// ];
|
||||
|
||||
function MyVoices() {
|
||||
return (
|
||||
@@ -84,7 +102,7 @@ function VoiceDesignerMainPage({ sessionWrapper }: Props) {
|
||||
return (
|
||||
<ListItems
|
||||
type="dataset"
|
||||
data={datasets}
|
||||
data={actionDataSets}
|
||||
//data={datasetList}
|
||||
handleDeleteDataset={openDeleteDatasetModal}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import Button from "components/common/Button";
|
||||
import { faPlus } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import "./ListItems/ListItems.scss";
|
||||
|
||||
|
||||
interface ListItemsProps {
|
||||
data: any[];
|
||||
type: "voice" | "dataset";
|
||||
handleDeleteVoice?: () => void;
|
||||
handleDeleteDataset?: () => void;
|
||||
}
|
||||
|
||||
interface ListItem {
|
||||
badge?: any;
|
||||
buttons: any;
|
||||
index: number;
|
||||
isCreating?: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const Working = () => <div className="d-flex align-items-center gap-2 py-1">
|
||||
<p className="fw-medium opacity-75">
|
||||
Voice is being created...
|
||||
</p>
|
||||
<div
|
||||
className="spinner-border spinner-border-sm text-light"
|
||||
role="status"
|
||||
>
|
||||
<span className="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
const ItemRow = ({ badge: Badge, buttons, index, isCreating, name, ...rest }: ListItem) => {
|
||||
return <div className="d-flex flex-column flex-lg-row gap-3 list-items p-3 align-items-lg-center">
|
||||
<div className="d-inline-flex flex-wrap align-items-center flex-grow-1 gap-2">
|
||||
<h5 className="fw-semibold mb-0">
|
||||
{ Badge ? <Badge /> : null }
|
||||
{ name }
|
||||
</h5>
|
||||
</div>
|
||||
<div className="d-flex">
|
||||
{ isCreating ? <Working /> :
|
||||
<div className="d-flex gap-2">
|
||||
{ buttons && buttons.length ? buttons.map((action: any, key: number) => {
|
||||
return <Button { ...{
|
||||
...action,
|
||||
key,
|
||||
name: `item-row:${index},button:${key}`,
|
||||
} }/>;
|
||||
}) : null }
|
||||
</div> }
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default function NewList({ data, handleDeleteDataset, type, handleDeleteVoice, }: 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>
|
||||
<Button
|
||||
icon={faPlus} // 1
|
||||
label="Create New Voice" // 2
|
||||
small={true}
|
||||
to="/voice-designer/create" // 3
|
||||
/>
|
||||
</div>;
|
||||
return data.length ? <div className="d-flex flex-column gap-3">
|
||||
{ data.map((item, key) => <ItemRow {...{ key, ...item, index: key }}/>) }
|
||||
</div> : <DataPlaceholder />;
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { ListDatasetsByUser, Dataset } from "@storyteller/components/src/api/voice_designer/voice_datasets/ListDatasetsByUser";
|
||||
import { DeleteDataset } from "@storyteller/components/src/api/voice_designer/voice_datasets/DeleteDataset";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
}
|
||||
|
||||
export default function useVoiceRequests({ sessionWrapper }: Props) {
|
||||
const { user } = sessionWrapper.sessionStateResponse || {};
|
||||
const [datasets, datasetsSet] = useState<Dataset[]>([]);
|
||||
|
||||
const deleteDataSet = (voiceToken: string) => DeleteDataset(voiceToken,{
|
||||
set_delete: true,
|
||||
as_mod: false
|
||||
}).then(res => {
|
||||
console.log("🏧",res);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!datasets.length && user && user.username) {
|
||||
ListDatasetsByUser(user.username,{}).then(res => {
|
||||
if (res.datasets) datasetsSet(res.datasets);
|
||||
});
|
||||
}
|
||||
|
||||
},[user, datasets]);
|
||||
|
||||
return { datasets, deleteDataSet };
|
||||
};
|
||||
Reference in new issue
Block a user