# IntegrationConnector

> Connections page for OAuth services such as Google Analytics, Search Console, YouTube, GitHub and Slack, with cards, a scope consent dialog, account or property picker, status, reconnect and confirmed disconnect.

Source: https://docs.nasaqui.com/components/integration-connector

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/integration-connector.json
```

Cards for the services an account can connect: what each one gives access to, who authorised it, which
property or channel it uses, and its health. Connecting first shows the scopes to consent to; disconnecting
asks to confirm. It has no backend: your callbacks start the OAuth flow.

## When to use

- A Connections or Integrations page for data and tool services.

## When not to use

- Sign-in providers (Google, GitHub as a way to log in): use [`ConnectedAccounts`](https://docs.nasaqui.com/components/connected-accounts).
- A single "Continue with" button: [`OAuthButtons`](https://docs.nasaqui.com/components/oauth-buttons).

## Import

```tsx
import { IntegrationConnector } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"
```

## Quick start

```tsx
import { IntegrationConnector, type IntegrationService } from "@fadymondy/nasaq/web";

declare const services: IntegrationService[];
declare const api: { connect(id: string, scopes: string[]): Promise<void>; disconnect(id: string): Promise<void> };

export function Connections() {
  return <IntegrationConnector services={services} onConnect={(id, scopes) => api.connect(id, scopes)} onDisconnect={(id) => api.disconnect(id)} />;
}
```

## Anatomy

```
IntegrationConnector            data-slot="integration-connector" (Card, or bare)
├─ group heading                "Google", "Developer tools"
└─ service card                 data-slot="integration-card" (data-status)
   ├─ logo or name, description, Status
   ├─ connected as, last sync, granted scopes
   ├─ account Select            when connected and `accounts` is given
   ├─ message                   for "error" and "needs-reauth"
   └─ Connect / Reconnect / Disconnect (ConfirmButton)
Consent Dialog                  scope checkboxes (required ones locked), Continue
```

## API

**IntegrationConnector**: every `div` prop except `children`, plus:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `services` | `readonly IntegrationService[]` | required | See below. |
| `onConnect` | `(id, scopeIds) => Promise<void \| { error? }>` | required | Start OAuth for the ticked scopes. |
| `onDisconnect` | `(id) => Promise<void \| { error? }>` | required | Revoke the link. |
| `onSelectAccount` | `(id, accountId) => Promise<void \| { error? }>` | | Shows the picker. |
| `bare` | `boolean` | `false` | Drop the card header when the page has its own. |
| `labels` | `Partial<IntegrationConnectorLabels>` | | Override any string. |

**IntegrationService**: `id`, `name`, `description?`, `icon?`, `group?`, `scopes`, `status`
(`disconnected | connected | needs-reauth | error | pending`), `grantedScopes?`, `connectedAs?`, `accounts?`, `accountId?`,
`lastSyncAt?`, `message?`, `learnMoreHref?`.

## Examples

**A property picker**

```tsx
import { IntegrationConnector } from "@fadymondy/nasaq/web";

export const Picker = () => (
  <IntegrationConnector
    services={[
      {
        id: "ga",
        name: "Google Analytics",
        status: "connected",
        scopes: [{ id: "read", label: "Read reports", required: true }],
        accounts: [{ id: "1", name: "Blog", detail: "GA4 412000111" }],
        accountId: "1",
      },
    ]}
    onConnect={async () => undefined}
    onDisconnect={async () => undefined}
    onSelectAccount={async () => undefined}
  />
);
```

## Accessibility

- Cards are labelled sections; status is text as well as colour. Dialogs trap focus and return it.
- Required scopes are checked and disabled with a visible reason. Errors are `role="alert"`.

## RTL & i18n

- English and Arabic strings follow the Nasaq locale. Emails, usernames and property IDs are `dir="ltr"`.

## Styling & tokens

- Built on `Card`, `Status`, `Dialog`, `AlertDialog`, `Select` and `--nq-*` tokens.
- Target `[data-slot="integration-card"][data-status="needs-reauth"]`.

## Do / Don't

- Do ask only for the scopes you use and explain each in plain words.
- Do show a logo only when it is the brand's official one. Without it the name is shown as text.
- Don't invent or redraw a brand mark.

## Related

- [`ConnectedAccounts`](https://docs.nasaqui.com/components/connected-accounts)
- [`OAuthButtons`](https://docs.nasaqui.com/components/oauth-buttons)

## Lab

https://docs.nasaqui.com/?path=/docs/components-integrations-integration-connector--docs

## Code

### React

```tsx
import { IntegrationConnector, type IntegrationService } from "@fadymondy/nasaq/web";

