Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fusion views (part 1) #1

Merged
merged 44 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ea536a3
Update .gitignore
Haprog Sep 17, 2021
dc9e9c3
Commit vaadin-maven-plugin generated files
Haprog Sep 17, 2021
2106a44
Add a Vaadin Fusion based hello-world view and theme
Haprog Sep 16, 2021
7f51889
Ignore frontend/generated/ from Checkstyle NoHttp check
Haprog Sep 17, 2021
3057c32
Fix regex in nohttp-checkstyle-suppressions.xml
Haprog Sep 17, 2021
8523a89
Ignore some IntelliJ IDEA files from Checkstyle NoHttp check
Haprog Sep 17, 2021
d5001ce
Update .editorconfig
Haprog Sep 17, 2021
505f181
Fix indentation in TS files to 2 spaces
Haprog Sep 17, 2021
08ca19a
Add a blank Home view to Fusion and cross-link home views between Fus…
Haprog Sep 17, 2021
2fcf365
Use top navigation in Fusion views
Haprog Sep 17, 2021
e40ef80
Add custom index.html for Fusion
Haprog Sep 17, 2021
d6b2a95
Add a Fusion based VetsView
Haprog Sep 18, 2021
2d3c16e
Add a Fusion based ErrorView
Haprog Sep 20, 2021
00cccef
Update Home page
Haprog Sep 20, 2021
3eab582
Add a footer to the Fusion main-layout
Haprog Sep 20, 2021
9901544
Improve styling and add menu icons
Haprog Sep 20, 2021
e0192ae
Fix original icons
Haprog Sep 20, 2021
b0469d4
Remove dummy hello-world-view
Haprog Sep 20, 2021
ee59a2c
Refactor data fetching in VetsView
Haprog Sep 22, 2021
c1e8c56
Add OwnerEndpoint
Haprog Sep 22, 2021
23d0b2b
Add some owner views
Haprog Sep 22, 2021
1b50634
Refactor
Haprog Sep 23, 2021
0c8a0b7
Add CreateOrUpdateOwnerView (WIP)
Haprog Sep 23, 2021
25cf407
Update VetsView to use vaadin-grid with sorting
Haprog Sep 24, 2021
2037fad
Update OwnersListView to use vaadin-grid with sorting
Haprog Sep 24, 2021
da0f131
Add scope to @JsonIdentityInfo
Haprog Sep 25, 2021
5512a8d
Update routing
Haprog Sep 25, 2021
6e82adf
Implement OwnerDetailsView
Haprog Sep 25, 2021
c33be52
Implement CreateOrUpdateOwnerView using Binder
Haprog Sep 25, 2021
5a826ca
Fix main-layout styles
Haprog Sep 25, 2021
7719c69
Add type RouterLocationChangedEvent in index.ts
Haprog Sep 25, 2021
4f0e663
Highlight "Find owners" in nav within all owner views
Haprog Sep 25, 2021
052de03
Remove unnecessary type RouteInfo
Haprog Sep 28, 2021
842911a
Remove unnecessary Readonly
Haprog Sep 28, 2021
289c80b
Simplify OwnerEndpoint save method
Haprog Sep 28, 2021
696f9b5
Add error handling to saving owner data
Haprog Sep 28, 2021
f2f4c36
Remove unnecessary @Autowired annotation
Haprog Sep 28, 2021
0492f68
Remove unnecessary use of "this." from new endpoints
Haprog Sep 28, 2021
9d57820
Refactor OwnersListView
Haprog Sep 28, 2021
e92e4cf
Use short syntax for array types in TS
Haprog Sep 28, 2021
eba98ec
Simplify VetsView specialtiesRenderer
Haprog Sep 28, 2021
cdc437f
Prefer connectedCallback for loading data when entering view
Haprog Sep 29, 2021
4397135
Refactor FindOwnersView
Haprog Sep 29, 2021
897ba6c
Trigger find on Enter key in FindOwnersView
Haprog Sep 29, 2021
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
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ tab_width = 4
indent_size = 2
indent_style = space

