Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
137 lines
4.4 KiB
TypeScript
137 lines
4.4 KiB
TypeScript
import React, { useMemo, useState } from 'react';
|
|
|
|
import { IframeBridge, callHandlerJson } from '@alga-psa/extension-iframe-sdk';
|
|
import { Button, Card, Stack, Text } from '@alga-psa/ui-kit';
|
|
|
|
const bridge = new IframeBridge({ devAllowWildcard: true });
|
|
bridge.ready();
|
|
|
|
function formatError(error: unknown): string {
|
|
return error instanceof Error ? error.message : String(error);
|
|
}
|
|
|
|
async function runProxyCall(path: string) {
|
|
return callHandlerJson(bridge, path);
|
|
}
|
|
|
|
export default function App() {
|
|
const [activeAction, setActiveAction] = useState<string | null>(null);
|
|
const [result, setResult] = useState<unknown>('Ready.');
|
|
|
|
const output = useMemo(() => JSON.stringify(result, null, 2), [result]);
|
|
|
|
const runAction = async (actionKey: string, path: string) => {
|
|
setActiveAction(actionKey);
|
|
try {
|
|
const nextResult = await runProxyCall(path);
|
|
setResult({ ok: true, path, result: nextResult });
|
|
} catch (error) {
|
|
setResult({ ok: false, path, error: formatError(error) });
|
|
} finally {
|
|
setActiveAction(null);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
minHeight: '100vh',
|
|
padding: 24,
|
|
background: 'linear-gradient(180deg, var(--alga-bg) 0%, var(--alga-primary-50) 100%)',
|
|
color: 'var(--alga-fg)',
|
|
fontFamily:
|
|
'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
}}
|
|
>
|
|
<div style={{ maxWidth: 960, margin: '0 auto' }}>
|
|
<Stack gap={16}>
|
|
<Stack gap={6}>
|
|
<Text as="strong" size="lg" weight={700}>
|
|
Client/Service Read Demo
|
|
</Text>
|
|
<Text as="p" tone="muted" style={{ margin: 0 }}>
|
|
Uses host capabilities for tenant-scoped client and service reads without calling
|
|
internal APIs from the handler.
|
|
</Text>
|
|
</Stack>
|
|
|
|
<Card>
|
|
<Stack direction="row" gap={10} style={{ flexWrap: 'wrap' }}>
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() => void runAction('clients', '/api/clients')}
|
|
disabled={activeAction !== null}
|
|
>
|
|
{activeAction === 'clients' ? 'Loading...' : 'Load Clients'}
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => void runAction('services', '/api/services')}
|
|
disabled={activeAction !== null}
|
|
>
|
|
{activeAction === 'services' ? 'Loading...' : 'Load Services'}
|
|
</Button>
|
|
</Stack>
|
|
</Card>
|
|
|
|
<div
|
|
style={{
|
|
display: 'grid',
|
|
gap: 16,
|
|
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
|
|
}}
|
|
>
|
|
<Card>
|
|
<Stack gap={10}>
|
|
<Text as="strong" weight={600}>
|
|
What It Tests
|
|
</Text>
|
|
<Text as="p" tone="muted" size="sm" style={{ margin: 0 }}>
|
|
Separate UI actions for the two read capabilities exposed by this sample.
|
|
</Text>
|
|
<Stack gap={8}>
|
|
<Text size="sm">
|
|
<code>GET /api/clients</code>
|
|
</Text>
|
|
<Text size="sm">
|
|
<code>GET /api/services</code>
|
|
</Text>
|
|
</Stack>
|
|
</Stack>
|
|
</Card>
|
|
|
|
<Card>
|
|
<Stack gap={10}>
|
|
<Text as="strong" weight={600}>
|
|
Output
|
|
</Text>
|
|
<Text as="p" tone="muted" size="sm" style={{ margin: 0 }}>
|
|
Live handler response from the installed extension.
|
|
</Text>
|
|
<pre
|
|
style={{
|
|
margin: 0,
|
|
padding: '16px',
|
|
minHeight: 240,
|
|
overflow: 'auto',
|
|
borderRadius: 'var(--alga-radius)',
|
|
background: 'var(--alga-muted)',
|
|
color: 'var(--alga-fg)',
|
|
border: '1px solid var(--alga-border)',
|
|
fontSize: 12,
|
|
lineHeight: 1.5,
|
|
whiteSpace: 'pre-wrap',
|
|
wordBreak: 'break-word',
|
|
}}
|
|
>
|
|
{output}
|
|
</pre>
|
|
</Stack>
|
|
</Card>
|
|
</div>
|
|
</Stack>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|