declare const services: IntegrationService[];
declare const api: { connect(id: string, scopes: string[]): Promise<void>; disconnect(id: string): Promise<void> };

export function Connections() {
  return <IntegrationConnector services={services} onConnect={(id, scopes) => api.connect(id, scopes)} onDisconnect={(id) => api.disconnect(id)} />;
}
```

### shadcn

```tsx
import { IntegrationConnector, type IntegrationService } from "@/components/ui/integration-connector";

declare const services: IntegrationService[];
declare const api: { connect(id: string, scopes: string[]): Promise<void>; disconnect(id: string): Promise<void> };

export function Connections() {
  return <IntegrationConnector services={services} onConnect={(id, scopes) => api.connect(id, scopes)} onDisconnect={(id) => api.disconnect(id)} />;
}
```

### Vue

```vue
<script setup lang="ts">
import { NqIntegrationConnector, type IntegrationService } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const services = ref<IntegrationService[]>([
  {
    id: "search-console",
    name: "Search Console",
    group: "Google",
    status: "disconnected",
    scopes: [
      { id: "read", label: "Read your Search Console performance data", required: true },
      { id: "sitemaps", label: "Submit sitemaps" },
    ],
  },
  {
    id: "github",
    name: "GitHub",
    group: "Developer tools",
    status: "connected",
    connectedAs: "fadymondy",
    lastSyncAt: Date.now() - 3_600_000,
    scopes: [{ id: "repo", label: "Read repositories", required: true }],
  },
]);

// Start OAuth here (redirect or popup), then pass the updated `services` back. Resolve `{ error }` to show a message.
async function onConnect(id: string, scopes: string[]) {
  services.value = services.value.map((s) => (s.id === id ? { ...s, status: "connected" as const, grantedScopes: scopes, lastSyncAt: Date.now() } : s));
}
async function onDisconnect(id: string) {
  services.value = services.value.map((s) => (s.id === id ? { ...s, status: "disconnected" as const } : s));
}
</script>

<template>
  <NqIntegrationConnector :services="services" :on-connect="onConnect" :on-disconnect="onDisconnect" />
</template>
```

### Blade

```blade
<div x-data
    x-on:nq-connect="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-disconnect="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-select-account="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 200)))">
    <x-nq::integration-connector
        :services="[
            [
                'id' => 'search-console',
                'name' => 'Search Console',
                'group' => 'Google',
                'status' => 'disconnected',
                'description' => 'Search performance data.',
                'scopes' => [
                    ['id' => 'read', 'label' => 'Read your Search Console performance data', 'required' => true],
                    ['id' => 'sitemaps', 'label' => 'Submit sitemaps'],
                ],
            ],
            [
                'id' => 'analytics',
                'name' => 'Analytics',
                'group' => 'Google',
                'status' => 'connected',
                'connectedAs' => 'fady@example.com',
                'lastSyncAt' => '2026-01-01T09:00:00Z',
                'scopes' => [['id' => 'read', 'label' => 'Read reports', 'required' => true]],
                'accounts' => [
                    ['id' => 'p1', 'name' => 'Nasaq blog', 'detail' => 'properties/1001'],
                    ['id' => 'p2', 'name' => 'Nasaq docs', 'detail' => 'properties/1002'],
                ],
                'accountId' => 'p1',
            ],
            [
                'id' => 'github',
                'name' => 'GitHub',
                'group' => 'Developer tools',
                'status' => 'error',
                'message' => 'The token was revoked.',
                'connectedAs' => 'fadymondy',
                'scopes' => [['id' => 'repo', 'label' => 'Read repositories', 'required' => true]],
            ],
        ]" />
