Skip to content

Commit 04174cd

Browse files
committed
update tutorial versions and display latest tutorial version
1 parent 8d27b84 commit 04174cd

File tree

16 files changed

+128
-83
lines changed

16 files changed

+128
-83
lines changed

lib/components/Tutorials/UpdateTutorial/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ var UpdateTutorial = (function (_super) {
2626
UpdateTutorial.prototype.render = function () {
2727
var _a = this.props, tutorial = _a.tutorial, tutorialUpdate = _a.tutorialUpdate;
2828
return (React.createElement("span", null,
29-
React.createElement(update_1.default, {style: styles.icon, color: colors_1.pink500, onTouchTap: tutorialUpdate.bind(this, tutorial.name)})
30-
));
29+
React.createElement(update_1.default, {style: styles.icon, color: colors_1.pink500, onTouchTap: tutorialUpdate.bind(this, tutorial.name)}),
30+
React.createElement("span", null, tutorial.latest)));
3131
};
3232
return UpdateTutorial;
3333
}(React.Component));

lib/components/Tutorials/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ var Tutorials = (function (_super) {
3636
),
3737
React.createElement(Table_1.TableRowColumn, null,
3838
tutorial.version,
39-
!tutorial.latest
39+
!tutorial.isLatest
4040
? React.createElement(UpdateTutorial_1.default, {tutorial: tutorial})
4141
: null)));
4242
}))),

lib/modules/tutorials/actions.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ var actions_2 = require('../tutorial/actions');
55
exports.tutorialSet = actions_2.tutorialSet;
66
function tutorialUpdate(title) {
77
return function (dispatch) {
8+
dispatch({ type: types_1.TUTORIAL_UPDATE, payload: { title: title } });
89
var alert = {
910
message: "run `npm install --save-dev " + title + "`",
1011
action: 'note',
1112
duration: 3000,
1213
};
13-
dispatch({ type: types_1.TUTORIAL_UPDATE, payload: { title: title } });
1414
dispatch(actions_1.alertOpen(alert));
1515
};
1616
}
@@ -27,3 +27,8 @@ function tutorialsFind() {
2727
};
2828
}
2929
exports.tutorialsFind = tutorialsFind;
30+
function tutorialVersion(_a) {
31+
var name = _a.name, latest = _a.latest;
32+
return { type: types_1.TUTORIAL_VERSION, payload: { name: name, latest: latest } };
33+
}
34+
exports.tutorialVersion = tutorialVersion;

