feat(automations): mobile-safe builder with desktop notice
The node builder is gated to lg+ (its fixed side panels no longer overflow a phone); below lg it shows a 'works best on a larger screen' notice. Automation tabs scroll instead of cutting off.
This commit is contained in:
parent
49282d2acb
commit
5118640a9c
18 changed files with 63 additions and 4 deletions
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'يعمل محرر الأتمتة بشكل أفضل على شاشة أكبر. افتحه على جهاز كمبيوتر مكتبي لإنشاء سير عملك.',
|
||||
'title' => 'الأتمتة',
|
||||
'default_name' => 'أتمتة جديدة',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'Der Automatisierungs-Editor funktioniert am besten auf einem größeren Bildschirm. Öffne ihn auf einem Desktop, um deinen Workflow zu erstellen.',
|
||||
'title' => 'Automatisierungen',
|
||||
'default_name' => 'Neue Automatisierung',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'Ο επεξεργαστής αυτοματισμών λειτουργεί καλύτερα σε μεγαλύτερη οθόνη. Άνοιξέ τον σε υπολογιστή για να δημιουργήσεις τη ροή εργασίας σου.',
|
||||
'title' => 'Αυτοματισμοί',
|
||||
'default_name' => 'Νέος αυτοματισμός',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'The automation editor works best on a larger screen. Open it on a desktop to build your workflow.',
|
||||
'title' => 'Automations',
|
||||
'default_name' => 'New automation',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'El editor de automatizaciones funciona mejor en una pantalla más grande. Ábrelo en un ordenador para crear tu flujo de trabajo.',
|
||||
'title' => 'Automatizaciones',
|
||||
'default_name' => 'Nueva automatización',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'L\'éditeur d\'automatisation fonctionne mieux sur un grand écran. Ouvrez-le sur un ordinateur pour créer votre workflow.',
|
||||
'title' => 'Automatisations',
|
||||
'default_name' => 'Nouvelle automatisation',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'L\'editor delle automazioni funziona meglio su uno schermo più grande. Aprilo su un desktop per creare il tuo flusso di lavoro.',
|
||||
'title' => 'Automazioni',
|
||||
'default_name' => 'Nuova automazione',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'オートメーションエディタは大きな画面での利用に最適です。ワークフローを作成するにはデスクトップで開いてください。',
|
||||
'title' => 'オートメーション',
|
||||
'default_name' => '新しいオートメーション',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => '자동화 편집기는 큰 화면에서 가장 잘 작동합니다. 워크플로를 만들려면 데스크톱에서 열어주세요.',
|
||||
'title' => '자동화',
|
||||
'default_name' => '새 자동화',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'De automatiserings-editor werkt het best op een groter scherm. Open het op een desktop om je workflow te bouwen.',
|
||||
'title' => 'Automatiseringen',
|
||||
'default_name' => 'Nieuwe automatisering',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'Edytor automatyzacji działa najlepiej na większym ekranie. Otwórz go na komputerze, aby zbudować swój workflow.',
|
||||
'title' => 'Automatyzacje',
|
||||
'default_name' => 'Nowa automatyzacja',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'O editor de automações funciona melhor em uma tela maior. Abra no desktop para montar seu fluxo de trabalho.',
|
||||
'title' => 'Automações',
|
||||
'default_name' => 'Nova automação',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'Редактор автоматизаций лучше всего работает на большом экране. Откройте его на компьютере, чтобы создать рабочий процесс.',
|
||||
'title' => 'Автоматизации',
|
||||
'default_name' => 'Новая автоматизация',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => 'Otomasyon düzenleyicisi daha büyük bir ekranda en iyi şekilde çalışır. İş akışınızı oluşturmak için masaüstünde açın.',
|
||||
'title' => 'Otomasyonlar',
|
||||
'default_name' => 'Yeni otomasyon',
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'mobile_notice' => '自动化编辑器在更大的屏幕上体验最佳。请在电脑上打开以搭建你的工作流。',
|
||||
'title' => '自动化',
|
||||
'default_name' => '新建自动化',
|
||||
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ const tabs = computed(() => [
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="flex items-center gap-6 border-b-2 border-foreground/10 px-4">
|
||||
<nav class="flex items-center gap-4 overflow-x-auto border-b-2 border-foreground/10 px-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
||||
<Link
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
:href="tab.href"
|
||||
:dusk="`automation-tab-${tab.key}`"
|
||||
class="-mb-0.5 border-b-2 py-2.5 text-sm font-medium transition-colors"
|
||||
class="-mb-0.5 shrink-0 whitespace-nowrap border-b-2 py-2.5 text-sm font-medium transition-colors"
|
||||
:class="
|
||||
tab.key === current
|
||||
? 'border-primary text-foreground'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, router } from '@inertiajs/vue3';
|
||||
import { IconBolt, IconLifebuoy } from '@tabler/icons-vue';
|
||||
import { IconBolt, IconDeviceDesktop, IconLifebuoy } from '@tabler/icons-vue';
|
||||
import { Background } from '@vue-flow/background';
|
||||
import { Controls } from '@vue-flow/controls';
|
||||
import {
|
||||
|
|
@ -475,7 +475,7 @@ const defaultEdgeOptions = {
|
|||
</template>
|
||||
</AutomationHeader>
|
||||
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<div class="hidden flex-1 overflow-hidden lg:flex">
|
||||
<main
|
||||
class="automations-canvas-host relative flex-1"
|
||||
@drop="onDrop"
|
||||
|
|
@ -547,6 +547,16 @@ const defaultEdgeOptions = {
|
|||
/>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-testid="automation-mobile-notice"
|
||||
class="flex flex-1 flex-col items-center justify-center gap-3 p-8 text-center lg:hidden"
|
||||
>
|
||||
<div class="inline-flex size-14 items-center justify-center rounded-2xl border-2 border-foreground bg-violet-200 shadow-2xs">
|
||||
<IconDeviceDesktop class="size-7 text-foreground" stroke-width="2" />
|
||||
</div>
|
||||
<p class="max-w-sm text-sm text-foreground/70">{{ $t('automations.mobile_notice') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
|
|
|||
34
tests/Browser/MobileAutomationsTest.php
Normal file
34
tests/Browser/MobileAutomationsTest.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Enums\UserWorkspace\Role;
|
||||
use App\Models\Automation;
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
|
||||
test('the automation builder shows a desktop-recommended notice on a phone', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = Workspace::factory()->create(['user_id' => $user->id]);
|
||||
$workspace->members()->attach($user->id, ['role' => Role::Member->value]);
|
||||
$user->update(['current_workspace_id' => $workspace->id]);
|
||||
|
||||
$automation = Automation::factory()->create(['workspace_id' => $workspace->id]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$page = visit(route('app.automations.workflow', $automation))->resize(375, 812);
|
||||
|
||||
$page->script(<<<'JS'
|
||||
(async () => {
|
||||
const sel = '[data-testid="automation-mobile-notice"]';
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const el = document.querySelector(sel);
|
||||
if (el && el.getBoundingClientRect().height > 0) return;
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
}
|
||||
})();
|
||||
JS);
|
||||
|
||||
$page->assertVisible('@automation-mobile-notice');
|
||||
});
|
||||
Loading…
Reference in a new issue