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

feat(cli): add code template for default home page controller #1763

Merged
merged 1 commit into from
Sep 28, 2018
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
73 changes: 73 additions & 0 deletions packages/cli/generators/app/templates/public/index.html.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title><%= project.description %></title>

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update to the newest design so we have a favicon (otherwise loading this throws a console error in the browser (if someone was to check)).

<link rel="shortcut icon" type="image/x-icon" href="//v4.loopback.io/favicon.ico">

<style>
h3 {
margin-left: 25px;
text-align: center;
}

a, a:visited {
color: #3f5dff;
}

h3 a {
margin-left: 10px;
}

a:hover, a:focus, a:active {
color: #001956;
}

.power {
position: absolute;
bottom: 25px;
left: 50%;
transform: translateX(-50%);
}

.info {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}

.info h1 {
text-align: center;
margin-bottom: 0px;
}

.info p {
text-align: center;
margin-bottom: 3em;
margin-top: 1em;
}
</style>
</head>

<body>
<div class="info">
<h1><%= project.name %></h1>
<p>Version <%= project.version || '1.0.0' %></p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, we are hard-coding project name and version to index.html at the time when the HomePageController is scaffolded. Subsequent updates to name and version in project's package.json files are not going to be picked up, the home page will display version 1.0.0 forever. I find that rather confusing!

@raymondfeng @virkt25 Is this intentional? I thought our intention was to render the home pages from an EJS template at runtime, that's what I see in loopbackio/loopback4-example-shopping#16.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was intentional as the first step:

We wanted to keep the HomePageController implementation simple and easy to understand.

  • The generated public/index.html is a plain html instead of a template. We set the name/version during code gen but it's up to developers to maintain it
  • There is no need to use a template engine to render the view

That's been said, I'm fine to upgrade it to an EJS view once #1764 is landed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the Version from the static page then? Application name is unlikely to change, but the version is going to change often.


<h3>OpenAPI spec: <a href="/openapi.json">/openapi.json</a></h4>
<h3>API Explorer: <a href="/explorer">/explorer</a></h4>
</div>

<footer class="power">
<a href="https://v4.loopback.io" target="_blank">
<img src="https://loopback.io/images/branding/powered-by-loopback/blue/powered-by-loopback-sm.png" />
</a>
</footer>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {get} from '@loopback/openapi-v3';
import * as fs from 'fs';
import * as path from 'path';
import {inject} from '@loopback/context';
import {RestBindings, Response} from '@loopback/rest';

export class HomePageController {
private html: string;
constructor(@inject(RestBindings.Http.RESPONSE) private response: Response) {
this.html = fs.readFileSync(
path.join(__dirname, '../../../public/index.html'),
'utf-8',
);
}

@get('/', {
responses: {
'200': {
description: 'Home Page',
content: {'text/html': {schema: {type: 'string'}}},
},
},
})
homePage() {
this.response
.status(200)
.contentType('html')
.send(this.html);
return this.response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright IBM Corp. 2018. All Rights Reserved.
// Node module: @loopback/example-shopping
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Client} from '@loopback/testlab';
import {<%= project.applicationName %>} from '../..';
import {setupApplication} from './test-helper';

describe('HomePageController', () => {
let app: <%= project.applicationName %>;
let client: Client;

before('setupApplication', async () => {
({app, client} = await setupApplication());
});

after(async () => {
await app.stop();
});

it('exposes a default home page', async () => {
await client
.get('/')
.expect(200)
.expect('Content-Type', /text\/html/);
});
});
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
import {
Client,
createRestAppClient,
givenHttpServerConfig,
expect,
} from '@loopback/testlab';
import {Client, expect} from '@loopback/testlab';
import {<%= project.applicationName %>} from '../..';
import {setupApplication} from './test-helper';

describe('PingController', () => {
let app: <%= project.applicationName %>;
let client: Client;

before(givenAnApplication);

before(async () => {
await app.boot();
await app.start();
});

before(() => {
client = createRestAppClient(app);
before('setupApplication', async () => {
({app, client} = await setupApplication());
});

after(async () => {
Expand All @@ -29,10 +18,4 @@ describe('PingController', () => {
const res = await client.get('/ping?msg=world').expect(200);
expect(res.body).to.containEql({greeting: 'Hello from LoopBack'});
});

function givenAnApplication() {
app = new <%= project.applicationName %>({
rest: givenHttpServerConfig(),
});
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {<%= project.applicationName %>} from '../..';
import {
createRestAppClient,
givenHttpServerConfig,
Client,
} from '@loopback/testlab';

export async function setupApplication(): Promise<AppWithClient> {
const app = new <%= project.applicationName %>({
rest: givenHttpServerConfig(),
});

await app.boot();
await app.start();

const client = createRestAppClient(app);

return {app, client};
}

export interface AppWithClient {
app: <%= project.applicationName %>;
client: Client;
}
2 changes: 1 addition & 1 deletion packages/cli/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ exports.renameEJS = function() {

// extname already contains a leading '.'
const fileName = `${basename}${extname}`;
const result = fileName.match(/(.+)(.ts|.json|.js|.md)\.ejs$/);
const result = fileName.match(/(.+)(.ts|.json|.js|.md|.html)\.ejs$/);
if (result) {
extname = result[2];
basename = result[1];
Expand Down
16 changes: 16 additions & 0 deletions packages/cli/test/integration/generators/app.integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ describe('app-generator specific files', () => {
'test/acceptance/ping.controller.acceptance.ts',
/describe\('PingController'/,
);
assert.fileContent(
'src/controllers/home-page.controller.ts',
/export class HomePageController/,
);
assert.fileContent(
'src/controllers/home-page.controller.ts',
/homePage\(\)/,
);
assert.fileContent(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also assert ./test-helper.ts file

'test/acceptance/home-page.controller.acceptance.ts',
/describe\('HomePageController'/,
);
assert.fileContent(
'test/acceptance/test-helper.ts',
/export async function setupApplication/,
);
});
});

Expand Down