浏览代码

Let a workshop remove an integration that never finished setting up (#308)

Bernt Christian Egeland 4 周之前
父节点
当前提交
437301ef57

+ 5 - 0
messages/de/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Trennen",
     "disconnectTitle": "{name} trennen?",
     "disconnectDescription": "Torqvoice vergisst das Konto und beendet die Synchronisierung. Bereits im Kalender erstellte Termine bleiben erhalten.",
+    "removeSetup": "Entfernen",
+    "removeSetupTitle": "{name} entfernen?",
+    "removeSetupDescription": "Es ist noch nichts verbunden. Torqvoice vergisst die Eingaben, und {name} erscheint wieder in der Liste der verfügbaren Dienste.",
+    "removeSetupDone": "{name} entfernt",
+    "removeSetupHint": "Doch nicht? Entfernen Sie die Einrichtung, und der Dienst kehrt in die Liste unten zurück.",
     "disconnected": "Getrennt",
     "test": "Verbindung testen",
     "testPassed": "Verbindung funktioniert",

+ 5 - 0
messages/en/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Disconnect",
     "disconnectTitle": "Disconnect {name}?",
     "disconnectDescription": "Torqvoice forgets the account and stops syncing. Events already created in the calendar stay there.",
+    "removeSetup": "Remove",
+    "removeSetupTitle": "Remove {name}?",
+    "removeSetupDescription": "Nothing is connected yet. Torqvoice forgets what was entered, and {name} goes back to the list of available services.",
+    "removeSetupDone": "{name} removed",
+    "removeSetupHint": "Not going ahead with this? Remove it and the service returns to the list below.",
     "disconnected": "Disconnected",
     "test": "Test connection",
     "testPassed": "Connection works",

+ 5 - 0
messages/es/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Desconectar",
     "disconnectTitle": "¿Desconectar {name}?",
     "disconnectDescription": "Torqvoice olvida la cuenta y deja de sincronizar. Los eventos ya creados en el calendario se mantienen.",
+    "removeSetup": "Quitar",
+    "removeSetupTitle": "¿Quitar {name}?",
+    "removeSetupDescription": "Todavía no hay nada conectado. Torqvoice olvida lo introducido y {name} vuelve a la lista de servicios disponibles.",
+    "removeSetupDone": "{name} quitado",
+    "removeSetupHint": "¿No vas a seguir con esto? Quítalo y el servicio vuelve a la lista de abajo.",
     "disconnected": "Desconectado",
     "test": "Probar conexión",
     "testPassed": "La conexión funciona",

+ 5 - 0
messages/fr/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Déconnecter",
     "disconnectTitle": "Déconnecter {name} ?",
     "disconnectDescription": "Torqvoice oublie le compte et arrête la synchronisation. Les événements déjà créés dans le calendrier y restent.",
+    "removeSetup": "Retirer",
+    "removeSetupTitle": "Retirer {name} ?",
+    "removeSetupDescription": "Rien n'est encore connecté. Torqvoice oublie ce qui a été saisi et {name} revient dans la liste des services disponibles.",
+    "removeSetupDone": "{name} retiré",
+    "removeSetupHint": "Vous n'allez pas plus loin ? Retirez-le et le service revient dans la liste ci-dessous.",
     "disconnected": "Déconnecté",
     "test": "Tester la connexion",
     "testPassed": "La connexion fonctionne",

+ 5 - 0
messages/it/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Scollega",
     "disconnectTitle": "Scollegare {name}?",
     "disconnectDescription": "Torqvoice dimentica l'account e interrompe la sincronizzazione. Gli eventi già creati nel calendario restano lì.",
+    "removeSetup": "Rimuovi",
+    "removeSetupTitle": "Rimuovere {name}?",
+    "removeSetupDescription": "Non c'è ancora nulla di collegato. Torqvoice dimentica quanto inserito e {name} torna nell'elenco dei servizi disponibili.",
+    "removeSetupDone": "{name} rimosso",
+    "removeSetupHint": "Non vuoi procedere? Rimuovilo e il servizio torna nell'elenco qui sotto.",
     "disconnected": "Scollegato",
     "test": "Prova la connessione",
     "testPassed": "La connessione funziona",

+ 5 - 0
messages/lt/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Atjungti",
     "disconnectTitle": "Atjungti {name}?",
     "disconnectDescription": "Torqvoice pamirš paskyrą ir nustos sinchronizuoti. Kalendoriuje jau sukurti įvykiai liks.",
+    "removeSetup": "Pašalinti",
+    "removeSetupTitle": "Pašalinti {name}?",
+    "removeSetupDescription": "Dar niekas neprijungta. Torqvoice pamiršta, kas buvo įvesta, o {name} grįžta į galimų paslaugų sąrašą.",
+    "removeSetupDone": "{name} pašalinta",
+    "removeSetupHint": "Nebetęsite? Pašalinkite, ir paslauga grįš į sąrašą žemiau.",
     "disconnected": "Atjungta",
     "test": "Tikrinti ryšį",
     "testPassed": "Ryšys veikia",

+ 5 - 0
messages/nb/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Koble fra",
     "disconnectTitle": "Koble fra {name}?",
     "disconnectDescription": "Torqvoice glemmer kontoen og slutter å synkronisere. Hendelser som allerede er opprettet i kalenderen, blir liggende der.",
+    "removeSetup": "Fjern",
+    "removeSetupTitle": "Fjerne {name}?",
+    "removeSetupDescription": "Ingenting er koblet til ennå. Torqvoice glemmer det som ble fylt inn, og {name} går tilbake til listen over tilgjengelige tjenester.",
+    "removeSetupDone": "{name} fjernet",
+    "removeSetupHint": "Skal du ikke gå videre med dette? Fjern det, så går tjenesten tilbake til listen nedenfor.",
     "disconnected": "Frakoblet",
     "test": "Test tilkoblingen",
     "testPassed": "Tilkoblingen fungerer",

+ 5 - 0
messages/nl/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Loskoppelen",
     "disconnectTitle": "{name} loskoppelen?",
     "disconnectDescription": "Torqvoice vergeet het account en stopt met synchroniseren. Afspraken die al in de agenda zijn aangemaakt, blijven daar staan.",
+    "removeSetup": "Verwijderen",
+    "removeSetupTitle": "{name} verwijderen?",
+    "removeSetupDescription": "Er is nog niets verbonden. Torqvoice vergeet wat is ingevuld en {name} gaat terug naar de lijst met beschikbare diensten.",
+    "removeSetupDone": "{name} verwijderd",
+    "removeSetupHint": "Gaat u hier niet mee door? Verwijder het en de dienst keert terug naar de lijst hieronder.",
     "disconnected": "Losgekoppeld",
     "test": "Verbinding testen",
     "testPassed": "Verbinding werkt",

+ 5 - 0
messages/pl/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Rozłącz",
     "disconnectTitle": "Rozłączyć {name}?",
     "disconnectDescription": "Torqvoice zapomni konto i przestanie synchronizować. Wydarzenia już utworzone w kalendarzu pozostaną.",
+    "removeSetup": "Usuń",
+    "removeSetupTitle": "Usunąć {name}?",
+    "removeSetupDescription": "Nic nie jest jeszcze połączone. Torqvoice zapomina wpisane dane, a {name} wraca na listę dostępnych usług.",
+    "removeSetupDone": "Usunięto {name}",
+    "removeSetupHint": "Nie zamierzasz tego kontynuować? Usuń, a usługa wróci na listę poniżej.",
     "disconnected": "Rozłączono",
     "test": "Testuj połączenie",
     "testPassed": "Połączenie działa",

+ 5 - 0
messages/pt-BR/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Desconectar",
     "disconnectTitle": "Desconectar {name}?",
     "disconnectDescription": "O Torqvoice esquece a conta e para de sincronizar. Os eventos já criados no calendário permanecem lá.",
+    "removeSetup": "Remover",
+    "removeSetupTitle": "Remover {name}?",
+    "removeSetupDescription": "Nada está conectado ainda. O Torqvoice esquece o que foi preenchido e {name} volta para a lista de serviços disponíveis.",
+    "removeSetupDone": "{name} removido",
+    "removeSetupHint": "Não vai seguir com isso? Remova e o serviço volta para a lista abaixo.",
     "disconnected": "Desconectado",
     "test": "Testar conexão",
     "testPassed": "A conexão funciona",

+ 5 - 0
messages/ru/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Отключить",
     "disconnectTitle": "Отключить {name}?",
     "disconnectDescription": "Torqvoice забудет аккаунт и прекратит синхронизацию. События, уже созданные в календаре, останутся на месте.",
+    "removeSetup": "Удалить",
+    "removeSetupTitle": "Удалить {name}?",
+    "removeSetupDescription": "Пока ничего не подключено. Torqvoice забудет введённые данные, и {name} вернётся в список доступных сервисов.",
+    "removeSetupDone": "{name} удалён",
+    "removeSetupHint": "Не будете продолжать? Удалите, и сервис вернётся в список ниже.",
     "disconnected": "Отключено",
     "test": "Проверить подключение",
     "testPassed": "Подключение работает",

+ 5 - 0
messages/tr/integrations.json

@@ -71,6 +71,11 @@
     "disconnect": "Bağlantıyı kes",
     "disconnectTitle": "{name} bağlantısı kesilsin mi?",
     "disconnectDescription": "Torqvoice hesabı unutur ve senkronizasyonu durdurur. Takvimde zaten oluşturulmuş etkinlikler orada kalır.",
+    "removeSetup": "Kaldır",
+    "removeSetupTitle": "{name} kaldırılsın mı?",
+    "removeSetupDescription": "Henüz hiçbir şey bağlı değil. Torqvoice girilenleri unutur ve {name} kullanılabilir hizmetler listesine geri döner.",
+    "removeSetupDone": "{name} kaldırıldı",
+    "removeSetupHint": "Devam etmeyecek misiniz? Kaldırın, hizmet aşağıdaki listeye geri döner.",
     "disconnected": "Bağlantı kesildi",
     "test": "Bağlantıyı test et",
     "testPassed": "Bağlantı çalışıyor",

+ 60 - 17
src/app/(authenticated)/settings/integrations/[connector]/connection-settings.tsx

@@ -16,6 +16,7 @@ import {
   Plug,
   RefreshCw,
   RotateCcw,
+  Trash2,
   Unplug,
   Upload,
 } from 'lucide-react'
@@ -137,6 +138,27 @@ export function ConnectionSettings({
     if (done) router.push('/settings/integrations')
   }
 
+  // A row that never got past setup, or was disconnected and kept its
+  // settings, still shows under "Connected" as in progress. Clearing the
+  // fields cannot get rid of it, because the required ones refuse to be
+  // empty; this can. The same action as disconnect, worded for a service
+  // that was never actually connected.
+  const removeSetup = async () => {
+    const ok = await confirm({
+      title: t('connection.removeSetupTitle', { name: manifest.name }),
+      description: t('connection.removeSetupDescription', { name: manifest.name }),
+      confirmLabel: t('connection.removeSetup'),
+      destructive: true,
+    })
+    if (!ok) return
+    const done = await run(
+      'disconnect',
+      () => disconnectIntegration(manifest.id),
+      t('connection.removeSetupDone', { name: manifest.name })
+    )
+    if (done) router.push('/settings/integrations')
+  }
+
   const firstSchedule = manifest.schedules?.[0]?.job
   const hasSync = Boolean(firstSchedule)
   const isCalendar = manifest.category === 'calendar'
@@ -260,23 +282,44 @@ export function ConnectionSettings({
             )}
           </div>
         ) : (
-          <ConnectForm
-            manifest={manifest}
-            tenantClientId={connection?.tenantClientId ?? null}
-            needsTenantApp={oauthNeedsTenantApp}
-            redirectUri={view.redirectUri}
-            oauthStartUrl={oauthStartUrl}
-            enabled={view.enabled}
-            busy={busy}
-            initialSettings={connection?.settings}
-            onSave={(values, settings) =>
-              run(
-                'credentials',
-                () => saveIntegrationCredentials(manifest.id, values, settings),
-                isOAuth ? undefined : t('connection.connectedShort')
-              )
-            }
-          />
+          <>
+            <ConnectForm
+              manifest={manifest}
+              tenantClientId={connection?.tenantClientId ?? null}
+              needsTenantApp={oauthNeedsTenantApp}
+              redirectUri={view.redirectUri}
+              oauthStartUrl={oauthStartUrl}
+              enabled={view.enabled}
+              busy={busy}
+              initialSettings={connection?.settings}
+              onSave={(values, settings) =>
+                run(
+                  'credentials',
+                  () => saveIntegrationCredentials(manifest.id, values, settings),
+                  isOAuth ? undefined : t('connection.connectedShort')
+                )
+              }
+            />
+            {connection && (
+              <div className="mt-4 flex flex-wrap items-center justify-between gap-2 border-t pt-3 text-sm">
+                <p className="text-muted-foreground">{t('connection.removeSetupHint')}</p>
+                <Button
+                  variant="outline"
+                  size="sm"
+                  className="text-destructive hover:text-destructive"
+                  onClick={removeSetup}
+                  disabled={busy !== null}
+                >
+                  {busy === 'disconnect' ? (
+                    <Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
+                  ) : (
+                    <Trash2 className="mr-1 h-3.5 w-3.5" />
+                  )}
+                  {t('connection.removeSetup')}
+                </Button>
+              </div>
+            )}
+          </>
         )}
 
         {connected && view.inbound && (