Skip to content

Commit 74d556d

Browse files
committed
optimistic ui, remove profiling code
1 parent 4cfaa72 commit 74d556d

File tree

7 files changed

+85
-99
lines changed

7 files changed

+85
-99
lines changed

ui/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
"dev": "vite dev",
99
"build": "vite build && tsc --noEmit",
1010
"start": "NODE_ENV=production node dist/server/server.js",
11-
"start:profile": "NODE_ENV=production node --prof dist/server/server.js",
12-
"start:inspect": "NODE_ENV=production node --inspect dist/server/server.js",
13-
"start:debug": "NODE_ENV=production DEBUG=true node dist/server/server.js",
1411
"preview": "vite preview",
1512
"type-check": "tsc --noEmit",
1613
"type-check:watch": "tsc --noEmit --watch"

ui/src/api/orchestrator_serverFunctions.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { fetchRepos } from "./orchestrator_repos";
44
import { getOrgSettings, updateOrgSettings } from "./orchestrator_orgs";
55
import { testSlackWebhook } from "./drift_slack";
66
import { fetchProjects, updateProject, fetchProject } from "./orchestrator_projects";
7-
import { timeAsync } from "@/lib/perf.server";
87

98
export const getOrgSettingsFn = createServerFn({method: 'GET'})
109
.inputValidator((data : {userId: string, organisationId: string}) => data)
@@ -29,10 +28,7 @@ export const getProjectsFn = createServerFn({method: 'GET'})
2928
})
3029
.handler(async ({ data }) => {
3130
try {
32-
const projects : any = await timeAsync(
33-
`fetchProjects(org=${data.organisationId})`,
34-
() => fetchProjects(data.organisationId, data.userId)
35-
)
31+
const projects : any = await fetchProjects(data.organisationId, data.userId)
3632
return projects.result || []
3733
} catch (error) {
3834
console.error('Error in getProjectsFn:', error)
@@ -53,10 +49,7 @@ export const getReposFn = createServerFn({method: 'GET'})
5349
.handler(async ({ data }) => {
5450
let repos = []
5551
try {
56-
const reposData :any = await timeAsync(
57-
`fetchRepos(org=${data.organisationId})`,
58-
() => fetchRepos(data.organisationId, data.userId)
59-
)
52+
const reposData :any = await fetchRepos(data.organisationId, data.userId)
6053
repos = reposData.result
6154
} catch (error) {
6255
console.error('Error fetching repos:', error)
@@ -68,11 +61,8 @@ export const getReposFn = createServerFn({method: 'GET'})
6861
export const getProjectFn = createServerFn({method: 'GET'})
6962
.inputValidator((data : {projectId: string, organisationId: string, userId: string}) => data)
7063
.handler(async ({ data }) => {
71-
const project : any = await timeAsync(
72-
`fetchProject(${data.projectId})`,
73-
() => fetchProject(data.projectId, data.organisationId, data.userId)
74-
)
75-
return project
64+
const project : any = await fetchProject(data.projectId, data.organisationId, data.userId)
65+
return project.result
7666
})
7767

7868

@@ -83,9 +73,6 @@ export const getRepoDetailsFn = createServerFn({method: 'GET'})
8373
let allJobs: Job[] = [];
8474
let repo: Repo
8575
try {
86-
const result = await timeAsync(
87-
`fetchRepoJobs(${repoId})`,
88-
async () => {
8976
const response = await fetch(`${process.env.ORCHESTRATOR_BACKEND_URL}/api/repos/${repoId}/jobs`, {
9077
method: 'GET',
9178
headers: {
@@ -100,9 +87,7 @@ export const getRepoDetailsFn = createServerFn({method: 'GET'})
10087
throw new Error('Failed to fetch jobs');
10188
}
10289

103-
return await response.json();
104-
}
105-
);
90+
const result = await response.json();
10691

10792
repo = result.repo
10893
allJobs = result.jobs || []

ui/src/api/statesman_serverFunctions.ts

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
11
import { createServerFn } from "@tanstack/react-start"
22
import { createUnit, getUnit, listUnits, getUnitVersions, unlockUnit, lockUnit, getUnitStatus, deleteUnit, downloadLatestState, forcePushState, restoreUnitStateVersion } from "./statesman_units"
3-
import { timeAsync } from "@/lib/perf.server"
43

54
export const listUnitsFn = createServerFn({method: 'GET'})
65
.inputValidator((data : {userId: string, organisationId: string, email: string}) => data)
76
.handler(async ({ data }) => {
8-
const units : any = await timeAsync(
9-
`listUnits(org=${data.organisationId})`,
10-
() => listUnits(data.organisationId, data.userId, data.email)
11-
)
7+
const units : any = await listUnits(data.organisationId, data.userId, data.email)
128
return units
139
})
1410

1511
export const getUnitFn = createServerFn({method: 'GET'})
1612
.inputValidator((data : {userId: string, organisationId: string, email: string, unitId: string}) => data)
1713
.handler(async ({ data }) => {
18-
const unit : any = await timeAsync(
19-
`getUnit(${data.unitId})`,
20-
() => getUnit(data.organisationId, data.userId, data.email, data.unitId)
21-
)
14+
const unit : any = await getUnit(data.organisationId, data.userId, data.email, data.unitId)
2215
return unit
2316
})
2417

2518
export const getUnitVersionsFn = createServerFn({method: 'GET'})
2619
.inputValidator((data : {userId: string, organisationId: string, email: string, unitId: string}) => data)
2720
.handler(async ({ data }) => {
28-
const unitVersions : any = await timeAsync(
29-
`getUnitVersions(${data.unitId})`,
30-
() => getUnitVersions(data.organisationId, data.userId, data.email, data.unitId)
31-
)
21+
const unitVersions : any = await getUnitVersions(data.organisationId, data.userId, data.email, data.unitId)
3222
return unitVersions
3323
})
3424

@@ -70,20 +60,14 @@ export const restoreUnitStateVersionFn = createServerFn({method: 'POST'})
7060
export const getUnitStatusFn = createServerFn({method: 'GET'})
7161
.inputValidator((data : {userId: string, organisationId: string, email: string, unitId: string}) => data)
7262
.handler(async ({ data }) => {
73-
const unitStatus : any = await timeAsync(
74-
`getUnitStatus(${data.unitId})`,
75-
() => getUnitStatus(data.organisationId, data.userId, data.email, data.unitId)
76-
)
63+
const unitStatus : any = await getUnitStatus(data.organisationId, data.userId, data.email, data.unitId)
7764
return unitStatus
7865
})
7966

8067
export const createUnitFn = createServerFn({method: 'POST'})
8168
.inputValidator((data : {userId: string, organisationId: string, email: string, name: string}) => data)
8269
.handler(async ({ data }) => {
83-
const unit : any = await timeAsync(
84-
`createUnit(${data.name})`,
85-
() => createUnit(data.organisationId, data.userId, data.email, data.name)
86-
)
70+
const unit : any = await createUnit(data.organisationId, data.userId, data.email, data.name)
8771
return unit
8872
})
8973

ui/src/components/UnitCreateForm.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,22 @@ type UnitCreateFormProps = {
1212
email: string
1313
organisationId: string
1414
onCreated: (unit: { id: string; name: string }) => void
15+
onCreatedOptimistic?: (tempUnit: { id: string; name: string; isOptimistic: boolean }) => void
16+
onCreatedFailed?: () => void
1517
onBringOwnState: () => void
1618
showBringOwnState?: boolean
1719
}
1820

19-
export default function UnitCreateForm({ userId, email, organisationId, onCreated, onBringOwnState, showBringOwnState = true }: UnitCreateFormProps) {
21+
export default function UnitCreateForm({
22+
userId,
23+
email,
24+
organisationId,
25+
onCreated,
26+
onCreatedOptimistic,
27+
onCreatedFailed,
28+
onBringOwnState,
29+
showBringOwnState = true
30+
}: UnitCreateFormProps) {
2031
const [unitName, setUnitName] = React.useState('')
2132
const [unitType, setUnitType] = React.useState<'local' | 'remote'>('local')
2233
const [isCreating, setIsCreating] = React.useState(false)
@@ -26,6 +37,15 @@ export default function UnitCreateForm({ userId, email, organisationId, onCreate
2637
if (!unitName.trim()) return
2738
setIsCreating(true)
2839
setError(null)
40+
41+
const tempId = `temp-${Date.now()}`
42+
const tempUnit = { id: tempId, name: unitName.trim(), isOptimistic: true }
43+
44+
// Optimistic update - show immediately
45+
if (onCreatedOptimistic) {
46+
onCreatedOptimistic(tempUnit)
47+
}
48+
2949
try {
3050
const unit = await createUnitFn({
3151
data: {
@@ -38,6 +58,9 @@ export default function UnitCreateForm({ userId, email, organisationId, onCreate
3858
onCreated({ id: unit.id, name: unit.name })
3959
} catch (e: any) {
4060
setError(e?.message ?? 'Failed to create unit')
61+
if (onCreatedFailed) {
62+
onCreatedFailed()
63+
}
4164
} finally {
4265
setIsCreating(false)
4366
}

ui/src/lib/perf.server.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.

ui/src/routes/_authenticated/_dashboard/dashboard/units.index.tsx

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ function formatDate(date: Date) {
5555
})
5656
}
5757

58-
function CreateUnitModal({ onUnitCreated }: { onUnitCreated: () => void }) {
58+
function CreateUnitModal({ onUnitCreated, onUnitOptimistic, onUnitFailed }: {
59+
onUnitCreated: () => void,
60+
onUnitOptimistic: (unit: any) => void,
61+
onUnitFailed: () => void
62+
}) {
5963
const [open, setOpen] = useState(false)
6064
const { user, organisationId } = Route.useLoaderData()
6165
const navigate = Route.useNavigate()
@@ -80,7 +84,17 @@ function CreateUnitModal({ onUnitCreated }: { onUnitCreated: () => void }) {
8084
userId={user?.id || ''}
8185
email={user?.email || ''}
8286
organisationId={organisationId}
83-
onCreated={() => { setOpen(false); onUnitCreated(); }}
87+
onCreatedOptimistic={(tempUnit) => {
88+
onUnitOptimistic(tempUnit)
89+
setOpen(false)
90+
}}
91+
onCreated={() => {
92+
setOpen(false)
93+
onUnitCreated()
94+
}}
95+
onCreatedFailed={() => {
96+
onUnitFailed()
97+
}}
8498
onBringOwnState={() => { setOpen(false); navigate({ to: '/dashboard/onboarding' }); }}
8599
showBringOwnState={false}
86100
/>
@@ -96,11 +110,28 @@ function RouteComponent() {
96110
const navigate = Route.useNavigate()
97111
const router = useRouter()
98112

113+
// Handle optimistic update - add immediately
114+
function handleUnitOptimistic(tempUnit: any) {
115+
setUnits(prev => [{
116+
...tempUnit,
117+
locked: false,
118+
size: 0,
119+
updatedAt: new Date(),
120+
isOptimistic: true
121+
}, ...prev])
122+
}
123+
124+
// Handle actual creation - refresh from server
99125
async function handleUnitCreated() {
100126
const unitsData = await listUnitsFn({data: {organisationId: organisationId, userId: user?.id || '', email: user?.email || ''}})
101127
setUnits(unitsData.units)
102128
}
103129

130+
// Handle failure - remove optimistic unit
131+
function handleUnitFailed() {
132+
setUnits(prev => prev.filter((u: any) => !u.isOptimistic))
133+
}
134+
104135
return (<>
105136
<div className="container mx-auto p-4">
106137
<div className="mb-6">
@@ -122,7 +153,11 @@ function RouteComponent() {
122153
<Button variant="outline" asChild>
123154
<Link to="/dashboard/onboarding">Show onboarding flow</Link>
124155
</Button>
125-
<CreateUnitModal onUnitCreated={handleUnitCreated} />
156+
<CreateUnitModal
157+
onUnitOptimistic={handleUnitOptimistic}
158+
onUnitCreated={handleUnitCreated}
159+
onUnitFailed={handleUnitFailed}
160+
/>
126161
</div>)}
127162
</CardHeader>
128163
<CardContent>
@@ -153,20 +188,25 @@ function RouteComponent() {
153188
</TableRow>
154189
</TableHeader>
155190
<TableBody>
156-
{units.map((unit) => (
157-
<TableRow key={unit.id}>
191+
{units.map((unit: any) => (
192+
<TableRow key={unit.id} className={unit.isOptimistic ? 'opacity-60' : ''}>
158193
<TableCell>
159194
{unit.locked ? <Lock className="h-5 w-5 text-destructive" /> : <Unlock className="h-5 w-5 text-muted-foreground" />}
160195
</TableCell>
161-
<TableCell className="font-medium">{unit.name}</TableCell>
196+
<TableCell className="font-medium">
197+
{unit.name}
198+
{unit.isOptimistic && <span className="ml-2 text-xs text-muted-foreground">(Creating...)</span>}
199+
</TableCell>
162200
<TableCell>{formatBytes(unit.size)}</TableCell>
163201
<TableCell>{formatDate(unit.updatedAt || new Date())}</TableCell>
164202
<TableCell className="text-right">
165-
<Button variant="ghost" asChild className="justify-end">
166-
<Link to={`/dashboard/units/$unitId`} params={{ unitId: unit.id }}>
167-
View Details <ExternalLink className="ml-2 h-4 w-4" />
168-
</Link>
169-
</Button>
203+
{!unit.isOptimistic && (
204+
<Button variant="ghost" asChild className="justify-end">
205+
<Link to={`/dashboard/units/$unitId`} params={{ unitId: unit.id }}>
206+
View Details <ExternalLink className="ml-2 h-4 w-4" />
207+
</Link>
208+
</Button>
209+
)}
170210
</TableCell>
171211
</TableRow>
172212
))}

ui/vite.config.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ export default defineConfig(({ mode }) => {
2121
port: 3030,
2222
allowedHosts,
2323
},
24-
build: {
25-
// Enable source maps for profiling
26-
sourcemap: true,
27-
},
2824
plugins: [
2925
tsConfigPaths({
3026
projects: ['./tsconfig.json'],

0 commit comments

Comments
 (0)