[*.{html,sql,less}]
[*.{html,sql,less,css,js,ts}]
indent_size = 2
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ target/*
.attach_pid*
.idea
*.iml
*.ipr
*.iws
/target
.sts4-cache/
.vscode
_site/

# The following files are generated/updated by vaadin-maven-plugin
node_modules/
frontend/generated/
pnpmfile.js
webpack.generated.js
6 changes: 6 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# NOTICE: this is an auto-generated file
#
# This file sets the default parameters for manual `pnpm install`.
#
shamefully-hoist=true
31 changes: 31 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<html lang="en">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="shortcut icon" type="image/x-icon" href="/resources/images/favicon.png">

<title>PetClinic :: a Spring Framework demonstration</title>

<style>
body, #outlet {
height: 100vh;
width: 100%;
margin: 0;
}
body {
background-color: #f1f1f1;
}
</style>
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
</head>
<body>
<!-- vaadin-router in index.ts needs an outlet for displaying the views -->
<div id="outlet"></div>
</body>
</html>
25 changes: 25 additions & 0 deletions frontend/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Router, RouterLocation } from '@vaadin/router';
import { routes } from './routes';
import { appStore } from './stores/app-store';

export const router = new Router(document.querySelector('#outlet'));

router.setRoutes(routes);

type RouterLocationChangedEvent = CustomEvent<{
marcushellberg marked this conversation as resolved.
Show resolved Hide resolved
router: Router;
location: RouterLocation;
}>;

window.addEventListener(
'vaadin-router-location-changed',
(e: RouterLocationChangedEvent) => {
appStore.setLocation(e.detail.location);
const title = appStore.currentViewTitle;
if (title) {
document.title = title + ' | ' + appStore.applicationName;
} else {
document.title = appStore.applicationName;
}
}
);
108 changes: 108 additions & 0 deletions frontend/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Route } from '@vaadin/router';
import './views/error-view';
import './views/home-view';
import './views/main-layout';
import './views/owners/create-or-update-owner-view';
import './views/owners/find-owners-view';
import './views/owners/owners-list-view';
import './views/owners/owner-details-view';
import './views/vets-view';

export type ViewRoute = Route & {
title?: string;
icon?: string;
children?: ViewRoute[];
};

export const views: ViewRoute[] = [
// place routes below (more info https://vaadin.com/docs/latest/fusion/routing/overview)
{
path: '/',
component: 'home-view',
icon: '',
title: '',
},
{
path: '/home-fusion',
name: 'home',
component: 'home-view',
icon: 'la la-home',
title: 'Home',
},
{
// Included on root level to include in navigation menu. Otherwise this
// could be as a child of the '/owners-fusion' item below.
path: '/owners-fusion/find',
name: 'find-owners',
component: 'find-owners-view',
icon: 'la la-search',
title: 'Find owners',
},
{
path: '/owners-fusion',
name: 'owners-base',
children: [
{
path: '/',
name: 'owners-list',
component: 'owners-list-view',
},
{
path: '/new',
name: 'new-owner',
component: 'create-or-update-owner-view',
},
{
path: '/([0-9]+)',
children: [
{
path: '/',
name: 'owner-details',
component: 'owner-details-view',
},
{
path: '/edit',
name: 'edit-owner',
component: 'create-or-update-owner-view',
},
{
path: '/pets/new',
name: 'add-pet',
component: '',
},
{
path: '/pets/([0-9]+)/edit',
name: 'edit-pet',
component: '',
},
{
path: '/pets/([0-9]+)/visits/new',
name: 'add-visit',
component: '',
},
],
},
],
},
{
path: '/vets-fusion',
name: 'vets-list',
component: 'vets-view',
icon: 'la la-th-list',
title: 'Veterinarians',
},
{
path: '/error-fusion',
component: 'error-view',
icon: 'la la-exclamation-triangle',
title: 'Error',
},
];

export const routes: ViewRoute[] = [
{
path: '/',
component: 'main-layout',
children: [...views],
},
];
27 changes: 27 additions & 0 deletions frontend/stores/app-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RouterLocation } from '@vaadin/router';
import { makeAutoObservable } from 'mobx';

export class AppStore {
applicationName = 'Fusion PetClinic';

// The location, relative to the base path, e.g. "hello" when viewing "/hello"
location = '';

currentViewTitle = '';

constructor() {
makeAutoObservable(this);
}

setLocation(location: RouterLocation) {
if (location.route) {
this.location = location.route.path;
} else if (location.pathname.startsWith(location.baseUrl)) {
this.location = location.pathname.substr(location.baseUrl.length);
} else {
this.location = location.pathname;
}
this.currentViewTitle = (location?.route as any)?.title || '';
}
}
export const appStore = new AppStore();
36 changes: 36 additions & 0 deletions frontend/themes/petclinic/main-layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[slot='navbar'] {
background-image: linear-gradient(0deg, var(--lumo-shade-5pct), var(--lumo-shade-5pct));
}

[slot='navbar'] nav a {
text-decoration: none;
transition: color 140ms;
}

[slot='navbar'] nav a .la {
margin-top: calc(var(--lumo-space-xs) * 0.5);
}

[slot='navbar'] nav a::before {
border-radius: var(--lumo-border-radius);
bottom: calc(var(--lumo-space-xs) * 0.5);
content: '';
left: 0;
position: absolute;
right: 0;
top: calc(var(--lumo-space-xs) * 0.5);
transition: background-color 140ms;
}

[slot='navbar'] nav a[highlight] {
color: var(--lumo-primary-text-color);
}

[slot='navbar'] nav a[highlight]::before {
background-color: var(--lumo-primary-color-10pct);
}

[slot='navbar'] footer vaadin-context-menu {
align-items: center;
display: flex;
}
2 changes: 2 additions & 0 deletions frontend/themes/petclinic/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import url('./main-layout.css');
@import url('line-awesome/dist/line-awesome/css/line-awesome.min.css');
1 change: 1 addition & 0 deletions frontend/themes/petclinic/theme.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"lumoImports":["typography","color","spacing","badge","utility"]}
23 changes: 23 additions & 0 deletions frontend/views/error-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { View } from '../views/view';
import { CrashEndpoint } from 'Frontend/generated/endpoints';

@customElement('error-view')
export class ErrorView extends View {
@state()
result?: string;

async firstUpdated(changedProperties: any) {
super.firstUpdated(changedProperties);

this.result = await CrashEndpoint.triggerException();
marcushellberg marked this conversation as resolved.
Show resolved Hide resolved
}

render() {
return html`
<p>See JS console for errors.</p>
<p>For more information see the Fusion <a href="https://vaadin.com/docs/latest/fusion/application/error-handling">Error Handling</a> documentation.</p>
`;
}
}
17 changes: 17 additions & 0 deletions frontend/views/home-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { View } from '../views/view';

@customElement('home-view')
export class HomeView extends View {
render() {
return html`
<h2>Welcome</h2>
<div class="row">
<div class="col-md-12">
<img class="img-responsive" src="/resources/images/pets.png"/>
</div>
</div>
`;
}
}
86 changes: 86 additions & 0 deletions frontend/views/main-layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import '@vaadin/vaadin-app-layout';
import '@vaadin/vaadin-avatar/vaadin-avatar';
import '@vaadin/vaadin-context-menu';
import '@vaadin/vaadin-lumo-styles/utility';
import '@vaadin/vaadin-tabs';
import '@vaadin/vaadin-tabs/vaadin-tab';
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { router } from '../index';
import { views } from '../routes';
import { appStore } from '../stores/app-store';
import { Layout } from './view';
import type { RouterLocation } from '@vaadin/router';

interface RouteInfo {
marcushellberg marked this conversation as resolved.
Show resolved Hide resolved
path: string;
title: string;
icon: string;
}

@customElement('main-layout')
export class MainLayout extends Layout {
render() {
return html`
<vaadin-app-layout>
<header class="bg-base border-b border-contrast-10 box-border flex flex-col w-full" slot="navbar">
<nav class="flex gap-s overflow-auto px-m">
<a href="/" router-ignore class="flex mx-s p-s relative text-secondary">
<span class="la la-home me-s text-l"></span>
<span class="font-medium text-s">Original Home</span>
</a>
${this.getMenuRoutes().map(
(viewRoute) => html`
<a
?highlight=${this.highlightNav(viewRoute.path)}
class="flex
h-m items-center px-s relative text-secondary"
href=${router.urlForPath(viewRoute.path)}
>
<span class="${viewRoute.icon} me-s text-l"></span>
<span class="font-medium text-s whitespace-nowrap">${viewRoute.title}</span>
</a>
`
)}
</nav>
</header>
<div class="px-m">
<div class="mx-auto max-w-screen-lg my-xl">
<main>
<slot></slot>
</main>

<footer class="mt-xl text-center">
<img src="/resources/images/spring-pivotal-logo.png" alt="Sponsored by Pivotal" />
</footer>
</div>
</div>
</vaadin-app-layout>
`;
}

isSubRoute(location: RouterLocation, parentRouteName: string) {
return location.routes.find((r) => r.name === parentRouteName) !== undefined;
}

highlightNav(routePath: string) {
if (appStore.location.startsWith(routePath)) {
return true;
}
// Highlight "Find owners" if this is any view under the owners-base route
if (routePath === router.urlForName('find-owners')
&& this.isSubRoute(router.location, 'owners-base')) {
return true;
}
return false;
}

connectedCallback() {
super.connectedCallback();
this.classList.add('block', 'h-full');
}

private getMenuRoutes(): RouteInfo[] {
return views.filter((route) => route.title) as RouteInfo[];
}
}
Loading