lib/modules/tutorials/index.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
2-
var latestVersion_1 = require('./latestVersion');
32
var types_1 = require('./types');
3+
var latestVersion_1 = require('./utils/latestVersion');
44
var coderoad_cli_1 = require('coderoad-cli');
55
function tutorialsReducer(t, action) {
66
if (t === void 0) { t = []; }
@@ -11,9 +11,15 @@ function tutorialsReducer(t, action) {
1111
case types_1.TUTORIALS_UPDATE:
1212
return t.map(function (tutorial) {
1313
var name = tutorial.name, version = tutorial.version;
14-
if (version) {
15-
latestVersion_1.default({ name: name, version: version })
16-
.then(function (x) { return tutorial.latest = x; });
14+
latestVersion_1.default({ name: name, version: version });
15+
return tutorial;
16+
});
17+
case types_1.TUTORIAL_VERSION:
18+
var _a = action.payload, name_1 = _a.name, latest_1 = _a.latest;
19+
t.map(function (tutorial) {
20+
if (tutorial.name === name_1) {
21+
tutorial.isLatest = false;
22+
tutorial.latest = latest_1;
1723
}
1824
return tutorial;
1925
});

lib/modules/tutorials/types.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
exports.TUTORIALS_FIND = 'TUTORIALS_FIND';
33
exports.TUTORIALS_UPDATE = 'TUTORIALS_UPDATE';
44
exports.TUTORIAL_UPDATE = 'TUTORIAL_UPDATE';
5+
exports.TUTORIAL_VERSION = 'TUTORIAL_VERSION';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"use strict";
2+
var store_1 = require('../../../store');
3+
var compareVersions_1 = require('../../../utils/compareVersions');
4+
var fetch_1 = require('../../../utils/fetch');
5+
var actions_1 = require('./actions');
6+
var npmApiCall = function (name) { return ("https://registry.npmjs.org/" + name); };
7+
function getLatest(version, data) {
8+
return data['dist-tags'].latest;
9+
}
10+
function isLatestVersion(_a) {
11+
var name = _a.name, version = _a.version;
12+
window.fetch(npmApiCall(name))
13+
.then(fetch_1.status)
14+
.then(fetch_1.json)
15+
.then(getLatest.bind(this, version))
16+
.then(function (latest) {
17+
if (!compareVersions_1.isAboveVersion(version, latest)) {
18+
store_1.default.dispatch(actions_1.tutorialVersion({ name: name, latest: latest }));
19+
}
20+
})
21+
.catch(function (err) { return console.log("Error fetching tutorial \"" + name + "\": " + err); });
22+
}
23+
Object.defineProperty(exports, "__esModule", { value: true });
24+
exports.default = isLatestVersion;

lib/utils/fetch.js

+13-16
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
"use strict";
2-
var fetch = function (url) {
3-
return new Promise(function (resolve, reject) {
4-
var lib = url.startsWith('https') ? require('https') : require('http');
5-
var request = lib.get(url, function (response) {
6-
if (response.statusCode < 200 || response.statusCode > 299) {
7-
reject(new Error('Failed to load page, status code: ' + response.statusCode));
8-
}
9-
var body = [];
10-
response.on('data', function (chunk) { return body.push(chunk); });
11-
response.on('end', function () { return resolve(body.join('')); });
12-
});
13-
request.on('error', function (err) { return reject(err); });
14-
});
15-
};
16-
Object.defineProperty(exports, "__esModule", { value: true });
17-
exports.default = fetch;
2+
function status(response) {
3+
if (response.status >= 200 && response.status < 300) {
4+
return Promise.resolve(response);
5+
}
6+
else {
7+
return Promise.reject(new Error(response.statusText));
8+
}
9+
}
10+
exports.status = status;
11+
function json(response) {
12+
return response.json();
13+
}
14+
exports.json = json;

src/components/Tutorials/UpdateTutorial/index.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class UpdateTutorial extends React.Component<{
2727
color={pink500}
2828
onTouchTap={tutorialUpdate.bind(this, tutorial.name)}
2929
/>
30+
<span>{tutorial.latest}</span>
3031
</span>
3132
);
3233
}

src/components/Tutorials/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class Tutorials extends React.Component<{
4848
<TableRowColumn>
4949
{tutorial.version}
5050

51-
{!tutorial.latest
51+
{!tutorial.isLatest
5252
? <UpdateTutorial tutorial={tutorial} />
5353
: null
5454
}

src/modules/tutorials/actions.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import {alertOpen} from '../alert/actions';
2-
import {TUTORIALS_FIND, TUTORIALS_UPDATE, TUTORIAL_UPDATE} from './types';
2+
import {TUTORIALS_FIND, TUTORIALS_UPDATE, TUTORIAL_UPDATE, TUTORIAL_VERSION} from './types';
33
export {tutorialSet} from '../tutorial/actions';
44

55
export function tutorialUpdate(title: string):
66
Redux.ThunkAction<any, {}, {}> {
77
return (dispatch) => {
8+
dispatch({ type: TUTORIAL_UPDATE, payload: { title }});
9+
10+
// alert instructions
811
const alert = {
912
message: `run \`npm install --save-dev ${title}\``,
1013
action: 'note',
1114
duration: 3000,
1215
};
13-
dispatch({ type: TUTORIAL_UPDATE, payload: { title }});
1416
dispatch(alertOpen(alert));
1517
};
1618
}
@@ -26,3 +28,7 @@ export function tutorialsFind(): Redux.ThunkAction<any, {dir: string}, {}> {
2628
dispatch(tutorialsUpdate());
2729
};
2830
}
31+
32+
export function tutorialVersion({name, latest}): Action {
33+
return { type: TUTORIAL_VERSION, payload: { name, latest } };
34+
}

src/modules/tutorials/index.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// import {tutorialUpdate} from './utils/update';
2-
import isLatestVersion from './latestVersion';
3-
import {TUTORIALS_FIND, TUTORIALS_UPDATE} from './types';
2+
import {TUTORIALS_FIND, TUTORIALS_UPDATE, TUTORIAL_VERSION} from './types';
3+
import isLatestVersion from './utils/latestVersion';
44
import {tutorials} from 'coderoad-cli';
55

66
/**
@@ -31,9 +31,16 @@ export default function tutorialsReducer(
3131
case TUTORIALS_UPDATE:
3232
return t.map((tutorial: Tutorial.Info) => {
3333
const { name, version } = tutorial;
34-
if (version) {
35-
isLatestVersion({name, version})
36-
.then(x => tutorial.latest = x);
34+
isLatestVersion({name, version});
35+
return tutorial;
36+
});
37+
38+
case TUTORIAL_VERSION:
39+
const { name, latest } = action.payload;
40+
t.map((tutorial: Tutorial.Info) => {
41+
if (tutorial.name === name) {
42+
tutorial.isLatest = false;
43+
tutorial.latest = latest;
3744
}
3845
return tutorial;
3946
});

src/modules/tutorials/latestVersion.ts

-26
This file was deleted.

src/modules/tutorials/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const TUTORIALS_FIND = 'TUTORIALS_FIND';
22
export const TUTORIALS_UPDATE = 'TUTORIALS_UPDATE';
33
export const TUTORIAL_UPDATE = 'TUTORIAL_UPDATE';
4+
export const TUTORIAL_VERSION = 'TUTORIAL_VERSION';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import store from '../../../store';
2+
import {isAboveVersion} from '../../../utils/compareVersions';
3+
import {json, status} from '../../../utils/fetch';
4+
import {tutorialVersion} from './actions';
5+
6+
const npmApiCall = name => `https://registry.npmjs.org/${name}`;
7+
8+
function getLatest(version, data: Object): boolean {
9+
return data['dist-tags'].latest;
10+
}
11+
12+
/**
13+
* Checks that current tutorial version is >= latest version
14+
* via the NPM registry
15+
*
16+
* triggers an update by dispatching "tutorialVersion"
17+
*
18+
* @param {} {name
19+
* @param {} version}
20+
* @param {string} current
21+
* @returns Promise
22+
*/
23+
function isLatestVersion({name, version}): void {
24+
window.fetch(npmApiCall(name))
25+
.then(status)
26+
.then(json)
27+
.then(getLatest.bind(this, version))
28+
.then(latest => {
29+
if (!isAboveVersion(version, latest)) {
30+
store.dispatch(tutorialVersion({name, latest}))
31+
}
32+
})
33+
.catch((err) => console.log(`Error fetching tutorial "${name}": ${err}`));
34+
}
35+
36+
export default isLatestVersion;

src/typings/tutorial/index.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ declare namespace Tutorial {
1010
description?: string;
1111
keywords?: string[];
1212
version?: string;
13-
latest?: boolean;
13+
latest?: string;
14+
isLatest: boolean;
1415
}
1516

1617
export interface Config {

src/utils/fetch.ts

+10-24
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
1-
/**
2-
* fetch data from url
3-
* @param {string} url
4-
* @returns Promise
5-
*/
6-
const fetch = (url: string) => {
7-
return new Promise((resolve, reject) => {
8-
const lib = url.startsWith('https') ? require('https') : require('http');
9-
const request = lib.get(url, (response) => {
10-
// handle http errors
11-
if (response.statusCode < 200 || response.statusCode > 299) {
12-
reject(new Error('Failed to load page, status code: ' + response.statusCode));
13-
}
14-
const body = [];
15-
// on every content chunk, push it to the data array
16-
response.on('data', (chunk: never) => body.push(chunk));
17-
// we are done, resolve promise with those joined chunks
18-
response.on('end', () => resolve(body.join('')));
19-
});
20-
// handle connection errors of the request
21-
request.on('error', (err) => reject(err));
22-
});
23-
};
1+
export function status(response) {
2+
if (response.status >= 200 && response.status < 300) {
3+
return Promise.resolve(response);
4+
} else {
5+
return Promise.reject(new Error(response.statusText));
6+
}
7+
}
248

25-
export default fetch;
9+
export function json(response) {
10+
return response.json();
11+
}

0 commit comments

Comments
 (0)