</div>
```

### HTML + Alpine

```html
<div x-data
    x-on:nq-connect="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-disconnect="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-select-account="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 200)))">
    <div data-slot="integration-connector" x-data="nqIntegrationConnector(JSON.parse('{\u0022services\u0022:{\u0022search-console\u0022:{\u0022name\u0022:\u0022Search Console\u0022,\u0022scopes\u0022:[{\u0022id\u0022:\u0022read\u0022,\u0022label\u0022:\u0022Read your Search Console performance data\u0022,\u0022required\u0022:true},{\u0022id\u0022:\u0022sitemaps\u0022,\u0022label\u0022:\u0022Submit sitemaps\u0022,\u0022required\u0022:false}],\u0022granted\u0022:[\u0022read\u0022,\u0022sitemaps\u0022]},\u0022analytics\u0022:{\u0022name\u0022:\u0022Analytics\u0022,\u0022scopes\u0022:[{\u0022id\u0022:\u0022read\u0022,\u0022label\u0022:\u0022Read reports\u0022,\u0022required\u0022:true}],\u0022granted\u0022:[\u0022read\u0022]},\u0022github\u0022:{\u0022name\u0022:\u0022GitHub\u0022,\u0022scopes\u0022:[{\u0022id\u0022:\u0022repo\u0022,\u0022label\u0022:\u0022Read repositories\u0022,\u0022required\u0022:true}],\u0022granted\u0022:[\u0022repo\u0022]}},\u0022status\u0022:{\u0022search-console\u0022:\u0022disconnected\u0022,\u0022analytics\u0022:\u0022connected\u0022,\u0022github\u0022:\u0022error\u0022},\u0022account\u0022:{\u0022search-console\u0022:null,\u0022analytics\u0022:\u0022p1\u0022,\u0022github\u0022:null},\u0022strings\u0022:{\u0022dialogTitle\u0022:\u0022Connect {name}\u0022,\u0022dialogBody\u0022:\u0022You will go to {name} to sign in and approve access. Nasaq never sees your password.\u0022,\u0022continue\u0022:\u0022Continue to {name}\u0022,\u0022noPermissions\u0022:\u0022Pick at least one permission.\u0022,\u0022genericError\u0022:\u0022Something went wrong. Try again.\u0022,\u0022permissionsOne\u0022:\u00221 permission\u0022,\u0022permissionsMany\u0022:\u0022{n} permissions\u0022}}'))"
    class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground w-full">
            <div data-slot="card-header" class="grid auto-rows-min items-start gap-1 px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]"><h2 data-slot="card-title" class="text-label text-foreground">Connections</h2>
            <div data-slot="card-description" class="text-body-sm text-muted-foreground">Connect the services this workspace reads from or posts to.</div></div>
        <div data-slot="card-content" class="px-4"><div class="flex flex-col gap-5">
                <div data-slot="alert" data-tone="danger" role="alert"
     x-data="nqAlert()" x-modelable="open" x-show="open"     x-model="hasError" style="display: none" class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-danger/30 bg-nq-danger-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground"><span x-text="error"></span></div>
            </div>
            <div data-slot="alert-actions" class="ms-3 flex items-center gap-1">
                            <button data-slot="button"
     type="button"                         aria-label="Dismiss" x-on:click="dismiss()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 hover:bg-nq-hover size-control-sm p-0 text-muted-foreground [&_svg]:size-3.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
                    </div>
    </div>
                                    <section class="flex flex-col gap-3" aria-label="Google">
                                                    <h3 class="text-label text-muted-foreground">Google</h3>
                                                <ul class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
                                                                                            <li data-slot="integration-service" data-service="search-console" x-bind:data-status="status['search-console']"
                                    class="flex flex-col gap-3 rounded-card border border-border bg-card p-4">
                                    <div class="flex items-start justify-between gap-3">
                                        <div class="flex min-w-0 items-center gap-3">
                                                                                        <div class="flex min-w-0 flex-col">
                                                <h3 class="truncate text-label text-foreground" dir="auto">Search Console</h3>
                                                                                                    <span data-slot="status" data-tone="neutral" x-show="status[&#039;search-console&#039;] === &#039;disconnected&#039;" style="" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
