Allow saving configuration from the first-time wizard
This just updates the config and saves it to `flamenco-manager.yaml`. Saving the configuration doesn't restart the Manager yet, that's for another commit.
This commit is contained in:
parent
f9a3d3864a
commit
10f56148d4
@ -165,6 +165,9 @@ type ConfigService interface {
|
|||||||
// ForceFirstRun forces IsFirstRun() to return true. This is used to force the
|
// ForceFirstRun forces IsFirstRun() to return true. This is used to force the
|
||||||
// first-time wizard on a configured system.
|
// first-time wizard on a configured system.
|
||||||
ForceFirstRun()
|
ForceFirstRun()
|
||||||
|
|
||||||
|
// Save writes the in-memory configuration to the config file.
|
||||||
|
Save() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Shaman interface {
|
type Shaman interface {
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.blender.org/flamenco/internal/appinfo"
|
"git.blender.org/flamenco/internal/appinfo"
|
||||||
"git.blender.org/flamenco/internal/find_blender"
|
"git.blender.org/flamenco/internal/find_blender"
|
||||||
@ -168,6 +170,7 @@ func (f *Flamenco) FindBlenderExePath(e echo.Context) error {
|
|||||||
default:
|
default:
|
||||||
response = append(response, api.BlenderPathCheckResult{
|
response = append(response, api.BlenderPathCheckResult{
|
||||||
IsUsable: true,
|
IsUsable: true,
|
||||||
|
Input: result.Input,
|
||||||
Path: result.FoundLocation,
|
Path: result.FoundLocation,
|
||||||
Cause: result.BlenderVersion,
|
Cause: result.BlenderVersion,
|
||||||
Source: result.Source,
|
Source: result.Source,
|
||||||
@ -186,6 +189,7 @@ func (f *Flamenco) FindBlenderExePath(e echo.Context) error {
|
|||||||
default:
|
default:
|
||||||
response = append(response, api.BlenderPathCheckResult{
|
response = append(response, api.BlenderPathCheckResult{
|
||||||
IsUsable: true,
|
IsUsable: true,
|
||||||
|
Input: result.Input,
|
||||||
Path: result.FoundLocation,
|
Path: result.FoundLocation,
|
||||||
Cause: result.BlenderVersion,
|
Cause: result.BlenderVersion,
|
||||||
Source: result.Source,
|
Source: result.Source,
|
||||||
@ -212,6 +216,7 @@ func (f *Flamenco) CheckBlenderExePath(e echo.Context) error {
|
|||||||
ctx := e.Request().Context()
|
ctx := e.Request().Context()
|
||||||
checkResult, err := find_blender.CheckBlender(ctx, command)
|
checkResult, err := find_blender.CheckBlender(ctx, command)
|
||||||
response := api.BlenderPathCheckResult{
|
response := api.BlenderPathCheckResult{
|
||||||
|
Input: command,
|
||||||
Source: checkResult.Source,
|
Source: checkResult.Source,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +234,67 @@ func (f *Flamenco) CheckBlenderExePath(e echo.Context) error {
|
|||||||
return e.JSON(http.StatusOK, response)
|
return e.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Flamenco) SaveWizardConfig(e echo.Context) error {
|
||||||
|
logger := requestLogger(e)
|
||||||
|
|
||||||
|
var wizardCfg api.WizardConfig
|
||||||
|
if err := e.Bind(&wizardCfg); err != nil {
|
||||||
|
logger.Warn().Err(err).Msg("first-time wizard: bad request received")
|
||||||
|
return sendAPIError(e, http.StatusBadRequest, "invalid format")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = logger.With().Interface("config", wizardCfg).Logger()
|
||||||
|
|
||||||
|
if wizardCfg.StorageLocation == "" ||
|
||||||
|
!wizardCfg.BlenderExecutable.IsUsable ||
|
||||||
|
wizardCfg.BlenderExecutable.Path == "" {
|
||||||
|
logger.Warn().Msg("first-time wizard: configuration is incomplete, unable to accept")
|
||||||
|
return sendAPIError(e, http.StatusBadRequest, "configuration is incomplete")
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := f.config.Get()
|
||||||
|
conf.SharedStoragePath = wizardCfg.StorageLocation
|
||||||
|
|
||||||
|
var executable string
|
||||||
|
switch wizardCfg.BlenderExecutable.Source {
|
||||||
|
case api.BlenderPathSourceFileAssociation:
|
||||||
|
// The Worker will try to use the file association when the command is set
|
||||||
|
// to the string "blender".
|
||||||
|
executable = "blender"
|
||||||
|
case api.BlenderPathSourcePathEnvvar:
|
||||||
|
// The input command can be found on $PATH, and thus we don't need to save
|
||||||
|
// the absolute path to Blender here.
|
||||||
|
executable = wizardCfg.BlenderExecutable.Input
|
||||||
|
case api.BlenderPathSourceInputPath:
|
||||||
|
// The path should be used as-is.
|
||||||
|
executable = wizardCfg.BlenderExecutable.Path
|
||||||
|
}
|
||||||
|
if commandNeedsQuoting(executable) {
|
||||||
|
executable = strconv.Quote(executable)
|
||||||
|
}
|
||||||
|
blenderCommand := fmt.Sprintf("%s %s", executable, config.DefaultBlenderArguments)
|
||||||
|
|
||||||
|
// Use the same command for each platform for now, but put them each in their
|
||||||
|
// own definition so that they're easier to edit later.
|
||||||
|
conf.Variables["blender"] = config.Variable{
|
||||||
|
IsTwoWay: false,
|
||||||
|
Values: config.VariableValues{
|
||||||
|
{Platform: "linux", Value: blenderCommand},
|
||||||
|
{Platform: "windows", Value: blenderCommand},
|
||||||
|
{Platform: "darwin", Value: blenderCommand},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the final configuration to disk.
|
||||||
|
if err := f.config.Save(); err != nil {
|
||||||
|
logger.Error().Err(err).Msg("error saving configuration file")
|
||||||
|
return sendAPIError(e, http.StatusInternalServerError, "first-time wizard: error saving configuration file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info().Msg("first-time wizard: updating configuration")
|
||||||
|
return e.NoContent(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
func flamencoManagerDir() (string, error) {
|
func flamencoManagerDir() (string, error) {
|
||||||
exename, err := os.Executable()
|
exename, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -236,3 +302,7 @@ func flamencoManagerDir() (string, error) {
|
|||||||
}
|
}
|
||||||
return filepath.Dir(exename), nil
|
return filepath.Dir(exename), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func commandNeedsQuoting(cmd string) bool {
|
||||||
|
return strings.ContainsAny(cmd, " \n\t;()")
|
||||||
|
}
|
||||||
|
@ -116,6 +116,102 @@ func TestCheckSharedStoragePath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSaveWizardConfig(t *testing.T) {
|
||||||
|
mf, finish := metaTestFixtures(t)
|
||||||
|
defer finish()
|
||||||
|
|
||||||
|
doTest := func(body api.WizardConfig) config.Conf {
|
||||||
|
// Always start the test with a clean configuration.
|
||||||
|
originalConfig := config.DefaultConfig(func(c *config.Conf) {
|
||||||
|
c.SharedStoragePath = ""
|
||||||
|
})
|
||||||
|
var savedConfig config.Conf
|
||||||
|
|
||||||
|
// Mock the loading & saving of the config.
|
||||||
|
mf.config.EXPECT().Get().Return(&originalConfig)
|
||||||
|
mf.config.EXPECT().Save().Do(func() error {
|
||||||
|
savedConfig = originalConfig
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Call the API.
|
||||||
|
echoCtx := mf.prepareMockedJSONRequest(body)
|
||||||
|
err := mf.flamenco.SaveWizardConfig(echoCtx)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertResponseNoContent(t, echoCtx)
|
||||||
|
return savedConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test situation where file association with .blend files resulted in a blender executable.
|
||||||
|
{
|
||||||
|
savedConfig := doTest(api.WizardConfig{
|
||||||
|
StorageLocation: mf.tempdir,
|
||||||
|
BlenderExecutable: api.BlenderPathCheckResult{
|
||||||
|
IsUsable: true,
|
||||||
|
Input: "",
|
||||||
|
Path: "/path/to/blender",
|
||||||
|
Source: api.BlenderPathSourceFileAssociation,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(t, mf.tempdir, savedConfig.SharedStoragePath)
|
||||||
|
expectBlenderVar := config.Variable{
|
||||||
|
Values: config.VariableValues{
|
||||||
|
{Platform: "linux", Value: "blender " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "windows", Value: "blender " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "darwin", Value: "blender " + config.DefaultBlenderArguments},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectBlenderVar, savedConfig.Variables["blender"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test situation where the given command could be found on $PATH.
|
||||||
|
{
|
||||||
|
savedConfig := doTest(api.WizardConfig{
|
||||||
|
StorageLocation: mf.tempdir,
|
||||||
|
BlenderExecutable: api.BlenderPathCheckResult{
|
||||||
|
IsUsable: true,
|
||||||
|
Input: "kitty",
|
||||||
|
Path: "/path/to/kitty",
|
||||||
|
Source: api.BlenderPathSourcePathEnvvar,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(t, mf.tempdir, savedConfig.SharedStoragePath)
|
||||||
|
expectBlenderVar := config.Variable{
|
||||||
|
Values: config.VariableValues{
|
||||||
|
{Platform: "linux", Value: "kitty " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "windows", Value: "kitty " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "darwin", Value: "kitty " + config.DefaultBlenderArguments},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectBlenderVar, savedConfig.Variables["blender"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test a custom command given with the full path.
|
||||||
|
{
|
||||||
|
savedConfig := doTest(api.WizardConfig{
|
||||||
|
StorageLocation: mf.tempdir,
|
||||||
|
BlenderExecutable: api.BlenderPathCheckResult{
|
||||||
|
IsUsable: true,
|
||||||
|
Input: "/bin/cat",
|
||||||
|
Path: "/bin/cat",
|
||||||
|
Source: api.BlenderPathSourceInputPath,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(t, mf.tempdir, savedConfig.SharedStoragePath)
|
||||||
|
expectBlenderVar := config.Variable{
|
||||||
|
Values: config.VariableValues{
|
||||||
|
{Platform: "linux", Value: "/bin/cat " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "windows", Value: "/bin/cat " + config.DefaultBlenderArguments},
|
||||||
|
{Platform: "darwin", Value: "/bin/cat " + config.DefaultBlenderArguments},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectBlenderVar, savedConfig.Variables["blender"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func metaTestFixtures(t *testing.T) (mockedFlamenco, func()) {
|
func metaTestFixtures(t *testing.T) (mockedFlamenco, func()) {
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
mf := newMockedFlamenco(mockCtrl)
|
mf := newMockedFlamenco(mockCtrl)
|
||||||
|
@ -754,6 +754,20 @@ func (mr *MockConfigServiceMockRecorder) ResolveVariables(arg0, arg1 interface{}
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveVariables", reflect.TypeOf((*MockConfigService)(nil).ResolveVariables), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveVariables", reflect.TypeOf((*MockConfigService)(nil).ResolveVariables), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save mocks base method.
|
||||||
|
func (m *MockConfigService) Save() error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Save")
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save indicates an expected call of Save.
|
||||||
|
func (mr *MockConfigServiceMockRecorder) Save() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockConfigService)(nil).Save))
|
||||||
|
}
|
||||||
|
|
||||||
// MockTaskStateMachine is a mock of TaskStateMachine interface.
|
// MockTaskStateMachine is a mock of TaskStateMachine interface.
|
||||||
type MockTaskStateMachine struct {
|
type MockTaskStateMachine struct {
|
||||||
ctrl *gomock.Controller
|
ctrl *gomock.Controller
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
const DefaultBlenderArguments = "--factory-startup -b -y"
|
||||||
|
|
||||||
// The default configuration, use DefaultConfig() to obtain a copy.
|
// The default configuration, use DefaultConfig() to obtain a copy.
|
||||||
var defaultConfig = Conf{
|
var defaultConfig = Conf{
|
||||||
Base: Base{
|
Base: Base{
|
||||||
@ -61,9 +63,9 @@ var defaultConfig = Conf{
|
|||||||
// The default commands assume that the executables are available on $PATH.
|
// The default commands assume that the executables are available on $PATH.
|
||||||
"blender": {
|
"blender": {
|
||||||
Values: VariableValues{
|
Values: VariableValues{
|
||||||
VariableValue{Platform: "linux", Value: "blender --factory-startup -b -y"},
|
VariableValue{Platform: "linux", Value: "blender " + DefaultBlenderArguments},
|
||||||
VariableValue{Platform: "windows", Value: "blender.exe --factory-startup -b -y"},
|
VariableValue{Platform: "windows", Value: "blender.exe " + DefaultBlenderArguments},
|
||||||
VariableValue{Platform: "darwin", Value: "blender --factory-startup -b -y"},
|
VariableValue{Platform: "darwin", Value: "blender " + DefaultBlenderArguments},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<h1>Welcome to Flamenco!</h1>
|
<h1>Welcome to Flamenco!</h1>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<p>Before Flamenco can be used, a few things need to be set up.</p>
|
<p>Before Flamenco can be used, a few things need to be set up. This
|
||||||
<p>This wizard will guide you through the configuration.</p>
|
wizard will guide you through the configuration.</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>Shared Storage</h2>
|
<h2>Shared Storage</h2>
|
||||||
@ -13,10 +13,15 @@
|
|||||||
Manager and Workers exchange files. This could be a NAS in your network,
|
Manager and Workers exchange files. This could be a NAS in your network,
|
||||||
or some other file sharing server.</p>
|
or some other file sharing server.</p>
|
||||||
|
|
||||||
|
<p>Make sure this path is the same for all machines involved.</p>
|
||||||
|
|
||||||
<p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for
|
<p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for
|
||||||
this is not recommended, as Flamenco does not know when every machine has
|
this is not recommended, as Flamenco does not know when every machine has
|
||||||
received the files.</p>
|
received the files.</p>
|
||||||
|
|
||||||
|
<!-- TODO: @submit.prevent makes the button triggerable by pressing ENTER
|
||||||
|
in the input field, but also prevents the browser from caching
|
||||||
|
previously-used values. Would be great if we could have both. -->
|
||||||
<form @submit.prevent="checkSharedStoragePath">
|
<form @submit.prevent="checkSharedStoragePath">
|
||||||
<input v-model="sharedStoragePath" type="text">
|
<input v-model="sharedStoragePath" type="text">
|
||||||
<button type="submit">Check</button>
|
<button type="submit">Check</button>
|
||||||
@ -33,7 +38,7 @@
|
|||||||
|
|
||||||
<p>Choose which Blender to use below:</p>
|
<p>Choose which Blender to use below:</p>
|
||||||
|
|
||||||
<p v-if="blenderExeFinding">... finding Blenders ...</p>
|
<p v-if="isBlenderExeFinding">... finding Blenders ...</p>
|
||||||
<div v-for="blender in allBlenders" class="blender-selector"
|
<div v-for="blender in allBlenders" class="blender-selector"
|
||||||
:class="{ 'selected-blender': (blender == selectedBlender) }">
|
:class="{ 'selected-blender': (blender == selectedBlender) }">
|
||||||
<dl>
|
<dl>
|
||||||
@ -46,7 +51,7 @@
|
|||||||
<dt>Source</dt>
|
<dt>Source</dt>
|
||||||
<dd>{{ sourceLabels[blender.source] }}</dd>
|
<dd>{{ sourceLabels[blender.source] }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<button @click="selectedBlender = blender">Use this Blender</button>
|
<button @click="selectedBlender = blender" :disabled="selectedBlender == blender">Use this Blender</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>Or provide an alternative command to try:</p>
|
<p>Or provide an alternative command to try:</p>
|
||||||
@ -55,12 +60,35 @@
|
|||||||
<input v-model="customBlenderExe" type="text">
|
<input v-model="customBlenderExe" type="text">
|
||||||
<button type="submit">Check</button>
|
<button type="submit">Check</button>
|
||||||
</form>
|
</form>
|
||||||
<p v-if="blenderExeChecking">... checking ...</p>
|
<p v-if="isBlenderExeChecking">... checking ...</p>
|
||||||
<p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
|
<p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
|
||||||
Found something, it is selected above.</p>
|
Found something, it is selected above.</p>
|
||||||
<p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
|
<p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
|
||||||
{{ blenderExeCheckResult.cause }}</p>
|
{{ blenderExeCheckResult.cause }}</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section v-if="isConfigComplete">
|
||||||
|
<h2>The Final Step</h2>
|
||||||
|
<p>This is the configuration that will be used by Flamenco:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Storage</dt>
|
||||||
|
<dd>{{ sharedStorageCheckResult.path }}</dd>
|
||||||
|
<dt>Blender</dt>
|
||||||
|
<dd v-if="selectedBlender.source == 'file_association'">
|
||||||
|
Whatever Blender is associated with .blend files
|
||||||
|
(currently "<code>{{ selectedBlender.path }}</code>")
|
||||||
|
</dd>
|
||||||
|
<dd v-if="selectedBlender.source == 'path_envvar'">
|
||||||
|
The command "<code>{{ selectedBlender.input }}</code>" as found on <code>$PATH</code>
|
||||||
|
(currently "<code>{{ selectedBlender.path }}</code>")
|
||||||
|
</dd>
|
||||||
|
<dd v-if="selectedBlender.source == 'input_path'">
|
||||||
|
The command you provided:
|
||||||
|
"<code>{{ selectedBlender.path }}</code>"
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<button @click="confirmWizard" :disabled="isConfirming">Confirm</button>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="app-footer">
|
<footer class="app-footer">
|
||||||
@ -73,7 +101,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import NotificationBar from '@/components/footer/NotificationBar.vue'
|
import NotificationBar from '@/components/footer/NotificationBar.vue'
|
||||||
import UpdateListener from '@/components/UpdateListener.vue'
|
import UpdateListener from '@/components/UpdateListener.vue'
|
||||||
import { MetaApi, PathCheckInput } from "@/manager-api";
|
import { MetaApi, PathCheckInput, WizardConfig } from "@/manager-api";
|
||||||
import { apiClient } from '@/stores/api-query-count';
|
import { apiClient } from '@/stores/api-query-count';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -90,17 +118,18 @@ export default {
|
|||||||
allBlenders: [], // combination of autoFoundBlenders and blenderExeCheckResult.
|
allBlenders: [], // combination of autoFoundBlenders and blenderExeCheckResult.
|
||||||
|
|
||||||
autoFoundBlenders: [], // list of api.BlenderPathCheckResult
|
autoFoundBlenders: [], // list of api.BlenderPathCheckResult
|
||||||
blenderExeFinding: false,
|
isBlenderExeFinding: false,
|
||||||
selectedBlender: null, // the chosen api.BlenderPathCheckResult
|
selectedBlender: null, // the chosen api.BlenderPathCheckResult
|
||||||
|
|
||||||
customBlenderExe: "",
|
customBlenderExe: "",
|
||||||
blenderExeChecking: false,
|
isBlenderExeChecking: false,
|
||||||
blenderExeCheckResult: null, // api.BlenderPathCheckResult
|
blenderExeCheckResult: null, // api.BlenderPathCheckResult
|
||||||
sourceLabels: {
|
sourceLabels: {
|
||||||
file_association: "This Blender runs when you double-click a .blend file.",
|
file_association: "This Blender runs when you double-click a .blend file.",
|
||||||
path_envvar: "This Blender was found on the $PATH environment.",
|
path_envvar: "This Blender was found on the $PATH environment.",
|
||||||
input_path: "You pointed Flamenco to this executable.",
|
input_path: "You pointed Flamenco to this executable.",
|
||||||
}
|
},
|
||||||
|
isConfirming: false,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
cleanSharedStoragePath() {
|
cleanSharedStoragePath() {
|
||||||
@ -109,6 +138,10 @@ export default {
|
|||||||
cleanCustomBlenderExe() {
|
cleanCustomBlenderExe() {
|
||||||
return this.customBlenderExe.trim();
|
return this.customBlenderExe.trim();
|
||||||
},
|
},
|
||||||
|
isConfigComplete() {
|
||||||
|
return (this.sharedStorageCheckResult != null && this.sharedStorageCheckResult.is_usable) &&
|
||||||
|
(this.selectedBlender != null && this.selectedBlender.is_usable);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.findBlenderExePath();
|
this.findBlenderExePath();
|
||||||
@ -135,7 +168,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
findBlenderExePath() {
|
findBlenderExePath() {
|
||||||
this.blenderExeFinding = true;
|
this.isBlenderExeFinding = true;
|
||||||
this.autoFoundBlenders = [];
|
this.autoFoundBlenders = [];
|
||||||
|
|
||||||
console.log("Finding Blender");
|
console.log("Finding Blender");
|
||||||
@ -149,15 +182,24 @@ export default {
|
|||||||
console.log("Error finding Blender:", error);
|
console.log("Error finding Blender:", error);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.blenderExeFinding = false;
|
this.isBlenderExeFinding = false;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
checkBlenderExePath() {
|
checkBlenderExePath() {
|
||||||
this.blenderExeChecking = true;
|
const exeToTry = this.cleanCustomBlenderExe;
|
||||||
|
if (exeToTry == "") {
|
||||||
|
// Just erase any previously-found custom Blender executable.
|
||||||
|
this.isBlenderExeChecking = false;
|
||||||
|
this.blenderExeCheckResult = null;
|
||||||
|
this._refreshAllBlenders();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isBlenderExeChecking = true;
|
||||||
this.blenderExeCheckResult = null;
|
this.blenderExeCheckResult = null;
|
||||||
|
|
||||||
const pathCheck = new PathCheckInput(this.cleanCustomBlenderExe);
|
const pathCheck = new PathCheckInput(exeToTry);
|
||||||
console.log("requesting path check:", pathCheck);
|
console.log("requesting path check:", pathCheck);
|
||||||
this.metaAPI.checkBlenderExePath({ pathCheckInput: pathCheck })
|
this.metaAPI.checkBlenderExePath({ pathCheckInput: pathCheck })
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@ -172,7 +214,7 @@ export default {
|
|||||||
console.log("Error checking storage path:", error);
|
console.log("Error checking storage path:", error);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.blenderExeChecking = false;
|
this.isBlenderExeChecking = false;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -183,6 +225,25 @@ export default {
|
|||||||
this.allBlenders = this.autoFoundBlenders.concat([this.blenderExeCheckResult]);
|
this.allBlenders = this.autoFoundBlenders.concat([this.blenderExeCheckResult]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
confirmWizard() {
|
||||||
|
const wizardConfig = new WizardConfig(
|
||||||
|
this.sharedStorageCheckResult.path,
|
||||||
|
this.selectedBlender,
|
||||||
|
);
|
||||||
|
console.log("saving configuration:", wizardConfig);
|
||||||
|
this.isConfirming = true;
|
||||||
|
this.metaAPI.saveWizardConfig({ wizardConfig: wizardConfig })
|
||||||
|
.then((result) => {
|
||||||
|
console.log("Wizard config saved, reload the page");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Error saving wizard config:", error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.isConfirming = false;
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user