Make odoApp in waspc compatible with TypeScript (#960)

This commit is contained in:
Filip Sodić 2023-01-19 15:19:11 +01:00 committed by GitHub
parent b0c20a1f6d
commit 68c7d03814
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 217 additions and 87 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useState, FormEventHandler, ChangeEventHandler } from 'react'
import { Link } from 'react-router-dom'
import { useQuery } from '@wasp/queries'
@ -9,13 +9,27 @@ import updateTaskIsDone from '@wasp/actions/updateTaskIsDone.js'
import deleteCompletedTasks from '@wasp/actions/deleteCompletedTasks.js'
import toggleAllTasks from '@wasp/actions/toggleAllTasks.js'
const Todo = (props) => {
const { data: tasks, isError, error: tasksError } = useQuery(getTasks)
// Copied from Prisma
type Task = {
id: number
description: string
isDone: boolean
userId: number
}
const isThereAnyTask = () => tasks?.length > 0
type GetTasksError = { message: string }
const TasksError = (props) => {
return 'Error during fetching tasks: ' + (tasksError?.message || '')
type NonEmptyArray<T> = [T, ...T[]]
function areThereAnyTasks(tasks: Task[] | undefined): tasks is NonEmptyArray<Task> {
return !!(tasks && tasks.length > 0)
}
const Todo = () => {
const { data: tasks, isError, error: tasksError } = useQuery<{}, Task[], GetTasksError>(getTasks)
const TasksError = () => {
return <div>{'Error during fetching tasks: ' + (tasksError?.message || '')}</div>
}
return (
@ -24,13 +38,13 @@ const Todo = (props) => {
<h1>Todos</h1>
<div className='flex justify-start'>
<ToggleAllTasksButton disabled={!isThereAnyTask()} />
<ToggleAllTasksButton disabled={!areThereAnyTasks(tasks)} />
<NewTaskForm />
</div>
{isError && <TasksError />}
{isThereAnyTask() && (
{areThereAnyTasks(tasks) && (
<>
<Tasks tasks={tasks} />
@ -42,9 +56,9 @@ const Todo = (props) => {
)
}
const Footer = (props) => {
const numCompletedTasks = props.tasks.filter(t => t.isDone).length
const numUncompletedTasks = props.tasks.filter(t => !t.isDone).length
const Footer = ({ tasks }: { tasks: NonEmptyArray<Task> }) => {
const numCompletedTasks = tasks.filter(t => t.isDone).length
const numUncompletedTasks = tasks.filter(t => !t.isDone).length
const handleDeleteCompletedTasks = async () => {
try {
@ -72,33 +86,35 @@ const Footer = (props) => {
)
}
const Tasks = (props) => {
const Tasks = ({ tasks }: { tasks: NonEmptyArray<Task> }) => {
return (
<div>
<table className='border-separate border-spacing-2'>
<tbody>
{props.tasks.map((task, idx) => <Task task={task} key={idx} />)}
</tbody>
</table>
<table className='border-separate border-spacing-2'>
<tbody>
{tasks.map((task, idx) => <Task task={task} key={idx} />)}
</tbody>
</table>
</div>
)
}
const Task = (props) => {
const updateTaskIsDoneOptimistically = useAction(updateTaskIsDone, {
type UpdateTaskIsDonePayload = Pick<Task, "id" | "isDone">
const Task = ({ task }: { task: Task }) => {
const updateTaskIsDoneOptimistically = useAction<UpdateTaskIsDonePayload, void, Task[]>(updateTaskIsDone, {
optimisticUpdates: [{
getQuerySpecifier: () => [getTasks],
updateQuery: (updatedTask, oldTasks) => {
if (oldTasks === undefined) {
// cache is empty
return [updatedTask];
return [{ ...task, ...updatedTask }];
} else {
return oldTasks.map(task => task.id === updatedTask.id ? { ...task, ...updatedTask } : task)
}
}
}]
});
const handleTaskIsDoneChange = async (event) => {
const handleTaskIsDoneChange: ChangeEventHandler<HTMLInputElement> = async (event) => {
const id = parseInt(event.target.id)
const isDone = event.target.checked
@ -114,29 +130,29 @@ const Task = (props) => {
<td>
<input
type='checkbox'
id={String(props.task.id)}
checked={props.task.isDone}
id={String(task.id)}
checked={task.isDone}
onChange={handleTaskIsDoneChange}
color='default'
/>
</td>
<td>
<Link to={`/task/${props.task.id}`}> {props.task.description} </Link>
<Link to={`/task/${task.id}`}> {task.description} </Link>
</td>
</tr>
)
}
const NewTaskForm = (props) => {
const NewTaskForm = () => {
const defaultDescription = ''
const [description, setDescription] = useState(defaultDescription)
const createNewTask = async (description) => {
const createNewTask = async (description: Task['description']) => {
const task = { isDone: false, description }
await createTask(task)
}
const handleNewTaskSubmit = async (event) => {
const handleNewTaskSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
event.preventDefault()
try {
await createNewTask(description)
@ -161,7 +177,7 @@ const NewTaskForm = (props) => {
)
}
const ToggleAllTasksButton = (props) => {
const ToggleAllTasksButton = ({ disabled }: { disabled: boolean }) => {
const handleToggleAllTasks = async () => {
try {
await toggleAllTasks()
@ -173,7 +189,7 @@ const ToggleAllTasksButton = (props) => {
return (
<button
className='btn btn-blue'
disabled={props.disabled}
disabled={disabled}
onClick={handleToggleAllTasks}
>

View File

@ -1,27 +0,0 @@
{
"compilerOptions": {
// The following settings enable IDE support in user-provided source files.
// Editing them might break features like import autocompletion and
// definition lookup. Don't change them unless you know what you're doing.
//
// The relative path to the generated web app's root directory. This must be
// set to define the "paths" option.
"baseUrl": "../../.wasp/out/web-app/",
"paths": {
// Resolve all "@wasp" imports to the generated source code.
"@wasp/*": [
"src/*"
],
// Resolve all non-relative imports to the correct node module. Source:
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
"*": [
// Start by looking for the definiton inside the node modules root
// directory...
"node_modules/*",
// ... If that fails, try to find it inside definitely-typed type
// definitions.
"node_modules/@types/*"
]
}
}
}

View File

@ -1,7 +1,7 @@
import React from 'react'
import logout from '@wasp/auth/logout.js'
import Todo from '../Todo.js'
import Todo from '../Todo'
import '../Main.css'
const Main = () => {

View File

@ -0,0 +1,60 @@
declare module '*.avif' {
const src: string;
export default src;
}
declare module '*.bmp' {
const src: string;
export default src;
}
declare module '*.gif' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.webp' {
const src: string;
export default src;
}
declare module '*.svg' {
import * as React from 'react';
export const ReactComponent: React.FunctionComponent<React.SVGProps<
SVGSVGElement
> & { title?: string }>;
const src: string;
export default src;
}
declare module '*.module.css' {
const classes: { readonly [key: string]: string };
export default classes;
}
declare module '*.module.scss' {
const classes: { readonly [key: string]: string };
export default classes;
}
declare module '*.module.sass' {
const classes: { readonly [key: string]: string };
export default classes;
}

View File

@ -0,0 +1,55 @@
// =============================== IMPORTANT =================================
//
// This file is only used for Wasp IDE support. You can change it to configure
// your IDE checks, but none of these options will affect the TypeScript
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
{
"compilerOptions": {
// JSX support
"jsx": "preserve",
"strict": true,
// Allow default imports.
"esModuleInterop": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
// Wasp needs the following settings enable IDE support in your source
// files. Editing them might break features like import autocompletion and
// definition lookup. Don't change them unless you know what you're doing.
//
// The relative path to the generated web app's root directory. This must be
// set to define the "paths" option.
"baseUrl": "../../.wasp/out/web-app/",
"paths": {
// Resolve all "@wasp" imports to the generated source code.
"@wasp/*": [
"src/*"
],
// Resolve all non-relative imports to the correct node module. Source:
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
"*": [
// Start by looking for the definiton inside the node modules root
// directory...
"node_modules/*",
// ... If that fails, try to find it inside definitely-typed type
// definitions.
"node_modules/@types/*"
]
},
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
"typeRoots": [
"../../.wasp/out/web-app/node_modules/@types"
],
// Since this TS config is used only for IDE support and not for
// compilation, the following directory doesn't exist. We need to specify
// it to prevent this error:
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
"outDir": "phantom"
},
"exclude": [
"phantom"
],
}

View File

@ -1,27 +0,0 @@
{
"compilerOptions": {
// The following settings enable IDE support in user-provided source files.
// Editing them might break features like import autocompletion and
// definition lookup. Don't change them unless you know what you're doing.
//
// The relative path to the generated web app's root directory. This must be
// set to define the "paths" option.
"baseUrl": "../../.wasp/out/server/",
"paths": {
// Resolve all "@wasp" imports to the generated source code.
"@wasp/*": [
"src/*"
],
// Resolve all non-relative imports to the correct node module. Source:
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
"*": [
// Start by looking for the definiton inside the node modules root
// directory...
"node_modules/*",
// ... If that fails, Try to find it inside definitely-typed type
// definitions.
"node_modules/@types/*"
]
}
}
}

View File

@ -0,0 +1,48 @@
// =============================== IMPORTANT =================================
//
// This file is only used for Wasp IDE support. You can change it to configure
// your IDE checks, but none of these options will affect the TypeScript
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
{
"compilerOptions": {
// Allows default imports.
"esModuleInterop": true,
"allowJs": true,
"strict": true,
// Wasp needs the following settings enable IDE support in your source
// files. Editing them might break features like import autocompletion and
// definition lookup. Don't change them unless you know what you're doing.
//
// The relative path to the generated web app's root directory. This must be
// set to define the "paths" option.
"baseUrl": "../../.wasp/out/server/",
"paths": {
// Resolve all "@wasp" imports to the generated source code.
"@wasp/*": [
"src/*"
],
// Resolve all non-relative imports to the correct node module. Source:
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
"*": [
// Start by looking for the definiton inside the node modules root
// directory...
"node_modules/*",
// ... If that fails, try to find it inside definitely-typed type
// definitions.
"node_modules/@types/*"
]
},
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
"typeRoots": [
"../../.wasp/out/server/node_modules/@types"
],
// Since this TS config is used only for IDE support and not for
// compilation, the following directory doesn't exist. We need to specify
// it to prevent this error:
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
"outDir": "phantom",
},
"exclude": [
"phantom"
],
}

View File

@ -1,12 +1,15 @@
{
"compilerOptions": {
// Enable default imports in TypeScript.
"esModuleInterop": true,
"allowJs": true,
// The following settings enable IDE support in user-provided source files.
// Editing them might break features like import autocompletion and
// definition lookup. Don't change them unless you know what you're doing.
//
// The relative path to the generated web app's root directory. This must be
// set to define the "paths" option.
"baseUrl": "../../.wasp/out/server",
"baseUrl": "../../.wasp/out/server/",
"paths": {
// Resolve all non-relative imports to the correct node module. Source:
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
@ -18,6 +21,8 @@
// definitions.
"node_modules/@types/*"
]
}
},
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
"typeRoots": ["../../.wasp/out/server/node_modules/@types"]
}
}

View File

@ -29,7 +29,7 @@ app todoApp {
setupFn: import setup from "@server/serverSetup.js"
},
client: {
setupFn: import setup from "@client/clientSetup.js"
setupFn: import setup from "@client/clientSetup"
},
db: {
system: PostgreSQL