</svg>        <span class="truncate"  title="Not connected" >Not connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="success" x-show="status[&#039;search-console&#039;] === &#039;connected&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Connected" >Connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="warning" x-show="status[&#039;search-console&#039;] === &#039;needs-reauth&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs sign-in again" >Needs sign-in again</span>
</span>
                                                                                                    <span data-slot="status" data-tone="danger" x-show="status[&#039;search-console&#039;] === &#039;error&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Connection problem" >Connection problem</span>
</span>
                                                                                                    <span data-slot="status" data-tone="info" x-show="status[&#039;search-console&#039;] === &#039;pending&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-info-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <circle cx="12" cy="12" r="1"/>
</svg>        <span class="truncate"  title="Connecting…" >Connecting…</span>
</span>
                                                                                            </div>
                                        </div>
                                    </div>
                                                                            <p class="text-body-sm text-muted-foreground">Search performance data.</p>
                                                                                                            <dl class="grid gap-1 text-caption text-muted-foreground" x-show="isConnected('search-console')"  style="display: none" >
                                                                                <div class="flex flex-wrap gap-1">
                                            <dt>Last synced</dt>
                                            <dd>
                                                                                                    <span x-show="! synced['search-console']">Not synced yet</span>
                                                                                                <span x-show="synced['search-console']" style="display: none">Just now</span>
                                            </dd>
                                        </div>
                                        <div class="flex flex-wrap gap-1">
                                            <dt>Permissions</dt>
                                            <dd x-text="permissionsLabel('search-console')">2 permissions</dd>
                                        </div>
                                    </dl>
                                                                        <div class="mt-auto flex flex-wrap items-center gap-2 pt-1">
                                        <button data-slot="button"
     type="button"                         x-show="! isConnected(&#039;search-console&#039;)" style="" x-on:click="openDialog(&#039;search-console&#039;)" x-bind:aria-busy="status[&#039;search-console&#039;] === &#039;pending&#039; ? &#039;true&#039; : null" x-bind:disabled="status[&#039;search-console&#039;] === &#039;pending&#039; || busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="status[&#039;search-console&#039;] === &#039;pending&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                            <svg aria-hidden="true" x-show="status['search-console'] !== 'pending'" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M9 17H7A5 5 0 0 1 7 7h2"/>
  <path d="M15 7h2a5 5 0 1 1 0 10h-2"/>
  <line x1="8" x2="16" y1="12" y2="12"/>
</svg>                                            Connect</button>
                                        <span class="contents" x-show="isConnected('search-console')"  style="display: none" >
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;search-console&#039;] !== &#039;connected&#039;" style="" x-on:click="openDialog(&#039;search-console&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        Reconnect</button>
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;search-console&#039;] === &#039;connected&#039;" style="display: none" x-on:click="openDialog(&#039;search-console&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        Change permissions</button>
                                            <div data-slot="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" class="contents">
    <button data-slot="alert-dialog-trigger"
     type="button"                         aria-haspopup="dialog" x-on:click="show()" :aria-expanded="open" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="busy === &#039;search-console&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                                    Disconnect</button>
                                                <template x-teleport="body">
    <div data-slot="alert-dialog-portal">
        <div data-slot="alert-dialog-backdrop" x-nq-presence="open" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="alert-dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-md gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="alert-dialog-header" class="flex flex-col gap-1.5 text-start"><h2 data-slot="alert-dialog-title" :id="$id('nq-alert-dialog', 'title')" class="text-h3 text-foreground">Disconnect Search Console?</h2>
                                                        <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">Nasaq stops reading from this service and deletes the stored access. Data already imported stays. You can connect it again later.</p></div>
                                                    <div data-slot="alert-dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="alert-dialog-cancel"
     type="button"                         autofocus="autofocus" x-on:click="close()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
                                                        <button data-slot="confirm-button-action"
     type="button"                         x-on:click.capture="close()" x-on:click="disconnect(&#039;search-console&#039;)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        Disconnect</button></div>
        </div>
    </div>
</template>
</div>
                                        </span>
                                                                            </div>
                                </li>
                                                                                            <li data-slot="integration-service" data-service="analytics" x-bind:data-status="status['analytics']"
                                    class="flex flex-col gap-3 rounded-card border border-border bg-card p-4">
                                    <div class="flex items-start justify-between gap-3">
                                        <div class="flex min-w-0 items-center gap-3">
                                                                                        <div class="flex min-w-0 flex-col">
                                                <h3 class="truncate text-label text-foreground" dir="auto">Analytics</h3>
                                                                                                    <span data-slot="status" data-tone="neutral" x-show="status[&#039;analytics&#039;] === &#039;disconnected&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
</svg>        <span class="truncate"  title="Not connected" >Not connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="success" x-show="status[&#039;analytics&#039;] === &#039;connected&#039;" style="" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Connected" >Connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="warning" x-show="status[&#039;analytics&#039;] === &#039;needs-reauth&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs sign-in again" >Needs sign-in again</span>
</span>
                                                                                                    <span data-slot="status" data-tone="danger" x-show="status[&#039;analytics&#039;] === &#039;error&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Connection problem" >Connection problem</span>
</span>
                                                                                                    <span data-slot="status" data-tone="info" x-show="status[&#039;analytics&#039;] === &#039;pending&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-info-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <circle cx="12" cy="12" r="1"/>
</svg>        <span class="truncate"  title="Connecting…" >Connecting…</span>
</span>
                                                                                            </div>
                                        </div>
                                    </div>
                                                                                                            <dl class="grid gap-1 text-caption text-muted-foreground" x-show="isConnected('analytics')" >
                                                                                    <div class="flex flex-wrap gap-1">
                                                <dt>Signed in as</dt>
                                                <dd dir="ltr" class="text-foreground"><bdi>fady@example.com</bdi></dd>
                                            </div>
                                                                                <div class="flex flex-wrap gap-1">
                                            <dt>Last synced</dt>
                                            <dd>
                                                                                                    <span class="contents" x-show="! synced['analytics']"><time data-slot="date-time" datetime="2026-01-01T09:00:00+00:00" dir="auto"  title="Jan 1, 2026"     class="tabular-nums [unicode-bidi:isolate]">8 months ago</time>
</span>
                                                                                                <span x-show="synced['analytics']" style="display: none">Just now</span>
                                            </dd>
                                        </div>
                                        <div class="flex flex-wrap gap-1">
                                            <dt>Permissions</dt>
                                            <dd x-text="permissionsLabel('analytics')">1 permission</dd>
                                        </div>
                                    </dl>
                                                                            <div class="contents" x-show="isConnected('analytics')" >
                                            <div data-slot="field" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Account</label>
                                                <div data-slot="select" x-data="nqSelect('p1', false)" x-modelable="value" x-id="['nq-select']" x-model="account[&#039;analytics&#039;]" class="contents">
    <button data-slot="select-trigger" x-ref="trigger" x-bind="trigger"
        aria-label="Analytics: Account" class="flex h-control w-full min-w-0 items-center justify-between gap-2 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] cursor-default select-none outline-none transition-colors duration-150 ease-nq focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-popup-open:border-nq-focus data-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px]">
    <span data-slot="select-value" x-text="label() ?? ''" :data-placeholder="empty() ? '' : undefined"
    class="min-w-0 flex-1 truncate text-start data-placeholder:text-muted-foreground"></span>
    <span class="flex shrink-0 text-muted-foreground [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></span>
</button>
                                                    <template x-teleport="body">
    <div data-slot="select-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.trigger"
        class="z-50 min-w-[var(--anchor-width)] max-h-[var(--available-height)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="select-item" x-bind="item('p1', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('p1')" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate"><span class="flex min-w-0 flex-col">
                                                                    <span class="truncate" dir="auto">Nasaq blog</span>
                                                                                                                                            <span class="truncate text-caption text-muted-foreground" dir="ltr">properties/1001</span>
                                                                                                                                    </span></span>
</div>
                                                                                                                    <div data-slot="select-item" x-bind="item('p2', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('p2')" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate"><span class="flex min-w-0 flex-col">
                                                                    <span class="truncate" dir="auto">Nasaq docs</span>
                                                                                                                                            <span class="truncate text-caption text-muted-foreground" dir="ltr">properties/1002</span>
                                                                                                                                    </span></span>
</div>
    </div>
</template>
    </div>
</div>
                                        </div>
                                                                        <div class="mt-auto flex flex-wrap items-center gap-2 pt-1">
                                        <button data-slot="button"
     type="button"                         x-show="! isConnected(&#039;analytics&#039;)" style="display: none" x-on:click="openDialog(&#039;analytics&#039;)" x-bind:aria-busy="status[&#039;analytics&#039;] === &#039;pending&#039; ? &#039;true&#039; : null" x-bind:disabled="status[&#039;analytics&#039;] === &#039;pending&#039; || busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="status[&#039;analytics&#039;] === &#039;pending&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                            <svg aria-hidden="true" x-show="status['analytics'] !== 'pending'" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M9 17H7A5 5 0 0 1 7 7h2"/>
  <path d="M15 7h2a5 5 0 1 1 0 10h-2"/>
  <line x1="8" x2="16" y1="12" y2="12"/>
</svg>                                            Connect</button>
                                        <span class="contents" x-show="isConnected('analytics')" >
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;analytics&#039;] !== &#039;connected&#039;" style="display: none" x-on:click="openDialog(&#039;analytics&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        Reconnect</button>
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;analytics&#039;] === &#039;connected&#039;" style="" x-on:click="openDialog(&#039;analytics&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        Change permissions</button>
                                            <div data-slot="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" class="contents">
    <button data-slot="alert-dialog-trigger"
     type="button"                         aria-haspopup="dialog" x-on:click="show()" :aria-expanded="open" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="busy === &#039;analytics&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                                    Disconnect</button>
                                                <template x-teleport="body">
    <div data-slot="alert-dialog-portal">
        <div data-slot="alert-dialog-backdrop" x-nq-presence="open" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="alert-dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-md gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="alert-dialog-header" class="flex flex-col gap-1.5 text-start"><h2 data-slot="alert-dialog-title" :id="$id('nq-alert-dialog', 'title')" class="text-h3 text-foreground">Disconnect Analytics?</h2>
                                                        <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">Nasaq stops reading from this service and deletes the stored access. Data already imported stays. You can connect it again later.</p></div>
                                                    <div data-slot="alert-dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="alert-dialog-cancel"
     type="button"                         autofocus="autofocus" x-on:click="close()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
                                                        <button data-slot="confirm-button-action"
     type="button"                         x-on:click.capture="close()" x-on:click="disconnect(&#039;analytics&#039;)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        Disconnect</button></div>
        </div>
    </div>
</template>
</div>
                                        </span>
                                                                            </div>
                                </li>
                                                    </ul>
                    </section>
                                    <section class="flex flex-col gap-3" aria-label="Developer tools">
                                                    <h3 class="text-label text-muted-foreground">Developer tools</h3>
                                                <ul class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
                                                                                            <li data-slot="integration-service" data-service="github" x-bind:data-status="status['github']"
                                    class="flex flex-col gap-3 rounded-card border border-border bg-card p-4">
                                    <div class="flex items-start justify-between gap-3">
                                        <div class="flex min-w-0 items-center gap-3">
                                                                                        <div class="flex min-w-0 flex-col">
                                                <h3 class="truncate text-label text-foreground" dir="auto">GitHub</h3>
                                                                                                    <span data-slot="status" data-tone="neutral" x-show="status[&#039;github&#039;] === &#039;disconnected&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
</svg>        <span class="truncate"  title="Not connected" >Not connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="success" x-show="status[&#039;github&#039;] === &#039;connected&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Connected" >Connected</span>
</span>
                                                                                                    <span data-slot="status" data-tone="warning" x-show="status[&#039;github&#039;] === &#039;needs-reauth&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs sign-in again" >Needs sign-in again</span>
</span>
                                                                                                    <span data-slot="status" data-tone="danger" x-show="status[&#039;github&#039;] === &#039;error&#039;" style="" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Connection problem" >Connection problem</span>
</span>
                                                                                                    <span data-slot="status" data-tone="info" x-show="status[&#039;github&#039;] === &#039;pending&#039;" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-foreground text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-info-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <circle cx="12" cy="12" r="1"/>
</svg>        <span class="truncate"  title="Connecting…" >Connecting…</span>
</span>
                                                                                            </div>
                                        </div>
                                    </div>
                                                                                                                <div data-slot="alert" data-tone="danger" role="alert"
        x-show="status[&#039;github&#039;] === &#039;error&#039;" style="" class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-danger/30 bg-nq-danger-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground">The token was revoked.</div>
            </div>
    </div>
                                        <div data-slot="alert" data-tone="warning" role="alert"
        x-show="status[&#039;github&#039;] === &#039;needs-reauth&#039;" style="display: none" class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-warning/30 bg-nq-warning-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground">The token was revoked.</div>
            </div>
    </div>
                                                                        <dl class="grid gap-1 text-caption text-muted-foreground" x-show="isConnected('github')" >
                                                                                    <div class="flex flex-wrap gap-1">
                                                <dt>Signed in as</dt>
                                                <dd dir="ltr" class="text-foreground"><bdi>fadymondy</bdi></dd>
                                            </div>
                                                                                <div class="flex flex-wrap gap-1">
                                            <dt>Last synced</dt>
                                            <dd>
                                                                                                    <span x-show="! synced['github']">Not synced yet</span>
                                                                                                <span x-show="synced['github']" style="display: none">Just now</span>
                                            </dd>
                                        </div>
                                        <div class="flex flex-wrap gap-1">
                                            <dt>Permissions</dt>
                                            <dd x-text="permissionsLabel('github')">1 permission</dd>
                                        </div>
                                    </dl>
                                                                        <div class="mt-auto flex flex-wrap items-center gap-2 pt-1">
                                        <button data-slot="button"
     type="button"                         x-show="! isConnected(&#039;github&#039;)" style="display: none" x-on:click="openDialog(&#039;github&#039;)" x-bind:aria-busy="status[&#039;github&#039;] === &#039;pending&#039; ? &#039;true&#039; : null" x-bind:disabled="status[&#039;github&#039;] === &#039;pending&#039; || busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="status[&#039;github&#039;] === &#039;pending&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                            <svg aria-hidden="true" x-show="status['github'] !== 'pending'" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M9 17H7A5 5 0 0 1 7 7h2"/>
  <path d="M15 7h2a5 5 0 1 1 0 10h-2"/>
  <line x1="8" x2="16" y1="12" y2="12"/>
</svg>                                            Connect</button>
                                        <span class="contents" x-show="isConnected('github')" >
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;github&#039;] !== &#039;connected&#039;" style="" x-on:click="openDialog(&#039;github&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        Reconnect</button>
                                            <button data-slot="button"
     type="button"                         x-show="status[&#039;github&#039;] === &#039;connected&#039;" style="display: none" x-on:click="openDialog(&#039;github&#039;)" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        Change permissions</button>
                                            <div data-slot="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" class="contents">
    <button data-slot="alert-dialog-trigger"
     type="button"                         aria-haspopup="dialog" x-on:click="show()" :aria-expanded="open" x-bind:disabled="busy !== null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="busy === &#039;github&#039;" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                                    Disconnect</button>
                                                <template x-teleport="body">
    <div data-slot="alert-dialog-portal">
        <div data-slot="alert-dialog-backdrop" x-nq-presence="open" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="alert-dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-md gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="alert-dialog-header" class="flex flex-col gap-1.5 text-start"><h2 data-slot="alert-dialog-title" :id="$id('nq-alert-dialog', 'title')" class="text-h3 text-foreground">Disconnect GitHub?</h2>
                                                        <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">Nasaq stops reading from this service and deletes the stored access. Data already imported stays. You can connect it again later.</p></div>
                                                    <div data-slot="alert-dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="alert-dialog-cancel"
     type="button"                         autofocus="autofocus" x-on:click="close()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
                                                        <button data-slot="confirm-button-action"
     type="button"                         x-on:click.capture="close()" x-on:click="disconnect(&#039;github&#039;)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        Disconnect</button></div>
        </div>
    </div>
</template>
</div>
                                        </span>
                                                                            </div>
                                </li>
                                                    </ul>
                    </section>
                            </div>
            <div data-slot="dialog" x-data="nqDialog(false)" x-modelable="open" x-id="['nq-dialog']" x-model="dialogOpen" class="contents">
    <template x-teleport="body">
    <div data-slot="dialog-portal">
        <div data-slot="dialog-backdrop" x-nq-presence="open" x-on:click="close()" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-lg gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <form data-slot="integration-connect-dialog" class="grid gap-4" novalidate x-on:submit.prevent="submit()">
                        <div data-slot="dialog-header" class="flex flex-col gap-1.5 pe-8 text-start"><h2 data-slot="dialog-title" :id="$id('nq-dialog', 'title')" class="text-h3 text-foreground"><span x-text="dialogTitle"></span></h2>
                            <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground"><span x-text="dialogBody"></span></p></div>
                        <div data-slot="alert" data-tone="danger" role="alert"
        x-show="dialogError" style="display: none" class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-danger/30 bg-nq-danger-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground"><span x-text="dialogError"></span></div>
            </div>
    </div>
                        <fieldset class="grid gap-2 border-0 p-0">
                            <legend class="mb-1 text-label text-foreground">Nasaq will be able to</legend>
                            <ul class="grid gap-1 rounded-card border border-border p-2">
                                <template x-for="(sc, i) in scopes" :key="sc.id">
                                    <li class="flex items-start gap-2.5 rounded-control px-2 py-1.5">
                                        <button type="button" role="checkbox" data-slot="checkbox" x-data="nqCheckbox(false, false)" x-modelable="checked" x-bind="root"
    aria-checked="false"
     data-unchecked                 x-bind:id="&#039;nq-integration-5c59c5-&#039; + sc.id" x-model="picked[i]" x-bind:disabled="sc.required" x-bind:data-disabled="sc.required ? &#039;&#039; : null" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1 mt-0.5">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3" x-show="checked || indeterminate"  style="display: none" >
        <svg aria-hidden="true" x-show="indeterminate" style="display: none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
</svg>        <svg aria-hidden="true" x-show="! indeterminate" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg>    </span>
    </button>
                                        <label x-bind:for="'nq-integration-5c59c5-' + sc.id" class="flex min-w-0 flex-1 flex-wrap items-center gap-x-2 text-body-sm text-foreground">
                                            <span x-text="sc.label"></span>
                                            <span data-slot="badge"     x-show="sc.required" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-border text-muted-foreground">Required</span>
                                        </label>
                                    </li>
                                </template>
                            </ul>
                        </fieldset>
                        <div data-slot="dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="button"
     type="button"                         x-bind:disabled="dialogBusy" x-on:click="closeDialog()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
                            <button data-slot="button"
     type="submit"                         x-bind:disabled="dialogBusy" x-bind:aria-busy="dialogBusy ? &#039;true&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="dialogBusy" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                <span x-text="continueLabel"></span></button></div>
                    </form>
                            <button type="button" data-slot="dialog-close" x-on:click="close()" aria-label="Close"
                    class="absolute end-3 top-3 inline-flex size-8 items-center justify-center rounded-control text-muted-foreground transition-colors duration-150 hover:bg-nq-hover hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
                    </div>
    </div>
</template>
</div></div>
</div>
</div>
```
