Setup Screen: Use StepsWrapper
Similar to TabsWrapper, with Previous/Next navigation capabilities.
This commit is contained in:
parent
a075a36911
commit
8b02085c5b
13
web/app/src/components/steps/StepItem.vue
Normal file
13
web/app/src/components/steps/StepItem.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<script setup>
|
||||||
|
import { inject } from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
title: String,
|
||||||
|
});
|
||||||
|
const selectedStep = inject('selectedStep');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-show="selectedStep === title">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
124
web/app/src/components/steps/StepsWrapper.vue
Normal file
124
web/app/src/components/steps/StepsWrapper.vue
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useSlots, ref, provide } from 'vue';
|
||||||
|
const slots = useSlots();
|
||||||
|
|
||||||
|
const stepTitles = ref(slots.default().map((step) => step.props.title));
|
||||||
|
const selectedStep = ref(stepTitles.value[0]);
|
||||||
|
provide('selectedStep', selectedStep);
|
||||||
|
|
||||||
|
function updateStepTitle(title) {
|
||||||
|
selectedStep.value = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedStepNumber() {
|
||||||
|
return stepTitles.value.indexOf(selectedStep.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextStepTitle() {
|
||||||
|
selectedStep.value = stepTitles.value[selectedStepNumber() + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevStepTitle() {
|
||||||
|
selectedStep.value = stepTitles.value[selectedStepNumber() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="setup-step">
|
||||||
|
<h2>{{ selectedStep }}</h2>
|
||||||
|
<nav>
|
||||||
|
<ul class="progress">
|
||||||
|
<li
|
||||||
|
v-for="(title, index) in stepTitles"
|
||||||
|
:class="{active: selectedStep == title}"
|
||||||
|
@click="updateStepTitle(title)"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<slot />
|
||||||
|
<div
|
||||||
|
v-if="selectedStepNumber() != stepTitles.length - 1"
|
||||||
|
class="btn-bar btn-bar-wide">
|
||||||
|
<button
|
||||||
|
v-if="selectedStepNumber() > 0"
|
||||||
|
@click="prevStepTitle()"
|
||||||
|
class="btn">Back
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="nextStepTitle()"
|
||||||
|
class="btn btn-primary">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
--wiz-progress-indicator-size: 8px;
|
||||||
|
--wiz-progress-indicator-border-width: 2px;
|
||||||
|
--wiz-progress-indicator-color: var(--color-text-hint);
|
||||||
|
--wiz-progress-indicator-color-active: var(--color-accent);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
list-style: none;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress indicator dot. */
|
||||||
|
.progress li {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress li span {
|
||||||
|
background-color: var(--wiz-progress-indicator-color);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: var(--wiz-progress-indicator-border-width) solid var(--color-background-column);
|
||||||
|
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color);
|
||||||
|
content: '';
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
height: var(--wiz-progress-indicator-size);
|
||||||
|
position: relative;
|
||||||
|
width: var(--wiz-progress-indicator-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress li.active span {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress li.active+li span,
|
||||||
|
.progress li.active+li+li span {
|
||||||
|
background-color: var(--color-background-column);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress indicator line between dots. */
|
||||||
|
.progress:before {
|
||||||
|
background-color: var(--wiz-progress-indicator-color);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: var(--wiz-progress-indicator-border-width);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-step {
|
||||||
|
background-color: var(--color-background-column);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: var(--spacer) var(--spacer-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -1,131 +1,90 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="setup-container">
|
<div class="setup-container">
|
||||||
<section class="setup-step step-intro is-active">
|
<steps-wrapper>
|
||||||
<h1>Welcome</h1>
|
<step-item title="Welcome">
|
||||||
|
<p>Let's set you up.</p>
|
||||||
|
</step-item>
|
||||||
|
|
||||||
<ul class="progress">
|
<step-item title="Shared Storage">
|
||||||
<li class="active"><span></span></li>
|
<p>Flamenco needs some shared storage, to have a central place where the
|
||||||
<li><span></span></li>
|
Manager and Workers exchange files. This could be a NAS in your network,
|
||||||
<li><span></span></li>
|
or some other file sharing server.</p>
|
||||||
<li><span></span></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Let's set you up.</p>
|
<p>Make sure this path is the same for all machines involved.</p>
|
||||||
|
|
||||||
<div class="btn-bar">
|
<p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for
|
||||||
<button class="btn btn-primary align-center">Start Setup</button>
|
this is not recommended, as Flamenco does not know when every machine has
|
||||||
</div>
|
received the files.</p>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="setup-step is-active">
|
<!-- TODO: @submit.prevent makes the button triggerable by pressing ENTER
|
||||||
<h2>Shared Storage</h2>
|
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">
|
||||||
|
<input v-model="sharedStoragePath" type="text">
|
||||||
|
<button type="submit">Check</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
<ul class="progress">
|
<p v-if="sharedStorageCheckResult != null"
|
||||||
<li><span></span></li>
|
:class="{ 'check-ok': sharedStorageCheckResult.is_usable, 'check-failed': !sharedStorageCheckResult.is_usable }">
|
||||||
<li class="active"><span></span></li>
|
{{ sharedStorageCheckResult.cause }}
|
||||||
<li><span></span></li>
|
</p>
|
||||||
<li><span></span></li>
|
</step-item>
|
||||||
</ul>
|
<step-item title="Blender">
|
||||||
|
<p>Choose which Blender to use below:</p>
|
||||||
|
|
||||||
<p>Flamenco needs some shared storage, to have a central place where the
|
<p v-if="isBlenderExeFinding">... finding Blenders ...</p>
|
||||||
Manager and Workers exchange files. This could be a NAS in your network,
|
<div v-for="blender in allBlenders" class="blender-selector"
|
||||||
or some other file sharing server.</p>
|
:class="{ 'selected-blender': (blender == selectedBlender) }">
|
||||||
|
<dl>
|
||||||
|
<dt>Version</dt>
|
||||||
|
<dd>{{ blender.cause }}</dd>
|
||||||
|
|
||||||
<p>Make sure this path is the same for all machines involved.</p>
|
<dt>Path</dt>
|
||||||
|
<dd>{{ blender.path }}</dd>
|
||||||
|
|
||||||
<p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for
|
<dt>Source</dt>
|
||||||
this is not recommended, as Flamenco does not know when every machine has
|
<dd>{{ sourceLabels[blender.source] }}</dd>
|
||||||
received the files.</p>
|
</dl>
|
||||||
|
<button @click="selectedBlender = blender" :disabled="selectedBlender == blender">Use this Blender</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- TODO: @submit.prevent makes the button triggerable by pressing ENTER
|
<p>Or provide an alternative command to try:</p>
|
||||||
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">
|
|
||||||
<input v-model="sharedStoragePath" type="text">
|
|
||||||
<button type="submit">Check</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p v-if="sharedStorageCheckResult != null"
|
<form @submit.prevent="checkBlenderExePath">
|
||||||
:class="{ 'check-ok': sharedStorageCheckResult.is_usable, 'check-failed': !sharedStorageCheckResult.is_usable }">
|
<input v-model="customBlenderExe" type="text">
|
||||||
{{ sharedStorageCheckResult.cause }}
|
<button type="submit">Check</button>
|
||||||
</p>
|
</form>
|
||||||
|
<p v-if="isBlenderExeChecking">... checking ...</p>
|
||||||
<div class="btn-bar btn-bar-wide">
|
<p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
|
||||||
<button class="btn">Back</button>
|
Found something, it is selected above.</p>
|
||||||
<button class="btn btn-primary" disabled>Next</button>
|
<p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
|
||||||
</div>
|
{{ blenderExeCheckResult.cause }}</p>
|
||||||
</section>
|
</step-item>
|
||||||
|
<step-item title="Review">
|
||||||
<section class="setup-step is-active">
|
<div v-if="isConfigComplete">
|
||||||
<h2>Which Blender?</h2>
|
<p>This is the configuration that will be used by Flamenco:</p>
|
||||||
|
<dl>
|
||||||
<ul class="progress">
|
<dt>Storage</dt>
|
||||||
<li><span></span></li>
|
<dd>{{ sharedStorageCheckResult.path }}</dd>
|
||||||
<li><span></span></li>
|
<dt>Blender</dt>
|
||||||
<li class="active"><span></span></li>
|
<dd v-if="selectedBlender.source == 'file_association'">
|
||||||
<li><span></span></li>
|
Whatever Blender is associated with .blend files
|
||||||
</ul>
|
(currently "<code>{{ selectedBlender.path }}</code>")
|
||||||
|
</dd>
|
||||||
<p>Choose which Blender to use below:</p>
|
<dd v-if="selectedBlender.source == 'path_envvar'">
|
||||||
|
The command "<code>{{ selectedBlender.input }}</code>" as found on <code>$PATH</code>
|
||||||
<p v-if="isBlenderExeFinding">... finding Blenders ...</p>
|
(currently "<code>{{ selectedBlender.path }}</code>")
|
||||||
<div v-for="blender in allBlenders" class="blender-selector"
|
</dd>
|
||||||
:class="{ 'selected-blender': (blender == selectedBlender) }">
|
<dd v-if="selectedBlender.source == 'input_path'">
|
||||||
<dl>
|
The command you provided:
|
||||||
<dt>Version</dt>
|
"<code>{{ selectedBlender.path }}</code>"
|
||||||
<dd>{{ blender.cause }}</dd>
|
</dd>
|
||||||
|
</dl>
|
||||||
<dt>Path</dt>
|
</div>
|
||||||
<dd>{{ blender.path }}</dd>
|
<p v-if="isConfirmed" class="check-ok">Configuration has been saved, Flamenco will restart.</p>
|
||||||
|
<button @click="confirmWizard" :disabled="isConfirming">Confirm</button>
|
||||||
<dt>Source</dt>
|
</step-item>
|
||||||
<dd>{{ sourceLabels[blender.source] }}</dd>
|
</steps-wrapper>
|
||||||
</dl>
|
|
||||||
<button @click="selectedBlender = blender" :disabled="selectedBlender == blender">Use this Blender</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>Or provide an alternative command to try:</p>
|
|
||||||
|
|
||||||
<form @submit.prevent="checkBlenderExePath">
|
|
||||||
<input v-model="customBlenderExe" type="text">
|
|
||||||
<button type="submit">Check</button>
|
|
||||||
</form>
|
|
||||||
<p v-if="isBlenderExeChecking">... checking ...</p>
|
|
||||||
<p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
|
|
||||||
Found something, it is selected above.</p>
|
|
||||||
<p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
|
|
||||||
{{ blenderExeCheckResult.cause }}</p>
|
|
||||||
|
|
||||||
<div class="btn-bar btn-bar-wide">
|
|
||||||
<button class="btn">Back</button>
|
|
||||||
<button class="btn btn-primary">Next</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="isConfigComplete" class="setup-step is-active">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<p v-if="isConfirmed" class="check-ok">Configuration has been saved, Flamenco will restart.</p>
|
|
||||||
<button @click="confirmWizard" :disabled="isConfirming">Confirm</button>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="app-footer">
|
<footer class="app-footer">
|
||||||
@ -138,6 +97,8 @@
|
|||||||
<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 StepItem from '@/components/steps/StepItem.vue';
|
||||||
|
import StepsWrapper from '@/components/steps/StepsWrapper.vue';
|
||||||
import { MetaApi, PathCheckInput, WizardConfig } from "@/manager-api";
|
import { MetaApi, PathCheckInput, WizardConfig } from "@/manager-api";
|
||||||
import { apiClient } from '@/stores/api-query-count';
|
import { apiClient } from '@/stores/api-query-count';
|
||||||
|
|
||||||
@ -146,6 +107,8 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
NotificationBar,
|
NotificationBar,
|
||||||
UpdateListener,
|
UpdateListener,
|
||||||
|
StepsWrapper,
|
||||||
|
StepItem,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
sharedStoragePath: "",
|
sharedStoragePath: "",
|
||||||
@ -291,12 +254,7 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
|
||||||
--wiz-progress-indicator-size: 6px;
|
|
||||||
--wiz-progress-indicator-border-width: 2px;
|
|
||||||
--wiz-progress-indicator-color: var(--color-text-hint);
|
|
||||||
--wiz-progress-indicator-color-active: var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.is-first-time-wizard #app {
|
body.is-first-time-wizard #app {
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
@ -322,68 +280,7 @@ body.is-first-time-wizard #app {
|
|||||||
--color-check-ok: var(--color-status-completed);
|
--color-check-ok: var(--color-status-completed);
|
||||||
|
|
||||||
max-width: 640px;
|
max-width: 640px;
|
||||||
margin: auto;
|
margin: 20vh auto auto;
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-step {
|
|
||||||
background-color: var(--color-background-column);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
display: none;
|
|
||||||
padding: var(--spacer) var(--spacer-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-step.is-active{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-intro {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
list-style: none;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
padding: 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Progress indicator dot. */
|
|
||||||
.progress li span {
|
|
||||||
background-color: var(--wiz-progress-indicator-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
border: var(--wiz-progress-indicator-border-width) solid var(--color-background-column);
|
|
||||||
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
height: var(--wiz-progress-indicator-size);
|
|
||||||
position: relative;
|
|
||||||
width: var(--wiz-progress-indicator-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress li.active span {
|
|
||||||
background-color: var(--color-accent);
|
|
||||||
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress li.active+li span,
|
|
||||||
.progress li.active+li+li span,
|
|
||||||
.progress li.active+li+li+li span,
|
|
||||||
.progress li.active+li+li+li+span {
|
|
||||||
background-color: var(--color-background-column);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Progress indicator line between dots. */
|
|
||||||
.progress:before {
|
|
||||||
background-color: var(--wiz-progress-indicator-color);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
height: var(--wiz-progress-indicator-border-width);
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user