feat(client): set dynamic page title based on content
- add usePageTitle hook that writes '<title> | Liqa' to document.title - list pages use section name; detail pages use entity name once loaded - create/edit pages use static action title, edit includes entity name
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
const APP_NAME = 'Liqa';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets document.title to "<title> | Liqa" for the current page.
|
||||||
|
* Pass undefined or empty string to fall back to just "Liqa".
|
||||||
|
*/
|
||||||
|
export function usePageTitle(title: string | null | undefined): void {
|
||||||
|
useEffect(() => {
|
||||||
|
const prev = document.title;
|
||||||
|
document.title = title ? `${title} | ${APP_NAME}` : APP_NAME;
|
||||||
|
return () => {
|
||||||
|
document.title = prev;
|
||||||
|
};
|
||||||
|
}, [title]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, SubmitEvent } from 'react';
|
import { useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { KeyRound, X, Save } from 'lucide-react';
|
import { KeyRound, X, Save } from 'lucide-react';
|
||||||
import { credentials } from '../../api';
|
import { credentials } from '../../api';
|
||||||
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
||||||
@@ -8,6 +9,7 @@ import styles from '../Page.module.css';
|
|||||||
|
|
||||||
export function CreateCredentialPage() {
|
export function CreateCredentialPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('credentials.create_title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Upload, Pencil, Trash2, KeyRound } from 'lucide-react';
|
import { Upload, Pencil, Trash2, KeyRound } from 'lucide-react';
|
||||||
import { CodeBlock } from '../../ui';
|
import { CodeBlock } from '../../ui';
|
||||||
import { stringify as yamlStringify } from 'yaml';
|
import { stringify as yamlStringify } from 'yaml';
|
||||||
@@ -16,6 +17,7 @@ export function CredentialDetailPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [credential, setCredential] = useState<Credential | null>(null);
|
const [credential, setCredential] = useState<Credential | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(credential?.name ?? null);
|
||||||
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Settings, Pencil, Trash2, Plus, Download, KeyRound } from 'lucide-react';
|
import { Settings, Pencil, Trash2, Plus, Download, KeyRound } from 'lucide-react';
|
||||||
import { parse as yamlParse } from 'yaml';
|
import { parse as yamlParse } from 'yaml';
|
||||||
import { credentials } from '../../api';
|
import { credentials } from '../../api';
|
||||||
@@ -100,6 +101,7 @@ function AddCredentialCard() {
|
|||||||
|
|
||||||
export function CredentialsPage() {
|
export function CredentialsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('credentials.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [items, setItems] = useState<Credential[]>([]);
|
const [items, setItems] = useState<Credential[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { KeyRound, X, Save } from 'lucide-react';
|
import { KeyRound, X, Save } from 'lucide-react';
|
||||||
import { credentials } from '../../api';
|
import { credentials } from '../../api';
|
||||||
import type { Credential } from '../../api';
|
import type { Credential } from '../../api';
|
||||||
@@ -15,6 +16,7 @@ export function EditCredentialPage() {
|
|||||||
|
|
||||||
const [credential, setCredential] = useState<Credential | null>(null);
|
const [credential, setCredential] = useState<Credential | null>(null);
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
|
usePageTitle(credential ? `${t('credentials.edit_title')} — ${credential.name}` : t('credentials.edit_title'));
|
||||||
const [data, setData] = useState('');
|
const [data, setData] = useState('');
|
||||||
const [nameError, setNameError] = useState('');
|
const [nameError, setNameError] = useState('');
|
||||||
const [dataError, setDataError] = useState('');
|
const [dataError, setDataError] = useState('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, SubmitEvent } from 'react';
|
import { useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Globe, Save } from 'lucide-react';
|
import { X, Globe, Save } from 'lucide-react';
|
||||||
import { environments } from '../../api';
|
import { environments } from '../../api';
|
||||||
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
||||||
@@ -8,6 +9,7 @@ import styles from '../Page.module.css';
|
|||||||
|
|
||||||
export function CreateEnvironmentPage() {
|
export function CreateEnvironmentPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('environments.create_title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Globe, Save } from 'lucide-react';
|
import { X, Globe, Save } from 'lucide-react';
|
||||||
import { environments } from '../../api';
|
import { environments } from '../../api';
|
||||||
import type { Environment } from '../../api';
|
import type { Environment } from '../../api';
|
||||||
@@ -15,6 +16,7 @@ export function EditEnvironmentPage() {
|
|||||||
|
|
||||||
const [env, setEnv] = useState<Environment | null>(null);
|
const [env, setEnv] = useState<Environment | null>(null);
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
|
usePageTitle(env ? `${t('environments.edit_title')} — ${env.name}` : t('environments.edit_title'));
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [dataJson, setDataJson] = useState('{}');
|
const [dataJson, setDataJson] = useState('{}');
|
||||||
const [nameError, setNameError] = useState('');
|
const [nameError, setNameError] = useState('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Globe, Pencil, Trash2, Upload } from 'lucide-react';
|
import { Globe, Pencil, Trash2, Upload } from 'lucide-react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { stringify as yamlStringify } from 'yaml';
|
import { stringify as yamlStringify } from 'yaml';
|
||||||
import type { Environment } from '../../api';
|
import type { Environment } from '../../api';
|
||||||
@@ -25,6 +26,7 @@ export function EnvironmentDetailPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [env, setEnv] = useState<Environment | null>(null);
|
const [env, setEnv] = useState<Environment | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(env?.name ?? null);
|
||||||
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
const dataEntries = Object.entries(env?.data ?? {}).filter(([, v]) => v);
|
const dataEntries = Object.entries(env?.data ?? {}).filter(([, v]) => v);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Settings, ExternalLink, Pencil, Trash2, Plus, Globe, Download } from 'lucide-react';
|
import { Settings, ExternalLink, Pencil, Trash2, Plus, Globe, Download } from 'lucide-react';
|
||||||
import { parse as yamlParse } from 'yaml';
|
import { parse as yamlParse } from 'yaml';
|
||||||
import { stringify as yamlStringify } from 'yaml';
|
import { stringify as yamlStringify } from 'yaml';
|
||||||
@@ -117,6 +118,7 @@ function AddEnvironmentCard() {
|
|||||||
|
|
||||||
export function EnvironmentsPage() {
|
export function EnvironmentsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('environments.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [items, setItems] = useState<Environment[]>([]);
|
const [items, setItems] = useState<Environment[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Activity } from 'lucide-react';
|
import { Activity } from 'lucide-react';
|
||||||
import { runs } from '../../api';
|
import { runs } from '../../api';
|
||||||
import type { ScenarioRun, ScenarioRunStatus } from '../../api';
|
import type { ScenarioRun, ScenarioRunStatus } from '../../api';
|
||||||
@@ -38,6 +39,7 @@ type AllRunRow = ScenarioRun & {
|
|||||||
|
|
||||||
export function AllRunsPage() {
|
export function AllRunsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('runs.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [sortBy, setSortBy] = useState('createdAt');
|
const [sortBy, setSortBy] = useState('createdAt');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate, useParams, Link } from 'react-router-dom';
|
import { useNavigate, useParams, Link } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { runs } from '../../api';
|
import { runs } from '../../api';
|
||||||
import type {
|
import type {
|
||||||
Scenario,
|
Scenario,
|
||||||
@@ -69,6 +70,7 @@ export function RunDetailPage() {
|
|||||||
const [scenario, setScenario] = useState<Scenario | null>(null);
|
const [scenario, setScenario] = useState<Scenario | null>(null);
|
||||||
const [run, setRun] = useState<ScenarioRunDetail | null>(null);
|
const [run, setRun] = useState<ScenarioRunDetail | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(scenario ? `${t('runs.title')} — ${scenario.name}` : t('runs.title'));
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [polling, setPolling] = useState(false);
|
const [polling, setPolling] = useState(false);
|
||||||
const [pulseKey, setPulseKey] = useState(0);
|
const [pulseKey, setPulseKey] = useState(0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Play, ClipboardList, Activity } from 'lucide-react';
|
import { Play, ClipboardList, Activity } from 'lucide-react';
|
||||||
import { environments, scenarios, runs } from '../../api';
|
import { environments, scenarios, runs } from '../../api';
|
||||||
import type {
|
import type {
|
||||||
@@ -50,6 +51,7 @@ export function RunsPage() {
|
|||||||
|
|
||||||
const [scenario, setScenario] = useState<Scenario | null>(null);
|
const [scenario, setScenario] = useState<Scenario | null>(null);
|
||||||
const [items, setItems] = useState<RunRow[]>([]);
|
const [items, setItems] = useState<RunRow[]>([]);
|
||||||
|
usePageTitle(scenario ? `${t('runs.title')} — ${scenario.name}` : t('runs.title'));
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [pulseKey, setPulseKey] = useState(0);
|
const [pulseKey, setPulseKey] = useState(0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, ClipboardList } from 'lucide-react';
|
import { X, Save, ClipboardList } from 'lucide-react';
|
||||||
import { scenarios, environments } from '../../api';
|
import { scenarios, environments } from '../../api';
|
||||||
import type { Environment } from '../../api';
|
import type { Environment } from '../../api';
|
||||||
@@ -9,6 +10,7 @@ import styles from '../Page.module.css';
|
|||||||
|
|
||||||
export function CreateScenarioPage() {
|
export function CreateScenarioPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('scenarios.create_title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, ClipboardList } from 'lucide-react';
|
import { X, Save, ClipboardList } from 'lucide-react';
|
||||||
import { scenarios, steps } from '../../api';
|
import { scenarios, steps } from '../../api';
|
||||||
import type { Scenario } from '../../api';
|
import type { Scenario } from '../../api';
|
||||||
@@ -14,6 +15,7 @@ export function CreateStepPage() {
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const [scenario, setScenario] = useState<Scenario | null>(null);
|
const [scenario, setScenario] = useState<Scenario | null>(null);
|
||||||
|
usePageTitle(t('steps.create_title'));
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [execCode, setExecCode] = useState('');
|
const [execCode, setExecCode] = useState('');
|
||||||
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, ClipboardList } from 'lucide-react';
|
import { X, Save, ClipboardList } from 'lucide-react';
|
||||||
import { scenarios, environments } from '../../api';
|
import { scenarios, environments } from '../../api';
|
||||||
import type { Scenario, Environment } from '../../api';
|
import type { Scenario, Environment } from '../../api';
|
||||||
@@ -15,6 +16,7 @@ export function EditScenarioPage() {
|
|||||||
|
|
||||||
const [scenario, setScenario] = useState<Scenario | null>(null);
|
const [scenario, setScenario] = useState<Scenario | null>(null);
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
|
usePageTitle(scenario ? `${t('scenarios.edit_title')} — ${scenario.name}` : t('scenarios.edit_title'));
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [environmentId, setEnvironmentId] = useState<string>('');
|
const [environmentId, setEnvironmentId] = useState<string>('');
|
||||||
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, ClipboardList } from 'lucide-react';
|
import { X, Save, ClipboardList } from 'lucide-react';
|
||||||
import { scenarios, steps } from '../../api';
|
import { scenarios, steps } from '../../api';
|
||||||
import type { Scenario, ScenarioStep } from '../../api';
|
import type { Scenario, ScenarioStep } from '../../api';
|
||||||
@@ -15,6 +16,7 @@ export function EditStepPage() {
|
|||||||
|
|
||||||
const [scenario, setScenario] = useState<Scenario | null>(null);
|
const [scenario, setScenario] = useState<Scenario | null>(null);
|
||||||
const [step, setStep] = useState<ScenarioStep | null>(null);
|
const [step, setStep] = useState<ScenarioStep | null>(null);
|
||||||
|
usePageTitle(step ? t('steps.edit_title', { order: step.order }) : t('steps.edit_title', { order: '' }));
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [execCode, setExecCode] = useState('');
|
const [execCode, setExecCode] = useState('');
|
||||||
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
const [timeoutSeconds, setTimeoutSeconds] = useState<string>('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState, SubmitEvent } from 'react';
|
import { useEffect, useRef, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import {
|
import {
|
||||||
Play,
|
Play,
|
||||||
Pencil,
|
Pencil,
|
||||||
@@ -51,6 +52,7 @@ export function ScenarioDetailPage() {
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [scenario, setScenario] = useState<(Scenario & { steps: ScenarioStep[] }) | null>(null);
|
const [scenario, setScenario] = useState<(Scenario & { steps: ScenarioStep[] }) | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(scenario?.name ?? null);
|
||||||
|
|
||||||
// Credentials state
|
// Credentials state
|
||||||
const [scenarioCreds, setScenarioCreds] = useState<ScenarioCredential[]>([]);
|
const [scenarioCreds, setScenarioCreds] = useState<ScenarioCredential[]>([]);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Play, Plus, Trash2, Download, ClipboardList } from 'lucide-react';
|
import { Play, Plus, Trash2, Download, ClipboardList } from 'lucide-react';
|
||||||
import { parse as yamlParse } from 'yaml';
|
import { parse as yamlParse } from 'yaml';
|
||||||
import { environments, scenarios } from '../../api';
|
import { environments, scenarios } from '../../api';
|
||||||
@@ -38,6 +39,7 @@ const LAST_RUN_LABEL: Record<ScenarioRunStatus, string> = {
|
|||||||
|
|
||||||
export function ScenariosPage() {
|
export function ScenariosPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('scenarios.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [items, setItems] = useState<Scenario[]>([]);
|
const [items, setItems] = useState<Scenario[]>([]);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Trash2, Monitor } from 'lucide-react';
|
import { Trash2, Monitor } from 'lucide-react';
|
||||||
import { sessions } from '../../api';
|
import { sessions } from '../../api';
|
||||||
import type { Session } from '../../api';
|
import type { Session } from '../../api';
|
||||||
@@ -14,6 +15,7 @@ export function SessionDetailPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [session, setSession] = useState<Session | null>(null);
|
const [session, setSession] = useState<Session | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(session?.sessionName ?? null);
|
||||||
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Trash2, Monitor } from 'lucide-react';
|
import { Trash2, Monitor } from 'lucide-react';
|
||||||
import { sessions } from '../../api';
|
import { sessions } from '../../api';
|
||||||
import type { Session } from '../../api';
|
import type { Session } from '../../api';
|
||||||
@@ -19,6 +20,7 @@ import styles from '../Page.module.css';
|
|||||||
|
|
||||||
export function SessionsPage() {
|
export function SessionsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('sessions.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [items, setItems] = useState<Session[]>([]);
|
const [items, setItems] = useState<Session[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, SubmitEvent } from 'react';
|
import { useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, Braces } from 'lucide-react';
|
import { X, Save, Braces } from 'lucide-react';
|
||||||
import { snippets } from '../../api';
|
import { snippets } from '../../api';
|
||||||
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
import { Breadcrumbs, Button, Card, Input, CodeEditor, useToast } from '../../ui';
|
||||||
@@ -8,6 +9,7 @@ import styles from '../Page.module.css';
|
|||||||
|
|
||||||
export function CreateSnippetPage() {
|
export function CreateSnippetPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('snippets.create_title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState, SubmitEvent } from 'react';
|
import { useEffect, useState, SubmitEvent } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { X, Save, Braces } from 'lucide-react';
|
import { X, Save, Braces } from 'lucide-react';
|
||||||
import { snippets } from '../../api';
|
import { snippets } from '../../api';
|
||||||
import type { Snippet } from '../../api';
|
import type { Snippet } from '../../api';
|
||||||
@@ -15,6 +16,7 @@ export function EditSnippetPage() {
|
|||||||
|
|
||||||
const [snippet, setSnippet] = useState<Snippet | null>(null);
|
const [snippet, setSnippet] = useState<Snippet | null>(null);
|
||||||
const [alias, setAlias] = useState('');
|
const [alias, setAlias] = useState('');
|
||||||
|
usePageTitle(snippet ? `${t('snippets.edit_title')} — ${snippet.title}` : t('snippets.edit_title'));
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [code, setCode] = useState('');
|
const [code, setCode] = useState('');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Upload, Pencil, Trash2, Braces } from 'lucide-react';
|
import { Upload, Pencil, Trash2, Braces } from 'lucide-react';
|
||||||
import { CodeBlock } from '../../ui';
|
import { CodeBlock } from '../../ui';
|
||||||
import { stringify as yamlStringify } from 'yaml';
|
import { stringify as yamlStringify } from 'yaml';
|
||||||
@@ -24,6 +25,7 @@ export function SnippetDetailPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [snippet, setSnippet] = useState<Snippet | null>(null);
|
const [snippet, setSnippet] = useState<Snippet | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
usePageTitle(snippet?.title ?? null);
|
||||||
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { usePageTitle } from '../../hooks/usePageTitle';
|
||||||
import { Settings, Pencil, Trash2, Plus, Download, Braces } from 'lucide-react';
|
import { Settings, Pencil, Trash2, Plus, Download, Braces } from 'lucide-react';
|
||||||
import { parse as yamlParse } from 'yaml';
|
import { parse as yamlParse } from 'yaml';
|
||||||
import { snippets } from '../../api';
|
import { snippets } from '../../api';
|
||||||
@@ -114,6 +115,7 @@ function AddSnippetCard() {
|
|||||||
|
|
||||||
export function SnippetsPage() {
|
export function SnippetsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
usePageTitle(t('snippets.title'));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [items, setItems] = useState<Snippet[]>([]);
|
const [items, setItems] = useState<Snippet[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user