mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp
This commit is contained in:
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>
|
||||
|
||||
+29
-35
@@ -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">
|
||||
|
||||
+94
-62
@@ -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 };
|
||||
+7
-5
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user