fix(app): clarify storage workspace setup

- Show one centered setup action instead of simultaneous error and empty states

- Refresh configuration after closing Settings without requiring route remount

- Keep document creation and refresh unavailable until setup is complete
This commit is contained in:
Danila Poyarkov 2026-07-26 15:12:29 +03:00
parent c45e5e5cef
commit 050978029b
2 changed files with 32 additions and 10 deletions

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from '@open-pencil/vue'
@ -12,7 +12,7 @@ import {
type StorageDocument
} from '@/app/integrations/storage'
import { fadeOutGlobalLoader } from '@/app/editor/canvas/loader-overlay'
import { openSettingsDialog } from '@/app/settings/dialog'
import { openSettingsDialog, settingsDialogOpen } from '@/app/settings/dialog'
import type { CredentialStatus } from '@/app/settings/credentials/types'
import { createCanvasId } from '@/app/storage/id'
import { getLocalCanvasStore } from '@/app/storage/local-store'
@ -112,6 +112,10 @@ async function createDocument(): Promise<void> {
await store.saveFigFile()
}
watch(settingsDialogOpen, (open, wasOpen) => {
if (wasOpen && !open) void refresh()
})
onMounted(() => {
fadeOutGlobalLoader()
void refresh()
@ -148,9 +152,12 @@ onMounted(() => {
<section class="mx-auto max-w-6xl p-6">
<div class="mb-4 flex items-center justify-between">
<p v-if="loading" class="text-xs text-muted">{{ dialogs.loadingDocuments }}</p>
<p v-else-if="error" class="text-xs text-danger" role="alert">{{ error }}</p>
<p v-else-if="error && configured" class="text-xs text-danger" role="alert">
{{ error }}
</p>
<span v-else />
<button
v-if="configured"
type="button"
class="rounded px-2 py-1 text-xs text-muted hover:bg-hover hover:text-surface"
@click="refresh"
@ -181,9 +188,26 @@ onMounted(() => {
</button>
</div>
<div v-else-if="!loading" class="py-24 text-center text-xs text-muted">
<div v-else-if="!loading && configured" class="py-24 text-center text-xs text-muted">
{{ dialogs.emptyStorageWorkspace }}
</div>
<div
v-else-if="!loading"
class="mx-auto flex max-w-sm flex-col items-center py-24 text-center"
>
<div class="mb-3 flex size-10 items-center justify-center rounded-full bg-panel-field">
<icon-lucide-cloud class="size-5 text-muted" />
</div>
<p class="text-xs text-surface">{{ dialogs.storageNotConfigured }}</p>
<button
type="button"
class="mt-4 rounded bg-accent px-3 py-1.5 text-xs font-medium text-white hover:bg-accent/90"
@click="openSettingsDialog('storage')"
>
{{ dialogs.settings }}
</button>
</div>
</section>
</main>
</template>

View file

@ -36,11 +36,9 @@ test('configured storage lists and opens a remote document', async ({ page }) =>
await route.fulfill({ status: 404 })
})
await page.goto('/?test')
await page.goto('/storage?test')
const canvas = new CanvasHelper(page)
await canvas.waitForInit()
await page.getByTestId('app-settings-trigger').click()
await page.getByTestId('settings-section-storage').click()
await page.getByRole('button', { name: 'Settings' }).last().click()
await page.getByLabel('Endpoint').fill('https://s3.example.com')
await page.getByLabel('Bucket').fill('designs')
@ -67,9 +65,9 @@ test('storage workspace directs unconfigured users to Settings', async ({ page }
await page.goto('/storage?test')
await expect(page.getByTestId('storage-workspace')).toBeVisible()
await expect(page.getByRole('alert')).toContainText('Configure storage')
await expect(page.getByText('Configure storage before using this workspace.')).toBeVisible()
await expect(page.getByTestId('storage-new-document')).toBeDisabled()
await page.getByRole('button', { name: 'Settings' }).click()
await page.getByRole('button', { name: 'Settings' }).last().click()
await expect(page.getByTestId('settings-storage-panel')).toBeVisible()
})