Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

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>
);
}