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:
Victor O authored and GitHub committed 2023-11-03 21:24:48 -07:00
commit 40fa90153c
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 };
};