Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp

This commit is contained in:
Victor committed 2023-12-31 01:44:48 -05:00
commit 317cd5bcf6
10 files changed
+208 -148

No files matched your search

@@ -0,0 +1,13 @@
.fy-input {
input {
margin-bottom: 1rem;
:only-child {
margin-bottom: 0;
}
:last-child {
margin-bottom: 0;
}
}
}
@@ -1,6 +1,7 @@
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import "./Input.scss";
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
icon?: IconDefinition;
@@ -23,7 +24,7 @@ export default function TempInput({
{label}
</label>
)}
<div className={`form-group ${icon ? "input-icon" : ""}`}>
<div className={`fy-input ${icon ? "input-icon" : ""}`}>
{icon && (
<FontAwesomeIcon icon={icon} className="form-control-feedback" />
)}
@@ -0,0 +1,11 @@
.fy-select {
margin-bottom: 1rem;
:only-child {
margin-bottom: 0;
}
:last-child {
margin-bottom: 0;
}
}
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import "../Select/Select.scss";
import ReactSelect, { Props as ReactSelectProps } from "react-select";
import "./Select.scss";
export interface Option {
value: string | number | boolean;
@@ -35,7 +36,7 @@ export default function Select({
options.find((option: any) => option.value === value)?.label || "";
const onChange = ({ value }: any) =>
inChange({ target: { value, name, type: "select" } });
const className = `form-group${icon ? " input-icon" : ""}${
const className = `fy-select ${icon ? " input-icon" : ""}${
small ? " select-small" : ""
}`;
const classNames = {
@@ -1,4 +1,5 @@
import React from "react";
import "./TextArea.scss";
interface TextAreaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
@@ -20,9 +21,7 @@ export default function TempTextArea({
{label}
</label>
)}
<div className="form-group">
<textarea className="form-control" {...rest} />
</div>
<textarea className="fy-textarea form-control" {...rest} />
</>
);
}
@@ -0,0 +1,13 @@
.fy-textarea {
&:textarea {
margin-bottom: 1rem;
:only-child {
margin-bottom: 0;
}
:last-child {
margin-bottom: 0;
}
}
}
@@ -86,47 +86,41 @@ export default function UploadSdWeightPage({
<div className="col-12 col-lg-5">
<label className="sub-title required">Cover Image</label>
</div>
<div className="col-12 col-lg-7 d-flex flex-column gap-3 order-first order-lg-last">
<div>
<TempInput
{...{
label: "Title",
name: "title",
placeholder: "Title",
required: true,
}}
/>
</div>
<div>
<TempInput
{...{
label: "Download URL, eg. Google Drive link",
name: "Url",
placeholder: "Download URL",
required: true,
}}
/>
</div>
<div>
<TempSelect
{...{
icon: faEye,
label: "Visibility",
name: "visibility",
options: visibilityOptions,
placeholder: "Voice name",
}}
/>
</div>
<div>
<TempTextArea
{...{
label: "Description",
name: "descriptionMD",
placeholder: "Description",
}}
/>
</div>
<div className="col-12 col-lg-7 order-first order-lg-last">
<TempInput
{...{
label: "Title",
name: "title",
placeholder: "Title",
required: true,
}}
/>
<TempInput
{...{
label: "Download URL, eg. Google Drive link",
name: "Url",
placeholder: "Download URL",
required: true,
}}
/>
<TempSelect
{...{
icon: faEye,
label: "Visibility",
name: "visibility",
options: visibilityOptions,
placeholder: "Voice name",
}}
/>
<TempTextArea
{...{
label: "Description",
name: "descriptionMD",
placeholder: "Description",
}}
/>
</div>
</div>
</SplitPanel.Body>
@@ -67,43 +67,37 @@ function VoiceDesignerVoiceEditPage() {
/>
<Panel>
<div className="d-flex flex-column gap-4 p-3 py-4 p-md-4">
<div>
<TempInput
{...{
label: "Title",
placeholder: "Voice name",
onChange: inputCtrl(titleSet),
value: title,
}}
/>
</div>
<div className="p-3 py-4 p-md-4">
<TempInput
{...{
label: "Title",
placeholder: "Voice name",
onChange: inputCtrl(titleSet),
value: title,
}}
/>
<div>
<TempSelect
{...{
icon: faLanguage,
label: "Language",
// placeholder: "Voice name",
onChange: inputCtrl(languageSet),
options: languages,
value: language,
}}
/>
</div>
<TempSelect
{...{
icon: faLanguage,
label: "Language",
// placeholder: "Voice name",
onChange: inputCtrl(languageSet),
options: languages,
value: language,
}}
/>
<div>
<TempSelect
{...{
icon: faEye,
label: "Visibility",
// placeholder: "Voice name",
onChange: inputCtrl(visibilitySet),
options: visibilityOptions,
value: visibility,
}}
/>
</div>
<TempSelect
{...{
icon: faEye,
label: "Visibility",
// placeholder: "Voice name",
onChange: inputCtrl(visibilitySet),
options: visibilityOptions,
value: visibility,
}}
/>
</div>
<hr className="mt-0 mb-4" />
<div className="p-3 pb-4 px-lg-4 pt-0">
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
import { AudioInput } from "components/common";
import moment from 'moment';
import moment from "moment";
import ListItems from "../NewList";
import { v4 as uuidv4 } from "uuid";
import { ListSamplesForDataset } from "@storyteller/components/src/api/voice_designer/voice_dataset_samples/ListSamplesForDataset";
@@ -10,72 +10,94 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faWaveform } from "@fortawesome/pro-solid-svg-icons";
interface Props {
audioProps: any,
datasetToken?: string,
deleting: any,
deletingSet: any,
inProgress: any,
inProgressSet: any
samples: any,
samplesSet: any
audioProps: any;
datasetToken?: string;
deleting: any;
deletingSet: any;
inProgress: any;
inProgressSet: any;
samples: any;
samplesSet: any;
}
function UploadSamples({ audioProps, datasetToken, deleting, deletingSet, inProgress, inProgressSet, samples, samplesSet }: Props) {
const [listFetched,listFetchedSet] = useState(false);
function UploadSamples({
audioProps,
datasetToken,
deleting,
deletingSet,
inProgress,
inProgressSet,
samples,
samplesSet,
}: Props) {
const [listFetched, listFetchedSet] = useState(false);
const SampleBadge = () => <FontAwesomeIcon icon={faWaveform} className="me-2 me-lg-3" />;
const SampleBadge = () => (
<FontAwesomeIcon icon={faWaveform} className="me-2 me-lg-3" />
);
const sampleClick = () => ({ target }: { target: any }) => {
let sampleToken = samples[target.name.split(",")[0].split(":")[1]].sample_token;
deletingSet([ ...deleting, sampleToken ]); // add to deleting list
DeleteSample(sampleToken,{ as_mod: false, set_delete: true })
.then((res) => {
listFetchedSet(false);
deletingSet(deleting.filter((item: any) => item === sampleToken)); // remove from deleting list
});
};
const sampleClick =
() =>
({ target }: { target: any }) => {
let sampleToken =
samples[target.name.split(",")[0].split(":")[1]].sample_token;
deletingSet([...deleting, sampleToken]); // add to deleting list
DeleteSample(sampleToken, { as_mod: false, set_delete: true }).then(
res => {
listFetchedSet(false);
deletingSet(deleting.filter((item: any) => item === sampleToken)); // remove from deleting list
}
);
};
const actionSamples = [ // these spread operators combine the inProgress and sample arrays
const actionSamples = [
// these spread operators combine the inProgress and sample arrays
...inProgress,
...samples.map((sample: any, i: number) => {
let date = new Date(sample.created_at);
return {
...sample,
badge: SampleBadge,
buttons: [
{
label: "Delete",
small: true,
variant: "secondary",
onClick: sampleClick()
},
],
name: `Sample from ${ date ? moment(date).format("MMMM Do YYYY, h:mm a") : "" }`,
};
})
let date = new Date(sample.created_at);
return {
...sample,
badge: SampleBadge,
buttons: [
{
label: "Delete",
small: true,
variant: "secondary",
onClick: sampleClick(),
},
],
name: `Sample from ${
date ? moment(date).format("MMMM Do YYYY, h:mm a") : ""
}`,
};
}),
];
useEffect(() => {
if (audioProps.file && datasetToken) {
let uuid_idempotency_token = uuidv4();
audioProps.clear();
inProgressSet([ // add sample to in progress list
inProgressSet([
// add sample to in progress list
{
// badge: Component // this can be a loading indicator
// badge: Component // this can be a loading indicator
name: "Uploading",
uuid_idempotency_token
uuid_idempotency_token,
},
...inProgress
...inProgress,
]);
UploadSample("",{
UploadSample("", {
dataset_token: datasetToken || "",
file: audioProps.file,
uuid_idempotency_token,
})
.then((res) => {
}).then(res => {
if (res.success) {
inProgressSet(inProgress.filter((item: any) => // removes sample from in progress list
item.uuid_idempotency_token === uuid_idempotency_token)
inProgressSet(
inProgress.filter(
(
item: any // removes sample from in progress list
) => item.uuid_idempotency_token === uuid_idempotency_token
)
);
listFetchedSet(false); // refetches sample list
}
@@ -84,30 +106,40 @@ function UploadSamples({ audioProps, datasetToken, deleting, deletingSet, inProg
if (datasetToken && !listFetched) {
listFetchedSet(true);
ListSamplesForDataset(datasetToken,{})
.then((res) => {
ListSamplesForDataset(datasetToken, {}).then(res => {
if (res.success && res.samples) {
samplesSet(res.samples);
}
});
}
}, [
audioProps,
datasetToken,
listFetched,
inProgress,
inProgressSet,
samplesSet,
]);
},[audioProps, datasetToken, listFetched, inProgress, inProgressSet, samplesSet]);
return <div className="d-flex flex-column gap-4">
<label className="sub-title">Upload Audio</label>
<div className="d-flex flex-column gap-3 upload-component">
<AudioInput {...{ ...audioProps }}/>
{ actionSamples.length ? <ListItems {...{ data: actionSamples, isLoading: false }}/> :
<div className="panel panel-inner text-center p-5 rounded-5 h-100">
<div className="d-flex flex-column opacity-75 h-100 justify-content-center">
<FontAwesomeIcon icon={faWaveform} className="fs-3 mb-3" />
<h5>No voice samples yet</h5>
<p>Uploaded samples will appear here.</p>
return (
<div>
<label className="sub-title">Upload Audio</label>
<div className="d-flex flex-column gap-3 upload-component">
<AudioInput {...{ ...audioProps }} />
{actionSamples.length ? (
<ListItems {...{ data: actionSamples, isLoading: false }} />
) : (
<div className="panel panel-inner text-center p-5 rounded-5 h-100">
<div className="d-flex flex-column opacity-75 h-100 justify-content-center">
<FontAwesomeIcon icon={faWaveform} className="fs-3 mb-3" />
<h5>No voice samples yet</h5>
<p>Uploaded samples will appear here.</p>
</div>
</div>
</div> }
)}
</div>
</div>
</div>;
);
}
export { UploadSamples };
@@ -24,11 +24,13 @@ function VoiceDetails({ datasetInputs }: { datasetInputs: any }) {
const classNames = SearchFieldClass;
return (
<div className="d-flex flex-column gap-4">
{ datasetInputs.map(({ type = "", options = [], ...props }, key: number) => {
if (type === "text") return <Input {...{ ...props, key }} />;
else return <Select {...{ ...props, classNames, key, options } }/>;
}) }
<div>
{datasetInputs.map(
({ type = "", options = [], ...props }, key: number) => {
if (type === "text") return <Input {...{ ...props, key }} />;
else return <Select {...{ ...props, classNames, key, options }} />;
}
)}
</div>
);
}