Skip to content

Commit e148cbd

Browse files
committed
Progress on test form, but not complete
1 parent da98925 commit e148cbd

File tree

15 files changed

+387
-119
lines changed

15 files changed

+387
-119
lines changed
Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use client'
22
import React, { useState } from 'react';
3-
import { runTest } from '@/engines';
43
import { TestInput } from '@/types/TestInput';
54
import { TestOutput } from '@/types/TestOutput';
65
import { TestResults } from '@/components/TestResults';
@@ -9,61 +8,127 @@ import OptionsInput from './OptionsInput';
98

109
type TestFormProps = {
1110
engine: RegexEngine;
11+
testInput: TestInput;
1212
}
1313

14-
export default function TestForm({ engine }: TestFormProps) {
15-
const [testOutput, setTestOutput] = useState<TestOutput | null>();
16-
const [testInput, setTestInput] = useState<TestInput | null>();
14+
async function runTest(test_url:string, testInput: TestInput): Promise<TestOutput> {
15+
16+
const postData =
17+
`regex=${encodeURIComponent(testInput.regex)}` +
18+
`&replacement=${encodeURIComponent(testInput.replacement)}` +
19+
`&${testInput.option.map((option) => `option=${option}`).join("&")}` +
20+
`&${testInput.inputs.map((input) => `input=${input}`).join("&")}`;
21+
22+
const response = await fetch(test_url, {
23+
method: "POST",
24+
body: postData,
25+
headers: {
26+
"Content-Type": "application/x-www-form-urlencoded",
27+
},
28+
});
29+
const data = await response.json();
1730

18-
const inputs = ["", "", "", "", ""];
31+
console.log("test results", data);
1932

20-
const inputRows = inputs.map((input, index) => (
33+
return data as TestOutput;
34+
}
35+
36+
export default function TestForm(props: TestFormProps) {
37+
const [testOutput, setTestOutput] = useState<TestOutput | null>();
38+
const [testInput, setTestInput] = useState<TestInput>(props.testInput);
39+
40+
const inputRows = testInput.inputs.map((input, index) => (
2141
<div className="mb-2" key={`key${index}`}>
2242
{index <= 0 ? <label htmlFor={`row${index}`} className="col-sm-2 col-form-label">Inputs</label> : <></> }
2343
<input type="text" className="form-control" id={`input${index}`} name="input" defaultValue={input} />
2444
</div>
2545
));
46+
console.log("render", testInput.inputs);
47+
2648

2749
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
2850
event.preventDefault();
2951
const form = event.currentTarget;
3052
const formData = new FormData(form);
31-
const localInput: TestInput = {
32-
engine: engine.handle,
33-
regex: formData.get('regex') as string,
34-
replacement: formData.get('replacement') as string,
35-
option: formData.getAll('option') as string[],
36-
inputs: formData.getAll('input') as string[]
37-
};
38-
console.log(localInput);
53+
const localInput = formDataToTestInput( props.engine.handle, formData);
54+
console.log(props.engine.test_url, localInput);
3955
setTestInput(localInput);
4056
setTestOutput(null);
41-
setTestOutput(await runTest(engine, formData));
42-
43-
//window.history.pushState(null, "", `/advanced/${engine.handle}/results.html`);
57+
if (props.engine.test_url) {
58+
setTestOutput(await runTest(props.engine.test_url, localInput));
59+
}
4460
};
4561

62+
const onMoreInputs = (event: React.MouseEvent<HTMLButtonElement>) => {
63+
event.preventDefault();
64+
console.log(event);
65+
const form = event.currentTarget.form;
66+
if (!form) {
67+
return;
68+
}
69+
const formData = new FormData(form);
70+
const localInput = formDataToTestInput( props.engine.handle, formData);
71+
console.log("before more", localInput.inputs);
72+
for (let i = 0; i < 3; i++) {
73+
localInput.inputs.push('');
74+
}
75+
console.log("after more", localInput.inputs);
76+
77+
setTestInput(localInput);
78+
}
79+
80+
const onFewerInputs = (event: React.MouseEvent<HTMLButtonElement>) => {
81+
event.preventDefault();
82+
console.log(event);
83+
const form = event.currentTarget.form;
84+
if (!form) {
85+
return;
86+
}
87+
const formData = new FormData(form);
88+
const localInput = formDataToTestInput(props.engine.handle, formData);
89+
console.log("before fewer", localInput.inputs);
90+
localInput.inputs = localInput.inputs.filter(x => x.length > 0);
91+
while (localInput.inputs.length < 5) {
92+
localInput.inputs.push('');
93+
}
94+
setTestInput(localInput);
95+
console.log("after fewer", localInput.inputs);
96+
}
97+
4698
return (
4799
<>
48-
{(testInput ?
100+
{(testInput.regex ?
49101
(testOutput ? <TestResults testOutput={testOutput} /> : <><h2>Results</h2><p>Loading...</p></>)
50102
: <></>)
51103
}
52104
<h2>Expression to test</h2>
53105
<form method="post" action="results.html" onSubmit={onSubmit}>
54106
<div className="mb-3">
55107
<label htmlFor="regex" className="form-label">Regular Expression</label>
56-
<input type="text" className="form-control" id="regex" name="regex" />
108+
<input type="text" className="form-control" id="regex" name="regex" defaultValue={testInput.regex} />
57109
</div>
58110
<div className="mb-3">
59111
<label htmlFor="replacement" className="form-label">Replacement</label>
60-
<input type="text" className="form-control" id="replacement" name="replacement" />
112+
<input type="text" className="form-control" id="replacement" name="replacement" defaultValue={testInput.replacement} />
61113
</div>
62-
{ engine.options.length > 0 ? <OptionsInput engine={engine} options={[]} /> : <></> }
114+
{ props.engine.options.length > 0 ? <OptionsInput engine={props.engine} options={testInput.option} /> : <></> }
63115
<button type="submit" className="btn btn-primary">Test</button>
64116
{inputRows}
65117
<button type="submit" className="btn btn-primary">Test</button>
118+
<button className="ms-3 btn btn-outline-primary" onClick={onMoreInputs}>More inputs</button>
119+
{ testInput.inputs.length > 5 ? <button className="ms-3 btn btn-outline-primary" onClick={onFewerInputs}>Fewer inputs</button> : null }
66120
</form>
67121
</>
68122
);
123+
}
124+
125+
function formDataToTestInput(engineHandle:string, formData: FormData): TestInput {
126+
const retVal: TestInput = {
127+
engine: engineHandle,
128+
regex: formData.get('regex') as string,
129+
replacement: formData.get('replacement') as string,
130+
option: formData.getAll('option') as string[],
131+
inputs: formData.getAll('input') as string[]
132+
};
133+
return retVal;;
69134
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { TestInput } from "@/types/TestInput";
2+
import { TestOutput } from "@/types/TestOutput";
3+
4+
export type TestFormState = {
5+
message?: string;
6+
messageType?: string;
7+
testInput?: TestInput;
8+
testOutput?: TestOutput;
9+
};

src/app/advanced/[engine]/index.html/page.tsx

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { getEngine } from '@/engines';
33
import { ShareLinks } from '@/components/ShareLinks';
44
import { notFound } from 'next/navigation';
55
import TestForm from './TestForm';
6+
//import { testRegexAction } from './testRegexAction';
7+
//import OptionsInput from './OptionsInput';
8+
import { TestInput } from '@/types/TestInput';
69

710
export async function generateMetadata({ params }: { params: { engine: string } }) {
811
const engine = getEngine(params.engine);
@@ -33,6 +36,38 @@ export default function Page({ params }: { params: { engine: string } }) {
3336
</div>;
3437
}
3538

39+
const testInput:TestInput = {
40+
engine: engine.handle,
41+
regex: '',
42+
replacement: '',
43+
option: [],
44+
inputs: ["", "", "", "", ""],
45+
}
46+
47+
return (
48+
<>
49+
<div className="d-flex justify-content-between align-items-center">
50+
<h1>{engine.short_name} Regular Expression Test Page</h1>
51+
<a className="btn btn-success" href={engine.help_url} target="_blank">{engine.help_label}</a>
52+
</div>
53+
<ShareLinks url={`https://regexplanet.com/advanced/${engine.handle}/index.html`} text={`Test your ${engine.short_name} regular expression`} />
54+
<hr />
55+
{flash}
56+
<TestForm engine={engine} testInput={testInput} />
57+
</>
58+
);
59+
/*
60+
const testRegexEngineAction = testRegexAction.bind(null, engine.handle);
61+
62+
const inputs = ["", "", "", "", ""];
63+
64+
const inputRows = inputs.map((input, index) => (
65+
<div className="mb-2" key={`key${index}`}>
66+
{index <= 0 ? <label htmlFor={`row${index}`} className="col-sm-2 col-form-label">Inputs</label> : <></>}
67+
<input type="text" className="form-control" id={`input${index}`} name="input" defaultValue={input} />
68+
</div>
69+
));
70+
3671
return (
3772
<>
3873
<div className="d-flex justify-content-between align-items-center">
@@ -42,7 +77,22 @@ export default function Page({ params }: { params: { engine: string } }) {
4277
<ShareLinks url={`https://regexplanet.com/advanced/${engine.handle}/index.html`} text={`Test your ${engine.short_name} regular expression`} />
4378
<hr />
4479
{flash}
45-
<TestForm engine={engine} />
80+
<h2>Expression to test</h2>
81+
<form method="post" action={testRegexEngineAction}>
82+
<div className="mb-3">
83+
<label htmlFor="regex" className="form-label">Regular Expression</label>
84+
<input type="text" className="form-control" id="regex" name="regex" />
85+
</div>
86+
<div className="mb-3">
87+
<label htmlFor="replacement" className="form-label">Replacement</label>
88+
<input type="text" className="form-control" id="replacement" name="replacement" />
89+
</div>
90+
{engine.options.length > 0 ? <OptionsInput engine={engine} options={[]} /> : <></>}
91+
<button type="submit" className="btn btn-primary">Test</button>
92+
{inputRows}
93+
<button type="submit" className="btn btn-primary">Test</button>
94+
</form>
4695
</>
4796
);
97+
*/
4898
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { getEngineOrThrow } from "@/engines"
2+
import { TestInput } from "@/types/TestInput";
3+
import { TestOutput } from "@/types/TestOutput";
4+
5+
export async function testRegexAction(engineHandle: string, formData: FormData) {
6+
'use server'
7+
8+
const theEngine = getEngineOrThrow(engineHandle)
9+
if (!theEngine.test_url) {
10+
throw new Error('Engine does not support testing');
11+
}
12+
13+
const testInput:TestInput = {
14+
engine: engineHandle,
15+
regex: formData.get('regex') as string,
16+
replacement: formData.get('replacement') as string,
17+
option: formData.getAll('option') as string[],
18+
inputs: formData.getAll('input') as string[],
19+
}
20+
21+
const testOutput:TestOutput = { success: false, message: `Not implemented ${JSON.stringify(testInput)}` };
22+
23+
return testOutput;
24+
}

src/app/advanced/[engine]/results.html/route.ts

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ import { TestOutput } from "@/types/TestOutput";
33
import { NextRequest } from "next/server";
44
//import { renderToStaticMarkup, renderToString } from "react-dom/server";
55
import { postpage } from "./postpage";
6-
import { getEngine, runTest } from "@/engines";
7-
import { notFound } from "next/navigation";
8-
9-
6+
import { getEngine } from "@/engines";
7+
import { notFound, redirect } from "next/navigation";
108

119
async function renderPage(
1210
engine: string,
@@ -24,48 +22,27 @@ export async function GET(
2422
request: Request,
2523
{ params }: { params: { engine: string } }
2624
) {
27-
const engine = getEngine(params.engine);
28-
if (!engine) {
29-
return notFound();
30-
}
31-
32-
const testInput = {
33-
engine: engine.handle,
34-
regex: "test",
35-
replacement: "test",
36-
option: [],
37-
inputs: ["test"],
38-
};
39-
40-
/*
41-
const rawItem = request.url;
42-
if (!rawItem) {
43-
return new Response("No test input", {
44-
status: 400,
45-
});
25+
const engine = getEngine(params.engine);
26+
if (!engine) {
27+
return notFound();
4628
}
47-
const testInput = JSON.parse(rawItem) as TestInput;
48-
*/
49-
const formData = new FormData();
50-
formData.set("regex", testInput.regex);
5129

52-
const testOutput = runTest(engine, formData);
53-
54-
const html = JSON.stringify(testOutput);
55-
56-
return new Response(html, {
57-
status: 200,
58-
});
30+
redirect("/advanced/${engine.handle}/results.html");
5931
}
6032

6133
export async function POST(
6234
request: NextRequest,
6335
{ params }: { params: { engine: string } }
6436
) {
65-
const engine = getEngine(params.engine);
66-
if (!engine) {
67-
return notFound();
68-
}
37+
const engine = getEngine(params.engine);
38+
if (!engine) {
39+
return notFound();
40+
}
41+
if (!engine.test_url) {
42+
return new Response("Engine does not support testing", {
43+
status: 400,
44+
});
45+
}
6946

7047
const rawData = await request.formData();
7148

@@ -77,14 +54,15 @@ export async function POST(
7754
inputs: (rawData.getAll("input") || []) as string[],
7855
};
7956

80-
const testOutput = await runTest(engine, rawData);
57+
const response = await fetch(engine.test_url);//(testInput);
58+
const testOutput = await response.json() as TestOutput;
8159

8260
const html = await renderPage(engine.handle, "post", testInput, testOutput);
8361

8462
return new Response(html, {
8563
status: 200,
8664
headers: {
87-
"Content-Type": "text/html"
65+
"Content-Type": "text/html",
8866
},
8967
});
9068
}

src/app/status.html/ResultsTable.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import fetchJsonp from 'fetch-jsonp';
88
import { EngineStatus } from '@/types/EngineStatus';
99

1010

11-
function getHost(test_url: string|undefined) {
12-
if (!test_url) {
11+
function getHost(status_url: string|undefined) {
12+
if (!status_url) {
1313
return <i>(not configured)</i>
1414
}
15-
const urlObj = new URL(test_url);
15+
const urlObj = new URL(status_url);
1616
if (urlObj.host.endsWith(".gcr.regexplanet.com")) {
1717
return <Link href="https://cloud.google.com/run/">Cloud Run</Link>;
1818
}
@@ -163,7 +163,7 @@ export function ResultsTable() {
163163
<Link href={`/advanced/${engine.handle}/index.html`} >{engine.short_name}</Link>
164164
</td>
165165
{EngineStatusColumns(results[index])}
166-
<td className="d-none d-lg-table-cell">{getHost(engine.test_url)}</td>
166+
<td className="d-none d-lg-table-cell">{getHost(engine.status_url)}</td>
167167
</tr>
168168
))}
169169
</tbody>

0 commit comments

Comments
 (0)