This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
createBrowserSessionProfile, startBrowserSessionLogin,
|
||||
@@ -16,6 +17,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export function AddBrowserSessionDialog({ existingProfile, onClose }: Props) {
|
||||
const { t } = useTranslation('userfolder');
|
||||
const qc = useQueryClient();
|
||||
const [phase, setPhase] = useState<Phase>('form');
|
||||
const [label, setLabel] = useState(existingProfile?.label ?? '');
|
||||
@@ -26,7 +28,7 @@ export function AddBrowserSessionDialog({ existingProfile, onClose }: Props) {
|
||||
const [sessionId, setSessionId] = useState<string | null>(null);
|
||||
const [novncPath, setNovncPath] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const pip = usePictureInPicture(novncPath, label ? `noVNC — ログイン: ${label}` : 'noVNC — ログイン');
|
||||
const pip = usePictureInPicture(novncPath, label ? t('browserSessions.dialog.novncTitle', { label }) : t('browserSessions.dialog.novncTitleNoLabel'));
|
||||
|
||||
async function startLogin() {
|
||||
setError(null);
|
||||
@@ -88,7 +90,7 @@ export function AddBrowserSessionDialog({ existingProfile, onClose }: Props) {
|
||||
<div className={`bg-surface rounded-lg shadow-xl ${dialogSize} overflow-hidden flex flex-col`}>
|
||||
<div className="px-4 py-3 border-b border-hairline flex items-center justify-between">
|
||||
<h3 className="text-sm font-semibold text-slate-800">
|
||||
{existingProfile ? `再ログイン: ${existingProfile.label}` : 'ブラウザセッションを追加'}
|
||||
{existingProfile ? t('browserSessions.dialog.reLoginTitle', { label: existingProfile.label }) : t('browserSessions.dialog.addTitle')}
|
||||
</h3>
|
||||
<button onClick={cancel} className="text-slate-400 hover:text-slate-700 text-lg leading-none">×</button>
|
||||
</div>
|
||||
@@ -96,36 +98,36 @@ export function AddBrowserSessionDialog({ existingProfile, onClose }: Props) {
|
||||
{phase === 'form' && (
|
||||
<div className="p-4 space-y-3">
|
||||
<div>
|
||||
<label className="block text-xs text-slate-700 mb-1">ラベル</label>
|
||||
<label className="block text-xs text-slate-700 mb-1">{t('browserSessions.dialog.label')}</label>
|
||||
<input value={label} onChange={e => setLabel(e.target.value)}
|
||||
disabled={!!existingProfile}
|
||||
placeholder="My Twitter"
|
||||
className="w-full h-8 px-2 text-xs border border-hairline rounded-md disabled:bg-slate-50 disabled:text-slate-500" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-700 mb-1">開始 URL</label>
|
||||
<label className="block text-xs text-slate-700 mb-1">{t('browserSessions.dialog.startUrl')}</label>
|
||||
<input value={startUrl} onChange={e => setStartUrl(e.target.value)}
|
||||
placeholder="https://twitter.com/home"
|
||||
className="w-full h-8 px-2 text-xs border border-hairline rounded-md" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-700 mb-1">ログイン済みセレクター(任意)</label>
|
||||
<label className="block text-xs text-slate-700 mb-1">{t('browserSessions.dialog.loggedInSelector')}</label>
|
||||
<input value={loggedInSelector} onChange={e => setLoggedInSelector(e.target.value)}
|
||||
placeholder='[data-testid="primaryColumn"]'
|
||||
className="w-full h-8 px-2 text-xs border border-hairline rounded-md" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-700 mb-1">ログイン URL パターン(任意)</label>
|
||||
<label className="block text-xs text-slate-700 mb-1">{t('browserSessions.dialog.loginUrlPattern')}</label>
|
||||
<input value={loginUrl} onChange={e => setLoginUrl(e.target.value)}
|
||||
placeholder="https://twitter.com/i/flow/login**"
|
||||
className="w-full h-8 px-2 text-xs border border-hairline rounded-md" />
|
||||
</div>
|
||||
{error && <div className="text-xs text-rose-600">{error}</div>}
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<button onClick={cancel} className="text-xs px-3 py-1.5 rounded-md hover:bg-surface">キャンセル</button>
|
||||
<button onClick={cancel} className="text-xs px-3 py-1.5 rounded-md hover:bg-surface">{t('browserSessions.dialog.cancel')}</button>
|
||||
<button disabled={!label || !startUrl} onClick={startLogin}
|
||||
className="text-xs px-3 py-1.5 rounded-md bg-accent text-accent-fg hover:bg-accent-deep disabled:bg-slate-300">
|
||||
ログインウィンドウを開く
|
||||
{t('browserSessions.dialog.openLoginWindow')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,29 +138,29 @@ export function AddBrowserSessionDialog({ existingProfile, onClose }: Props) {
|
||||
<div className="flex-1 min-h-[420px] bg-black">
|
||||
{pip.isOpen ? (
|
||||
<div className="w-full h-full flex items-center justify-center text-xs text-slate-300">
|
||||
PiP ウィンドウで表示中。閉じるとここに戻ります。
|
||||
{t('browserSessions.dialog.pipShown')}
|
||||
</div>
|
||||
) : (
|
||||
<iframe src={novncPath} title="login" className="w-full h-full" allow="clipboard-read; clipboard-write" />
|
||||
)}
|
||||
</div>
|
||||
<div className="px-4 py-3 border-t border-hairline flex items-center justify-between text-xs">
|
||||
<span className="text-slate-600">上のウィンドウでログインし、完了したら「保存」をクリックしてください。</span>
|
||||
<span className="text-slate-600">{t('browserSessions.dialog.loginPrompt')}</span>
|
||||
<div className="flex gap-2 items-center">
|
||||
<PipButton pip={pip} />
|
||||
<button onClick={cancel} className="px-3 py-1.5 rounded-md hover:bg-surface">キャンセル</button>
|
||||
<button onClick={saveNow} className="px-3 py-1.5 rounded-md bg-accent text-accent-fg hover:bg-accent-deep">保存</button>
|
||||
<button onClick={cancel} className="px-3 py-1.5 rounded-md hover:bg-surface">{t('browserSessions.dialog.cancel')}</button>
|
||||
<button onClick={saveNow} className="px-3 py-1.5 rounded-md bg-accent text-accent-fg hover:bg-accent-deep">{t('browserSessions.dialog.save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{phase === 'saving' && <div className="p-6 text-center text-xs text-slate-500">保存中…</div>}
|
||||
{phase === 'done' && <div className="p-6 text-center text-xs text-emerald-600">保存しました。</div>}
|
||||
{phase === 'saving' && <div className="p-6 text-center text-xs text-slate-500">{t('browserSessions.dialog.savingState')}</div>}
|
||||
{phase === 'done' && <div className="p-6 text-center text-xs text-emerald-600">{t('browserSessions.dialog.doneState')}</div>}
|
||||
{phase === 'error' && (
|
||||
<div className="p-6 space-y-3 text-center">
|
||||
<div className="text-xs text-rose-600">{error}</div>
|
||||
<button onClick={cancel} className="px-3 py-1.5 rounded-md hover:bg-surface text-xs">閉じる</button>
|
||||
<button onClick={cancel} className="px-3 py-1.5 rounded-md hover:bg-surface text-xs">{t('browserSessions.dialog.close')}</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user