Model/IR Select dialog for large downloads
This commit is contained in:
Vendored
+1
-1
@@ -175,7 +175,7 @@
|
||||
"cSpell.ignoreWords": [
|
||||
"nammodel"
|
||||
],
|
||||
"cSpell.enabled": true,
|
||||
"cSpell.enabled": false,
|
||||
|
||||
// Disable all automatic completion suggestions - only show when Ctrl+Space is pressed
|
||||
"editor.quickSuggestions": {
|
||||
|
||||
@@ -314,7 +314,7 @@ static std::map<std::string, std::string> gearEnumValues =
|
||||
{"full-rig", "Full rig"},
|
||||
{"pedal", "Pedal"},
|
||||
{"outboard", "Outboard"},
|
||||
{"ir", "I/R"}};
|
||||
{"ir", "IR"}};
|
||||
|
||||
static std::string mdGear(const std::string &gear)
|
||||
{
|
||||
|
||||
@@ -713,7 +713,7 @@ static std::map<std::string, std::string> gearEnumValues =
|
||||
{"full-rig", "Full rig"},
|
||||
{"pedal", "Pedal"},
|
||||
{"outboard", "Outboard"},
|
||||
{"ir", "I/R"}};
|
||||
{"ir", "IR"}};
|
||||
|
||||
static std::string mdGear(const std::string &gear)
|
||||
{
|
||||
@@ -926,7 +926,7 @@ static std::string mdLicense(const std::string &license)
|
||||
static std::map<std::string, std::string> platformEnumValues =
|
||||
{
|
||||
{"nam", "NAM"},
|
||||
{"ir", "I/R"},
|
||||
{"ir", "IR"},
|
||||
{"aida-x", "Aida X"},
|
||||
{"aa-snapshot", "aa-snapshot"},
|
||||
{"proteus", "Proteus"}};
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace
|
||||
{"full-rig", "Full rig"},
|
||||
{"pedal", "Pedal"},
|
||||
{"outboard", "Outboard"},
|
||||
{"ir", "I/R"}};
|
||||
{"ir", "IR"}};
|
||||
|
||||
static std::string mdGear(const std::string &gear)
|
||||
{
|
||||
@@ -356,7 +356,7 @@ namespace
|
||||
static std::map<std::string, std::string> platformEnumValues =
|
||||
{
|
||||
{"nam", "NAM"},
|
||||
{"ir", "I/R"},
|
||||
{"ir", "IR"},
|
||||
{"aida-x", "Aida X"},
|
||||
{"aa-snapshot", "aa-snapshot"},
|
||||
{"proteus", "Proteus"}};
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ add_custom_command(
|
||||
public/css/roboto.css
|
||||
public/html/t3k_response.html
|
||||
public/var/current_pedalboard.json
|
||||
public/var/config.json.disabled
|
||||
public/var/config.json
|
||||
public/var/uiplugins.json
|
||||
public/var/plugin_classes.json
|
||||
public/testTone300Popup.html
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
npm run dev -- --host 0.0.0.0 --host lothlorien.local
|
||||
npm run dev -- --host 0.0.0.0
|
||||
|
||||
@@ -29,7 +29,7 @@ interface DialogExState {
|
||||
interface DialogExProps extends DialogProps {
|
||||
tag: string;
|
||||
fullwidth?: boolean;
|
||||
onEnterKey: () => void;
|
||||
onEnterKey?: () => void;
|
||||
dlgRef?: (instance: HTMLDivElement | null) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ import HomeIcon from '@mui/icons-material/Home';
|
||||
import FilePropertyDirectorySelectDialog from './FilePropertyDirectorySelectDialog';
|
||||
import { getAlbumArtUri, getTrackTitle } from './AudioFileMetadata';
|
||||
import Tone3000DownloadType from './Tone3000DownloadType';
|
||||
import { ModelSelectionDialog, ModelSelectionDialogParams } from './ModelSelectionDialog';
|
||||
|
||||
|
||||
const ToobNamModelFileUrl = "http://two-play.com/plugins/toob-nam#modelFile";
|
||||
@@ -182,6 +183,7 @@ export interface FilePropertyDialogState {
|
||||
|
||||
textFileName?: string;
|
||||
|
||||
modelSelectionDialogParams?: ModelSelectionDialogParams;
|
||||
};
|
||||
|
||||
interface DragState {
|
||||
@@ -255,7 +257,8 @@ export default withStyles(
|
||||
multiSelect: false,
|
||||
selectedFiles: [],
|
||||
openTone3000Help: false,
|
||||
openGuitarMlHelp: false
|
||||
openGuitarMlHelp: false,
|
||||
modelSelectionDialogParams: undefined,
|
||||
};
|
||||
this.requestScroll = true;
|
||||
}
|
||||
@@ -588,8 +591,19 @@ export default withStyles(
|
||||
this.requestFiles(this.state.navDirectory)
|
||||
this.model.onTone3000DownloadCompleteEvent.addEventHandler(this.handleTone3000DownloadComplete);
|
||||
this.requestScroll = true;
|
||||
|
||||
this.model.setT3kModelSelectionDialogListener({
|
||||
onShowDialog: (modelSelectionDialogParams: ModelSelectionDialogParams) => {
|
||||
this.setState({
|
||||
modelSelectionDialogParams: modelSelectionDialogParams
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.model.setT3kModelSelectionDialogListener(undefined);
|
||||
this.stopAutoScroll();
|
||||
this.cancelProgressTimeout();
|
||||
this.model.onTone3000DownloadCompleteEvent.removeEventHandler(this.handleTone3000DownloadComplete);
|
||||
@@ -939,7 +953,8 @@ export default withStyles(
|
||||
);
|
||||
}
|
||||
|
||||
getDefaultPath(): string {
|
||||
// yyy: depends on dialog type!!!
|
||||
private getDefaultPath(): string {
|
||||
try {
|
||||
let storage = window.localStorage;
|
||||
let result = storage.getItem("fpDefaultPath");
|
||||
@@ -1100,14 +1115,13 @@ export default withStyles(
|
||||
let downloadType: Tone3000DownloadType = Tone3000DownloadType.Nam;
|
||||
if (this.props.fileProperty.patchProperty === ToobNamModelFileUrl) {
|
||||
downloadType = Tone3000DownloadType.Nam;
|
||||
} else if (ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty))
|
||||
{
|
||||
} else if (ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty)) {
|
||||
downloadType = Tone3000DownloadType.CabIr;
|
||||
} else {
|
||||
throw new Error("Unsupported file property for Tone3000 dialog");
|
||||
}
|
||||
this.model.showTone3000DownloadPopup(
|
||||
downloadType,
|
||||
downloadType,
|
||||
this.state.currentDirectory);
|
||||
}
|
||||
|
||||
@@ -1147,14 +1161,14 @@ export default withStyles(
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const isTracksDirectory = this.isTracksDirectory();
|
||||
const isToobNamModelFile = this.props.fileProperty.patchProperty === ToobNamModelFileUrl;
|
||||
const isToobCabIrFile = ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty);
|
||||
const isToobCabIrFile = ToobCabIrFileUrls.includes(this.props.fileProperty.patchProperty);
|
||||
const isToobMLModelFile = this.props.fileProperty.patchProperty === ToobMlModelFileUrl;
|
||||
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
@@ -1726,6 +1740,16 @@ export default withStyles(
|
||||
|
||||
|
||||
/>
|
||||
{this.state.modelSelectionDialogParams && (
|
||||
<ModelSelectionDialog open={true}
|
||||
params={
|
||||
this.state.modelSelectionDialogParams
|
||||
}
|
||||
onClose={
|
||||
() => { this.setState({ modelSelectionDialogParams: undefined }); }
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<OkCancelDialog open={this.state.openConfirmDeleteDialog}
|
||||
|
||||
text={
|
||||
@@ -1826,7 +1850,8 @@ export default withStyles(
|
||||
title={pathFileNameOnly(this.state.textFileName)}
|
||||
fileName={this.state.textFileName} onClose={() => this.setState({ textFileName: undefined })}
|
||||
onT3kLinkClick={(href) => {
|
||||
return this.handleT3kLinkClick(href); }
|
||||
return this.handleT3kLinkClick(href);
|
||||
}
|
||||
}
|
||||
/>
|
||||
)}
|
||||
@@ -1853,7 +1878,7 @@ export default withStyles(
|
||||
// open pdf in new tab
|
||||
this.model.displayMediaFile(fileName);
|
||||
}
|
||||
|
||||
|
||||
handleShowTextFile(fileName: string) {
|
||||
this.setState({ textFileName: fileName });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Robin E. R. Davies
|
||||
* All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import Checkbox from "@mui/material/Checkbox";
|
||||
import DialogActions from "@mui/material/DialogActions";
|
||||
import DialogContent from "@mui/material/DialogContent";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import DialogEx from "./DialogEx";
|
||||
import { Model } from "./t3k/types.ts";
|
||||
import Tone3000DownloadType from "./Tone3000DownloadType.tsx";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import IconButtonEx from "./IconButtonEx.tsx";
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
import DialogTitle from "@mui/material/DialogTitle";
|
||||
import useWindowSize from "./UseWindowSize.tsx";
|
||||
|
||||
interface ModelSelection {
|
||||
selected: boolean;
|
||||
model: Model;
|
||||
}
|
||||
|
||||
export interface ModelSelectionDialogParams {
|
||||
downloadType: Tone3000DownloadType;
|
||||
toneName: string;
|
||||
models: Model[];
|
||||
onCancel: () => void;
|
||||
onModelsSelected: (selectedModels: Model[]) => void;
|
||||
};
|
||||
|
||||
export function ModelSelectionDialog(
|
||||
props: {
|
||||
open: boolean;
|
||||
params: ModelSelectionDialogParams;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
|
||||
const { models, toneName, onCancel, onModelsSelected } = props.params;
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
const [modelSelection, setModelSelection] = React.useState<ModelSelection[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setModelSelection(models.map((model) => ({
|
||||
selected: false,
|
||||
model,
|
||||
})));
|
||||
}, [models]);
|
||||
|
||||
const selectedCount = modelSelection.filter((selection) => selection.selected).length;
|
||||
const allSelected = modelSelection.length > 0 && selectedCount === modelSelection.length;
|
||||
const partiallySelected = selectedCount > 0 && selectedCount < modelSelection.length;
|
||||
|
||||
const toggleAll = () => {
|
||||
setModelSelection((currentSelection) => {
|
||||
const nextSelected = !allSelected;
|
||||
return currentSelection.map((selection) => ({
|
||||
...selection,
|
||||
selected: nextSelected,
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
const toggleModel = (modelId: number) => {
|
||||
setModelSelection((currentSelection) => currentSelection.map((selection) => {
|
||||
if (selection.model.id !== modelId) {
|
||||
return selection;
|
||||
}
|
||||
return {
|
||||
...selection,
|
||||
selected: !selection.selected,
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
onCancel();
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
onModelsSelected(
|
||||
modelSelection
|
||||
.filter((selection) => selection.selected)
|
||||
.map((selection) => selection.model)
|
||||
);
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
let title = props.params.downloadType === Tone3000DownloadType.Nam
|
||||
? "Select Models" :
|
||||
"Select IRs ";
|
||||
|
||||
let tableTitle =
|
||||
"(" + selectedCount.toString() + " of " + models.length.toString() + " selected) - " + toneName
|
||||
|
||||
return (
|
||||
<DialogEx tag="selectModels" open={props.open} onClose={() => { /* Do nothing */ }}
|
||||
fullWidth={true} maxWidth="md"
|
||||
fullScreen={windowSize[0].width < 450}
|
||||
|
||||
|
||||
>
|
||||
<DialogTitle style={{
|
||||
paddingBottom: 0,
|
||||
marginBottom: 0, paddingTop: 0,
|
||||
}} >
|
||||
|
||||
<Toolbar style={{ padding: 0 }}>
|
||||
<IconButtonEx
|
||||
tooltip="Back"
|
||||
edge="start"
|
||||
color="inherit"
|
||||
aria-label="back"
|
||||
style={{ opacity: 0.6 }}
|
||||
onClick={() => { handleCancel(); }}
|
||||
>
|
||||
<ArrowBackIcon style={{ width: 24, height: 24 }} />
|
||||
</IconButtonEx>
|
||||
<Typography noWrap component="div" sx={{ flexGrow: 1 }}>
|
||||
{title}
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</DialogTitle>
|
||||
<DialogContent sx={{ marginLeft: 0, marginRight: 0, paddingLeft: 0, paddingRight: 0 }}>
|
||||
<TableContainer component={Paper} variant="outlined" sx={{ backgroundColor: "transparent", border: "0px" }} >
|
||||
<Table sx={{ backgroundColor: "transparent" }}>
|
||||
<TableHead style={{ backgroundColor: "transparent" }}>
|
||||
<TableRow sx={{ backgroundColor: "transparent" }} onClick={toggleAll}>
|
||||
<TableCell padding="checkbox" sx={{ backgroundColor: "transparent" }}>
|
||||
<Checkbox
|
||||
checked={allSelected}
|
||||
indeterminate={partiallySelected}
|
||||
onChange={toggleAll}
|
||||
sx={{marginLeft: 1}}
|
||||
inputProps={{ 'aria-label': 'select all models' }}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell sx={{ backgroundColor: "transparent" }}>
|
||||
<Typography noWrap variant="body1">{tableTitle}</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody style={{ backgroundColor: "transparent" }}>
|
||||
{modelSelection.map((selection) => (
|
||||
<TableRow
|
||||
key={selection.model.id}
|
||||
onClick={() => toggleModel(selection.model.id)}
|
||||
sx={{ cursor: 'pointer', backgroundColor: 'transparent' }}
|
||||
>
|
||||
<TableCell padding="checkbox" sx={{ backgroundColor: "transparent", paddingLeft: 3, borderBottom: "0px" }}>
|
||||
<Checkbox
|
||||
checked={selection.selected}
|
||||
onClick={(event) => { event.stopPropagation(); }}
|
||||
onChange={() => toggleModel(selection.model.id)}
|
||||
inputProps={{ 'aria-labelledby': `model-selection-${selection.model.id}` }}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell id={`model-selection-${selection.model.id}`} sx={{ backgroundColor: "transparent", borderBottom: "0px" }}>
|
||||
<Typography noWrap variant="body2">
|
||||
{selection.model.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</DialogContent>
|
||||
<Divider />
|
||||
<DialogActions>
|
||||
<Button onClick={handleCancel} variant="dialogSecondary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleOk} variant="dialogPrimary" disabled={selectedCount === 0}>
|
||||
OK
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogEx>
|
||||
);
|
||||
}
|
||||
@@ -50,7 +50,8 @@ import { AlsaSequencerConfiguration, AlsaSequencerPortSelection } from './AlsaSe
|
||||
import { getDefaultModGuiPreference } from './ModGuiHost';
|
||||
import ChannelRouterSettings from './ChannelRouterSettings';
|
||||
import Tone3000DownloadProgress from './Tone3000DownloadProgress';
|
||||
import { Tone } from './t3k/types';
|
||||
import { Model, Tone } from './t3k/types';
|
||||
import { ModelSelectionDialogParams } from './ModelSelectionDialog';
|
||||
|
||||
|
||||
export enum State {
|
||||
@@ -66,6 +67,11 @@ export enum State {
|
||||
HotspotChanging,
|
||||
};
|
||||
|
||||
export interface T3kModelSelectionDialogListener {
|
||||
onShowDialog: (
|
||||
modelSelectionDialogParams: ModelSelectionDialogParams
|
||||
) => void;
|
||||
};
|
||||
export interface Tone3000PkceParams {
|
||||
publishableKey: string;
|
||||
redirectUrl: string;
|
||||
@@ -708,19 +714,16 @@ export class PiPedalModel //implements PiPedalModel
|
||||
|
||||
}
|
||||
|
||||
async makeTone3000Pkce(redirectUrl: string) : Promise<Tone3000PkceParams>
|
||||
{
|
||||
if (this.webSocket === undefined)
|
||||
{
|
||||
async makeTone3000Pkce(redirectUrl: string): Promise<Tone3000PkceParams> {
|
||||
if (this.webSocket === undefined) {
|
||||
throw new Error("Server disconnected.");
|
||||
}
|
||||
return await this.webSocket.request<Tone3000PkceParams>(
|
||||
"makeTone3000Pkce", redirectUrl);
|
||||
}
|
||||
|
||||
async sha256Base64url(intput: string) : Promise<string> {
|
||||
if (this.webSocket === undefined)
|
||||
{
|
||||
async sha256Base64url(intput: string): Promise<string> {
|
||||
if (this.webSocket === undefined) {
|
||||
throw new Error("Server disconnected.");
|
||||
}
|
||||
return this.webSocket.request<string>(
|
||||
@@ -774,7 +777,7 @@ export class PiPedalModel //implements PiPedalModel
|
||||
showTone3000DownloadPopup(
|
||||
downloadType: Tone3000DownloadType,
|
||||
downloadPath: string,
|
||||
options?: {
|
||||
options?: {
|
||||
userName?: string;
|
||||
}
|
||||
): void {
|
||||
@@ -1336,7 +1339,7 @@ export class PiPedalModel //implements PiPedalModel
|
||||
}
|
||||
|
||||
async writeTone3000Readme(
|
||||
filePath: string,
|
||||
filePath: string,
|
||||
tone: Tone,
|
||||
thumbnailUrl: string
|
||||
|
||||
@@ -3938,14 +3941,50 @@ export class PiPedalModel //implements PiPedalModel
|
||||
downloadType: Tone3000DownloadType
|
||||
): void {
|
||||
if (this.webSocket) {
|
||||
this.webSocket.send("DownloadModelsFromTone3000", {
|
||||
responseUri: responseUri,
|
||||
this.webSocket.send("DownloadModelsFromTone3000", {
|
||||
responseUri: responseUri,
|
||||
tone3000PckceParams: tone3000PckceParams,
|
||||
downloadPath: downloadPath,
|
||||
downloadType: downloadType === Tone3000DownloadType.Nam ? 0: 1
|
||||
});
|
||||
downloadType: downloadType === Tone3000DownloadType.Nam ? 0 : 1
|
||||
});
|
||||
}
|
||||
}
|
||||
private t3kModelSelectionDialogListener?: T3kModelSelectionDialogListener = undefined;
|
||||
|
||||
setT3kModelSelectionDialogListener(
|
||||
listener: T3kModelSelectionDialogListener | undefined
|
||||
) {
|
||||
this.t3kModelSelectionDialogListener = listener;
|
||||
}
|
||||
showT3kModelSelectionDialog(
|
||||
downloadType: Tone3000DownloadType,
|
||||
toneName: string,
|
||||
models: Model[],
|
||||
onModelsSelected: (selectedModels: Model[]) => void,
|
||||
onCancel: () => void
|
||||
) {
|
||||
if (!this.t3kModelSelectionDialogListener) {
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
this.tone3000Downloading.set(false);
|
||||
this.t3kModelSelectionDialogListener.onShowDialog(
|
||||
{
|
||||
downloadType: downloadType,
|
||||
toneName: toneName,
|
||||
models: models,
|
||||
onModelsSelected: (selectedModels: Model[]) => {
|
||||
this.tone3000Downloading.set(true);
|
||||
onModelsSelected(selectedModels);
|
||||
},
|
||||
onCancel: () => {
|
||||
this.tone3000Downloading.set(false);
|
||||
onCancel();
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -211,6 +211,28 @@ export class Tone3000DownloadHandler {
|
||||
this.progress.transferring = false;
|
||||
this.model.onTone3000DownloadComplete(resultPath);
|
||||
}
|
||||
|
||||
|
||||
private async maybeSelectModels(toneName: string, models: Model[]): Promise<Model[]> {
|
||||
let result = new Promise<Model[]>((resolve, reject) => {
|
||||
if (models.length < 12) {
|
||||
resolve(models);
|
||||
return;
|
||||
}
|
||||
this.model.showT3kModelSelectionDialog(
|
||||
this.downloadType,
|
||||
toneName,
|
||||
models,
|
||||
(models: Model[])=> {
|
||||
resolve(models);
|
||||
},
|
||||
() => {
|
||||
reject(new Error("canceled"));
|
||||
});
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
private async DownloadModelsFromTone3000(
|
||||
responseUri: string,
|
||||
tone3000PckceParams: Tone3000PkceParams,
|
||||
@@ -293,6 +315,14 @@ export class Tone3000DownloadHandler {
|
||||
}
|
||||
++page;
|
||||
}
|
||||
|
||||
try {
|
||||
models = await this.maybeSelectModels(tone.title, models);
|
||||
} catch (e) {
|
||||
// canceled.
|
||||
this.onTone3000DownloadComplete("");
|
||||
return;
|
||||
}
|
||||
let uploadPath = this.downloadPath;
|
||||
let extension: string;
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ export default defineConfig({
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: false,
|
||||
},
|
||||
'^/var/.*': {
|
||||
'^/var/(?!config\\.json$).*': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: false,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user