Skip to content

Commit

Permalink
dev-app: wait for vite to notice the new example before navigating to it
Browse files Browse the repository at this point in the history
  • Loading branch information
emilefokkema committed Jul 27, 2024
1 parent 41f18d2 commit 678e377
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 26 deletions.
10 changes: 8 additions & 2 deletions dev-app/backend/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { default as express, type Express, type Request, type Response, json } f
import { ExampleDescription } from '../shared';
import { createExample, getExamplesMetadata } from '../../examples/access'
import { getTestCasesMetadata } from '../../test-cases/backend'
import { CreateExampleRequest } from '../../examples/shared';

function logRequest(req: Request, res: Response): void{
console.log(`responding with ${res.statusCode} to ${req.path}`)
Expand All @@ -26,8 +27,13 @@ export function createRouter(): Express{
next()
}, logRequest)
app.post('/examples/create', async (req, res) => {
const id = await createExample(req.body)
res.status(200).send(id)
const {dirName, title} = await createExample(req.body)
const newDescription: ExampleDescription = {
id: dirName,
title,
kind: 'use-case'
};
res.json(newDescription)
})
return app;
}
15 changes: 2 additions & 13 deletions dev-app/frontend/src/current-example-url.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import { computed, inject, type Ref } from 'vue'
import { examplesStoreInjectionKey } from './constants'
import type { ExamplesStore } from './examples-store'
import type { ExampleDescription } from '../../shared'

function getTestCaseUrl(description: ExampleDescription): string{
return new URL(`/test-case/#/${description.id}`, location.href).toString()
}

function getExampleUrl(description: ExampleDescription): string{
return new URL(`/examples/${description.id}/`, location.href).toString()
}
import { getExampleUrl } from './get-example-url'

export interface CurrentExampleUrl{
url: Ref<string | undefined>
Expand All @@ -25,10 +17,7 @@ export function useCurrentExampleUrl(): Ref<string | undefined>{
return undefined;
}
const description = selectedExample.description;
if(description.kind === 'test-case'){
return getTestCaseUrl(selectedExample.description)
}
return getExampleUrl(selectedExample.description)
return getExampleUrl(description)
})
return rawCurrentExampleUrl;
}
19 changes: 16 additions & 3 deletions dev-app/frontend/src/examples-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { ref, type Ref } from 'vue'
import type { ExampleDescription } from '../../shared'
import type { CreateExampleRequest } from '../../../examples/shared'
import type { ExamplesRouter } from './examples-router'
import { getExampleUrl } from './get-example-url'
import { waitUntilFound } from './wait-until-found'

export interface DisplayableExample{
id: string
Expand All @@ -15,14 +17,21 @@ export interface ExamplesStore{
createExample(request: CreateExampleRequest): Promise<void>
}

function mapToDisplayableExample(description: ExampleDescription): DisplayableExample{
return {
id: `${description.kind}/${description.id}`,
description
};
}

export function createExamplesStore(router: ExamplesRouter): ExamplesStore{
const examples = ref<DisplayableExample[]>([])
const selected = ref<string | null>(null);

async function refresh(): Promise<void>{
const response = await fetch('/api/examples');
const result = (await response.json()) as ExampleDescription[];
const examplesValue = result.map(e => ({id: `${e.kind}/${e.id}`, description: e}));
const examplesValue = result.map(mapToDisplayableExample);
examplesValue.sort((a, b) => a.description.title > b.description.title ? 1 : -1);
examples.value = examplesValue;
if(selected.value === null){
Expand All @@ -41,8 +50,12 @@ export function createExamplesStore(router: ExamplesRouter): ExamplesStore{

async function createExample(request: CreateExampleRequest): Promise<void>{
const response = await fetch('/api/examples/create', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(request)})
const id = await response.text();
refresh().then(() => selectExample(`use-case/${id}`));
const description = await response.json();
const displayableExample = mapToDisplayableExample(description)
const url = getExampleUrl(description)
await waitUntilFound(url)
await refresh();
selectExample(displayableExample.id)
}
return { examples, selected, refresh, selectExample, createExample };
}
16 changes: 16 additions & 0 deletions dev-app/frontend/src/get-example-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ExampleDescription } from "../../shared";

function getTestCaseUrl(description: ExampleDescription): string{
return new URL(`/test-case/#/${description.id}`, location.href).toString()
}

function getUseCaseUrl(description: ExampleDescription): string{
return new URL(`/examples/${description.id}/`, location.href).toString()
}

export function getExampleUrl(description: ExampleDescription): string{
if(description.kind === 'test-case'){
return getTestCaseUrl(description)
}
return getUseCaseUrl(description)
}
18 changes: 18 additions & 0 deletions dev-app/frontend/src/wait-until-found.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
async function isFound(url: string): Promise<boolean>{
const response = await fetch(url);
return response.status === 200;
}

const retryInterval = 400;
const maxRetries = 10;

export async function waitUntilFound(url: string): Promise<void>{
let found = await isFound(url);
let retryCount = 0;
while(!found && retryCount < maxRetries){
console.log(`${url} was not found. Retrying in ${retryInterval}ms...`)
retryCount++;
await new Promise(res => setTimeout(res, retryInterval))
found = await isFound(url);
}
}
9 changes: 7 additions & 2 deletions examples/access/create-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { mkdir, writeFile } from 'fs/promises'
import { CreateExampleRequest } from "../shared";
import { getExamplesDirs } from "./get-examples-dirs";
import { examplesDirPath } from './constants';
import { ExampleMetadata } from './example-metadata';

function createExampleId(title: string, dirs: {dirName: string, fullPath: string}[]): string{
const wantedId = title.toLowerCase().replace(/[^\w\s]/g,'').replace(/\s+/g,'-');
Expand All @@ -15,7 +16,7 @@ function createExampleId(title: string, dirs: {dirName: string, fullPath: string
return id;
}

export async function createExample(request: CreateExampleRequest): Promise<string>{
export async function createExample(request: CreateExampleRequest): Promise<ExampleMetadata>{
const dirs = await getExamplesDirs();
const title = request.title.trim();
const id = createExampleId(title, dirs);
Expand All @@ -37,5 +38,9 @@ export async function createExample(request: CreateExampleRequest): Promise<stri
writeFile(path.resolve(exampleDirName, 'index-dark.css'), indexDarkCss, {encoding: 'utf-8'}),
writeFile(path.resolve(exampleDirName, 'example.json'), JSON.stringify(exampleJson, null, 2), {encoding: 'utf-8'})
])
return id;
return {
dirName: id,
dirPath: exampleDirName,
title,
};
}
5 changes: 5 additions & 0 deletions examples/access/example-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ExampleMetadata{
dirPath: string
dirName: string
title: string
}
7 changes: 1 addition & 6 deletions examples/access/get-examples-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import path from 'path'
import { readFile } from "fs/promises"
import { getExamplesDirs } from "./get-examples-dirs"

export interface ExampleMetadata{
dirPath: string
dirName: string
title: string
}
import { ExampleMetadata } from './example-metadata'

interface ExampleJson{
title: string
Expand Down

0 comments on commit 678e377

Please sign in to comment.