Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions assembly/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,17 @@
<phase>prepare-package</phase>
<configuration>
<target>
<!-- Replace hybrid view route in Flow only starter -->
<replace token="task-list-flow" value="task-list" dir="target/generated-sources/flow">
<!-- Replace Flow view route in Flow only starter -->
<replace token="task-list-flow" value="" dir="target/generated-sources/flow">
<include name="**/TaskListView.java"/>
</replace>
<!-- Replace hybrid view name in Flow only starter -->
<!-- Replace Flow view name in Flow only starter -->
<replace token="Task List Flow" value="Task List" dir="target/generated-sources/flow">
<include name="**/TaskListView.java"/>
</replace>
<!-- Replace hybrid view name in Hilla only starter -->
<replace token="Task List Hilla" value="Task List" dir="target/generated-sources/hilla-frontend">
<include name="**/task-list.tsx"/>
<include name="**/@index.tsx"/>
</replace>
</target>
</configuration>
Expand Down
2 changes: 1 addition & 1 deletion assembly/src/assembly/empty-skeleton.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<exclude>src/main/frontend/index.tsx</exclude>
<exclude>src/main/java/**</exclude>
<exclude>src/main/resources/META-INF/**</exclude>
<exclude>src/test/java/com/example/application/taskmanagement/**</exclude>
<exclude>src/test/**</exclude>
</excludes>
</fileSet>
<fileSet>
Expand Down
2 changes: 1 addition & 1 deletion assembly/src/assembly/hilla-skeleton.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<directory>${basedir}/target/generated-sources/hilla</directory>
<excludes>
<exclude>com/example/application/base/**</exclude>
<exclude>com/example/application/taskmanagement/ui/**</exclude>
<exclude>com/example/application/examplefeature/ui/**</exclude>
</excludes>
</fileSet>
<fileSet>
Expand Down
51 changes: 51 additions & 0 deletions walking-skeleton/README-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,64 @@

- [ ] TODO Replace or update this README with instructions relevant to your application

## Project Structure

The sources of your Walking Skeleton have the following structure:

```
src
├── main/frontend
│ └── themes
│ └── default
│ ├── styles.css
│ └── theme.json
├── main/java
│ └── [application package]
│ ├── base
│ │ └── ui
│ │ ├── component
│ │ │ └── ViewToolbar.java
│ │ ├── MainErrorHandler.java
│ │ └── MainLayout.java
│ ├── examplefeature
│ │ ├── ui
│ │ │ └── TaskListView.java
│ │ ├── Task.java
│ │ ├── TaskRepository.java
│ │ └── TaskService.java
│ └── Application.java
└── test/java
└── [application package]
└── examplefeature
└── TaskServiceTest.java
```

The main entry point into the application is `Application.java`. This class contains the `main()` method that start up
the Spring Boot application.

The skeleton follows a *feature-based package structure*, organizing code by *functional units* rather than traditional
architectural layers. It includes two feature packages: `base` and `examplefeature`.

* The `base` package contains classes meant for reuse across different features, either through composition or
inheritance. You can use them as-is, tweak them to your needs, or remove them.
* The `examplefeature` package is an example feature package that demonstrates the structure. It represents a
*self-contained unit of functionality*, including UI components, business logic, data access, and an integration test.
Once you create your own features, *you'll remove this package*.

The `src/main/frontend` directory contains an empty theme called `default`, based on the Lumo theme. It is activated in
the `Application` class, using the `@Theme` annotation.

## Starting in Development Mode

To start the application in development mode, import it into your IDE and run the `Application` class.
You can also start the application from the command line by running:

```bash
./mvnw
```

## Building for Production

To build the application in production mode, run:

```bash
Expand Down
52 changes: 52 additions & 0 deletions walking-skeleton/README-hilla.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,65 @@

- [ ] TODO Replace or update this README with instructions relevant to your application

## Project Structure

The sources of your Walking Skeleton have the following structure:

```
src
├── main/frontend
│ ├── components
│ │ └── ViewToolbar.tsx
│ ├── themes
│ │ └── default
│ │ ├── styles.css
│ │ └── theme.json
│ └── views
│ ├── @index.tsx
│ ├── @layout.tsx
│ └── _ErrorHandler.ts
├── main/java
│ └── [application package]
│ ├── examplefeature
│ │ ├── Task.java
│ │ ├── TaskRepository.java
│ │ └── TaskService.java
│ └── Application.java
└── test/java
└── [application package]
└── examplefeature
└── TaskServiceTest.java
```

The main entry point into the application is `Application.java`. This class contains the `main()` method that start up
the Spring Boot application.

The skeleton follows a *feature-based package structure*, organizing code by *functional units* rather than traditional
architectural layers. It includes one example feature package - `examplefeature` - that demonstrates the structure. It
represents a *self-contained unit of functionality*, including business logic, data access, and an integration test.
Once you create your own features, *you'll remove this package*.

The `src/main/frontend` directory contains the following:

* a `ViewToolbar` component that you can reuse in your application.
* an empty theme called `default`, based on the Lumo theme. It is activated in the `Application` class, using the
`@Theme` annotation.
* an example view `@index.tsx` that communicates with the `TaskService`. Once you create your own features,
*you'll replace this*.
* a main layout `@layout.tsx` that you can reuse and expand in your application.
* an `_ErrorHandler.ts` that you can reuse in your application.

## Starting in Development Mode

To start the application in development mode, import it into your IDE and run the `Application` class.
You can also start the application from the command line by running:

```bash
./mvnw
```

## Building for Production

To build the application in production mode, run:

```bash
Expand Down
97 changes: 81 additions & 16 deletions walking-skeleton/src/main/frontend/views/@index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,92 @@
// TODO Replace with your own main view.

import { ViewConfig } from '@vaadin/hilla-file-router/types.js';
import { Icon } from '@vaadin/react-components';
import { ViewToolbar } from 'Frontend/components/ViewToolbar';
import { Button, DatePicker, Grid, GridColumn, TextField } from '@vaadin/react-components';
import { Notification } from '@vaadin/react-components/Notification';
import { TaskService } from 'Frontend/generated/endpoints';
import { useSignal } from '@vaadin/hilla-react-signals';
import handleError from 'Frontend/views/_ErrorHandler';
import { Group, ViewToolbar } from 'Frontend/components/ViewToolbar';
import { useGridDataProvider } from '@vaadin/hilla-react-crud';

export const config: ViewConfig = {
title: 'Task List Hilla',
menu: {
icon: 'vaadin:home',
order: -100,
title: 'Welcome!',
icon: 'vaadin:clipboard-check',
order: 1,
title: 'Task List Hilla',
},
};

export default function MainView() {
const dateTimeFormatter = new Intl.DateTimeFormat(undefined, {
dateStyle: 'medium',
timeStyle: 'medium',
});

const dateFormatter = new Intl.DateTimeFormat(undefined, {
dateStyle: 'medium',
});

type TaskEntryFormProps = {
onTaskCreated?: () => void;
};

function TaskEntryForm(props: TaskEntryFormProps) {
const description = useSignal('');
const dueDate = useSignal<string | undefined>('');
const createTask = async () => {
try {
await TaskService.createTask(description.value, dueDate.value);
if (props.onTaskCreated) {
props.onTaskCreated();
}
description.value = '';
dueDate.value = undefined;
Notification.show('Task added', { duration: 3000, position: 'bottom-end', theme: 'success' });
} catch (error) {
handleError(error);
}
};
return (
<>
<TextField
placeholder="What do you want to do?"
aria-label="Task description"
maxlength={255}
style={{ minWidth: '20em' }}
value={description.value}
onValueChanged={(evt) => (description.value = evt.detail.value)}
/>
<DatePicker
placeholder="Due date"
aria-label="Due date"
value={dueDate.value}
onValueChanged={(evt) => (dueDate.value = evt.detail.value)}
/>
<Button onClick={createTask} theme="primary">
Create
</Button>
</>
);
}

export default function TaskListView() {
const dataProvider = useGridDataProvider(TaskService.list);

return (
<main className="p-m flex flex-col box-border w-full h-full">
<ViewToolbar title="Welcome to Vaadin!" />
<div className="flex-grow flex flex-col items-center justify-center">
<div className="flex flex-col items-center">
<Icon src="icons/construction.svg" className="text-success" style={{ width: '200px', height: '200px' }} />
<p>Replace this view with your own main view!</p>
</div>
</div>
<main className="w-full h-full flex flex-col box-border gap-s p-m">
<ViewToolbar title="Task List Hilla">
<Group>
<TaskEntryForm onTaskCreated={dataProvider.refresh} />
</Group>
</ViewToolbar>
<Grid dataProvider={dataProvider}>
<GridColumn path="description" />
<GridColumn path="dueDate" header="Due Date">
{({ item }) => (item.dueDate ? dateFormatter.format(new Date(item.dueDate)) : 'Never')}
</GridColumn>
<GridColumn path="creationDate" header="Creation Date">
{({ item }) => dateTimeFormatter.format(new Date(item.creationDate))}
</GridColumn>
</Grid>
</main>
);
}
92 changes: 0 additions & 92 deletions walking-skeleton/src/main/frontend/views/task-list.tsx

This file was deleted.

Loading