gitlab-radiator 3.3.9 → 3.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/client.js +2 -0
- package/public/client.js.LICENSE.txt +41 -0
- package/src/app.js +167 -80
- package/src/auth.js +25 -13
- package/src/config.js +44 -28
- package/src/gitlab/client.js +39 -17
- package/src/gitlab/index.js +157 -41
- package/src/gitlab/pipelines.js +247 -79
- package/src/gitlab/projects.js +118 -38
- package/src/gitlab/runners.js +76 -15
- package/src/index.js +4 -2
- package/.babelrc +0 -4
- package/.eslintrc +0 -13
- package/.github/workflows/test.yml +0 -20
- package/.nvmrc +0 -1
- package/build-npm +0 -19
- package/screenshot.png +0 -0
- package/src/client/.eslintrc +0 -21
- package/src/client/arguments.ts +0 -75
- package/src/client/gitlab-types.ts +0 -54
- package/src/client/groupedProjects.tsx +0 -40
- package/src/client/groups.tsx +0 -59
- package/src/client/index.tsx +0 -94
- package/src/client/info.tsx +0 -16
- package/src/client/jobs.tsx +0 -56
- package/src/client/projects.tsx +0 -51
- package/src/client/renderTimestamp.tsx +0 -45
- package/src/client/stages.tsx +0 -18
- package/src/dev-assets.js +0 -10
- package/test/gitlab/projects.test.js +0 -75
- package/test/gitlab-integration.js +0 -384
- package/tsconfig.json +0 -28
- package/webpack.common.js +0 -25
- package/webpack.dev.js +0 -13
- package/webpack.prod.js +0 -9
package/src/gitlab/projects.js
CHANGED
|
@@ -1,28 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.fetchProjects = fetchProjects;
|
|
9
|
+
|
|
10
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
|
+
|
|
12
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
13
|
+
|
|
14
|
+
var _client = require("./client");
|
|
15
|
+
|
|
16
|
+
function fetchProjects(_x) {
|
|
17
|
+
return _fetchProjects.apply(this, arguments);
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
function _fetchProjects() {
|
|
21
|
+
_fetchProjects = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(gitlab) {
|
|
22
|
+
var projects;
|
|
23
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
24
|
+
while (1) {
|
|
25
|
+
switch (_context.prev = _context.next) {
|
|
26
|
+
case 0:
|
|
27
|
+
_context.next = 2;
|
|
28
|
+
return fetchOwnProjects(gitlab);
|
|
29
|
+
|
|
30
|
+
case 2:
|
|
31
|
+
projects = _context.sent;
|
|
32
|
+
return _context.abrupt("return", projects // Ignore projects for which CI/CD is not enabled
|
|
33
|
+
.filter(project => project.jobs_enabled).map(projectMapper).filter(includeRegexFilter(gitlab)).filter(excludeRegexFilter(gitlab)).filter(archivedFilter(gitlab)));
|
|
34
|
+
|
|
35
|
+
case 4:
|
|
36
|
+
case "end":
|
|
37
|
+
return _context.stop();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, _callee);
|
|
41
|
+
}));
|
|
42
|
+
return _fetchProjects.apply(this, arguments);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function fetchOwnProjects(_x2) {
|
|
46
|
+
return _fetchOwnProjects.apply(this, arguments);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function _fetchOwnProjects() {
|
|
50
|
+
_fetchOwnProjects = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(gitlab) {
|
|
51
|
+
var projects, SAFETY_MAX_PAGE, page, _yield$gitlabRequest, data, headers;
|
|
52
|
+
|
|
53
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
54
|
+
while (1) {
|
|
55
|
+
switch (_context2.prev = _context2.next) {
|
|
56
|
+
case 0:
|
|
57
|
+
projects = [];
|
|
58
|
+
SAFETY_MAX_PAGE = 10;
|
|
59
|
+
page = 1;
|
|
60
|
+
|
|
61
|
+
case 3:
|
|
62
|
+
if (!(page <= SAFETY_MAX_PAGE)) {
|
|
63
|
+
_context2.next = 15;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_context2.next = 6;
|
|
68
|
+
return (0, _client.gitlabRequest)('/projects', {
|
|
69
|
+
page,
|
|
70
|
+
per_page: 100,
|
|
71
|
+
membership: true
|
|
72
|
+
}, gitlab);
|
|
73
|
+
|
|
74
|
+
case 6:
|
|
75
|
+
_yield$gitlabRequest = _context2.sent;
|
|
76
|
+
data = _yield$gitlabRequest.data;
|
|
77
|
+
headers = _yield$gitlabRequest.headers;
|
|
78
|
+
projects.push(data);
|
|
79
|
+
|
|
80
|
+
if (!(data.length === 0 || !headers['x-next-page'])) {
|
|
81
|
+
_context2.next = 12;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return _context2.abrupt("break", 15);
|
|
86
|
+
|
|
87
|
+
case 12:
|
|
88
|
+
page += 1;
|
|
89
|
+
_context2.next = 3;
|
|
90
|
+
break;
|
|
91
|
+
|
|
92
|
+
case 15:
|
|
93
|
+
return _context2.abrupt("return", projects.flat());
|
|
94
|
+
|
|
95
|
+
case 16:
|
|
96
|
+
case "end":
|
|
97
|
+
return _context2.stop();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, _callee2);
|
|
101
|
+
}));
|
|
102
|
+
return _fetchOwnProjects.apply(this, arguments);
|
|
26
103
|
}
|
|
27
104
|
|
|
28
105
|
function projectMapper(project) {
|
|
@@ -35,39 +112,42 @@ function projectMapper(project) {
|
|
|
35
112
|
default_branch: project.default_branch || 'master',
|
|
36
113
|
url: project.web_url,
|
|
37
114
|
tags: (project.tag_list || []).map(t => t.toLowerCase())
|
|
38
|
-
}
|
|
115
|
+
};
|
|
39
116
|
}
|
|
40
117
|
|
|
41
118
|
function getGroupName(project) {
|
|
42
|
-
|
|
43
|
-
return pathWithNameSpace.split('/')[0]
|
|
119
|
+
var pathWithNameSpace = project.path_with_namespace;
|
|
120
|
+
return pathWithNameSpace.split('/')[0];
|
|
44
121
|
}
|
|
45
122
|
|
|
46
123
|
function includeRegexFilter(config) {
|
|
47
124
|
return project => {
|
|
48
125
|
if (config.projects && config.projects.include) {
|
|
49
|
-
|
|
50
|
-
return includeRegex.test(project.name)
|
|
126
|
+
var includeRegex = new RegExp(config.projects.include, "i");
|
|
127
|
+
return includeRegex.test(project.name);
|
|
51
128
|
}
|
|
52
|
-
|
|
53
|
-
|
|
129
|
+
|
|
130
|
+
return true;
|
|
131
|
+
};
|
|
54
132
|
}
|
|
55
133
|
|
|
56
134
|
function excludeRegexFilter(config) {
|
|
57
135
|
return project => {
|
|
58
136
|
if (config.projects && config.projects.exclude) {
|
|
59
|
-
|
|
60
|
-
return !excludeRegex.test(project.name)
|
|
137
|
+
var excludeRegex = new RegExp(config.projects.exclude, "i");
|
|
138
|
+
return !excludeRegex.test(project.name);
|
|
61
139
|
}
|
|
62
|
-
|
|
63
|
-
|
|
140
|
+
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
64
143
|
}
|
|
65
144
|
|
|
66
145
|
function archivedFilter(config) {
|
|
67
146
|
return project => {
|
|
68
147
|
if (config.ignoreArchived) {
|
|
69
|
-
return !project.archived
|
|
148
|
+
return !project.archived;
|
|
70
149
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
150
|
+
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
}
|
package/src/gitlab/runners.js
CHANGED
|
@@ -1,18 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.fetchOfflineRunners = fetchOfflineRunners;
|
|
9
|
+
|
|
10
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
|
+
|
|
12
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
13
|
+
|
|
14
|
+
var _client = require("./client");
|
|
15
|
+
|
|
16
|
+
function fetchOfflineRunners(_x) {
|
|
17
|
+
return _fetchOfflineRunners.apply(this, arguments);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function _fetchOfflineRunners() {
|
|
21
|
+
_fetchOfflineRunners = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(gitlab) {
|
|
22
|
+
var runners, offline;
|
|
23
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
24
|
+
while (1) {
|
|
25
|
+
switch (_context.prev = _context.next) {
|
|
26
|
+
case 0:
|
|
27
|
+
_context.next = 2;
|
|
28
|
+
return fetchRunners(gitlab);
|
|
29
|
+
|
|
30
|
+
case 2:
|
|
31
|
+
runners = _context.sent;
|
|
32
|
+
offline = runners.filter(r => r.status === 'offline');
|
|
33
|
+
return _context.abrupt("return", {
|
|
34
|
+
offline,
|
|
35
|
+
totalCount: runners.length
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
case 5:
|
|
39
|
+
case "end":
|
|
40
|
+
return _context.stop();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}, _callee);
|
|
44
|
+
}));
|
|
45
|
+
return _fetchOfflineRunners.apply(this, arguments);
|
|
10
46
|
}
|
|
11
47
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return runners.map(r => ({
|
|
15
|
-
name: r.description || r.id,
|
|
16
|
-
status: r.status
|
|
17
|
-
}))
|
|
48
|
+
function fetchRunners(_x2) {
|
|
49
|
+
return _fetchRunners.apply(this, arguments);
|
|
18
50
|
}
|
|
51
|
+
|
|
52
|
+
function _fetchRunners() {
|
|
53
|
+
_fetchRunners = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(gitlab) {
|
|
54
|
+
var _yield$gitlabRequest, runners;
|
|
55
|
+
|
|
56
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
57
|
+
while (1) {
|
|
58
|
+
switch (_context2.prev = _context2.next) {
|
|
59
|
+
case 0:
|
|
60
|
+
_context2.next = 2;
|
|
61
|
+
return (0, _client.gitlabRequest)('/runners', {}, gitlab);
|
|
62
|
+
|
|
63
|
+
case 2:
|
|
64
|
+
_yield$gitlabRequest = _context2.sent;
|
|
65
|
+
runners = _yield$gitlabRequest.data;
|
|
66
|
+
return _context2.abrupt("return", runners.map(r => ({
|
|
67
|
+
name: r.description || r.id,
|
|
68
|
+
status: r.status
|
|
69
|
+
})));
|
|
70
|
+
|
|
71
|
+
case 5:
|
|
72
|
+
case "end":
|
|
73
|
+
return _context2.stop();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}, _callee2);
|
|
77
|
+
}));
|
|
78
|
+
return _fetchRunners.apply(this, arguments);
|
|
79
|
+
}
|
package/src/index.js
CHANGED
package/.babelrc
DELETED
package/.eslintrc
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
name: Run tests
|
|
2
|
-
|
|
3
|
-
on: [push, pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
build:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
strategy:
|
|
9
|
-
matrix:
|
|
10
|
-
node-version: [12.x, 14.x]
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v2
|
|
13
|
-
- uses: actions/setup-node@v1
|
|
14
|
-
with:
|
|
15
|
-
node-version: ${{ matrix.node-version }}
|
|
16
|
-
- run: npm ci
|
|
17
|
-
- run: npm audit
|
|
18
|
-
- run: npm run eslint
|
|
19
|
-
- run: npm test
|
|
20
|
-
- run: npm run build
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
14.17.0
|
package/build-npm
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
rm -fr build
|
|
4
|
-
mkdir -p build/src
|
|
5
|
-
|
|
6
|
-
# Copy static resources
|
|
7
|
-
cp -r public build
|
|
8
|
-
|
|
9
|
-
# Copy LICENSE, README and package.json
|
|
10
|
-
cp LICENSE package.json README.md build
|
|
11
|
-
|
|
12
|
-
# Copy bin script
|
|
13
|
-
cp -r bin build
|
|
14
|
-
|
|
15
|
-
# Bundle and minify client JS
|
|
16
|
-
npx webpack --config webpack.prod.js
|
|
17
|
-
|
|
18
|
-
# Transpile server
|
|
19
|
-
node_modules/.bin/babel src --ignore **/client/*.js,**/dev-assets.js --out-dir build/src
|
package/screenshot.png
DELETED
|
Binary file
|
package/src/client/.eslintrc
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es6": true
|
|
5
|
-
},
|
|
6
|
-
"parser": "@typescript-eslint/parser",
|
|
7
|
-
"plugins": [
|
|
8
|
-
"@typescript-eslint"
|
|
9
|
-
],
|
|
10
|
-
"extends": [
|
|
11
|
-
"eslint:recommended",
|
|
12
|
-
"plugin:react/recommended",
|
|
13
|
-
"plugin:@typescript-eslint/eslint-recommended",
|
|
14
|
-
"plugin:@typescript-eslint/recommended"
|
|
15
|
-
],
|
|
16
|
-
"settings": {
|
|
17
|
-
"react": {
|
|
18
|
-
"version": "17.0"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
package/src/client/arguments.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
interface ParsedQueryString {
|
|
2
|
-
[key: string]: string | undefined
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function argumentsFromDocumentUrl(): {override: {columns?: number, zoom?: number}, includedTags: string[] | null, screen: {id: number, total: number}} {
|
|
6
|
-
const args = parseQueryString(document.location.search)
|
|
7
|
-
return {
|
|
8
|
-
override: overrideArguments(args),
|
|
9
|
-
includedTags: tagArguments(args),
|
|
10
|
-
screen: screenArguments(args)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function tagArguments(args: ParsedQueryString): string[] | null {
|
|
15
|
-
if (args.tags === undefined) {
|
|
16
|
-
return null
|
|
17
|
-
}
|
|
18
|
-
return args.tags
|
|
19
|
-
.split(',')
|
|
20
|
-
.map(t => t.toLowerCase().trim())
|
|
21
|
-
.filter(t => t)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function overrideArguments(args: ParsedQueryString): {columns?: number, zoom?: number} {
|
|
25
|
-
return {
|
|
26
|
-
...parseColumns(args),
|
|
27
|
-
...parseZoom(args)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function parseColumns(args: ParsedQueryString) {
|
|
32
|
-
if (args.columns) {
|
|
33
|
-
const columns = Number(args.columns)
|
|
34
|
-
if (columns > 0 && columns <= 10) {
|
|
35
|
-
return {columns}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return {}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
function parseZoom(args: ParsedQueryString) {
|
|
43
|
-
if (args.zoom) {
|
|
44
|
-
const zoom = Number(args.zoom)
|
|
45
|
-
if (zoom > 0 && zoom <= 2) {
|
|
46
|
-
return {zoom}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return {}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function screenArguments(args: ParsedQueryString): {id: number, total: number} {
|
|
53
|
-
const matches = (/(\d)of(\d)/).exec(args.screen || '')
|
|
54
|
-
let id = matches ? Number(matches[1]) : 1
|
|
55
|
-
const total = matches ? Number(matches[2]) : 1
|
|
56
|
-
if (id > total) {
|
|
57
|
-
id = total
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
id,
|
|
61
|
-
total
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function parseQueryString(search: string): ParsedQueryString {
|
|
66
|
-
const entries = search
|
|
67
|
-
.slice(1)
|
|
68
|
-
.split('&')
|
|
69
|
-
.filter(parameter => parameter)
|
|
70
|
-
.map((parameter: string): [string, string | undefined] => {
|
|
71
|
-
const [key, value] = parameter.split('=')
|
|
72
|
-
return [key, value]
|
|
73
|
-
})
|
|
74
|
-
return Object.fromEntries(entries)
|
|
75
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export interface GlobalState {
|
|
3
|
-
columns: number
|
|
4
|
-
error: string | null
|
|
5
|
-
groupSuccessfulProjects: boolean
|
|
6
|
-
projects: Project[] | null
|
|
7
|
-
projectsOrder: string[]
|
|
8
|
-
zoom: number
|
|
9
|
-
now: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Project {
|
|
13
|
-
archived: false
|
|
14
|
-
group: string
|
|
15
|
-
id: number
|
|
16
|
-
name: string
|
|
17
|
-
nameWithoutNamespace: string
|
|
18
|
-
tags: string[]
|
|
19
|
-
url: string
|
|
20
|
-
default_branch: string
|
|
21
|
-
pipelines: Pipeline[]
|
|
22
|
-
maxNonFailedJobsVisible: number
|
|
23
|
-
status: 'success' | 'failed'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface Pipeline {
|
|
27
|
-
commit: Commit | null
|
|
28
|
-
id: number
|
|
29
|
-
ref: string
|
|
30
|
-
stages: Stage[]
|
|
31
|
-
status: 'success' | 'failed'
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface Commit {
|
|
35
|
-
title: string
|
|
36
|
-
author: string
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface Stage {
|
|
40
|
-
jobs: Job[]
|
|
41
|
-
name: string
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface Job {
|
|
45
|
-
finishedAt: string | null
|
|
46
|
-
id: number
|
|
47
|
-
name: string
|
|
48
|
-
stage: string
|
|
49
|
-
startedAt: string | null
|
|
50
|
-
status: JobStatus
|
|
51
|
-
url: string
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type JobStatus = 'created' | 'failed' | 'manual' | 'pending' | 'running' | 'skipped' | 'success'
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import _ from 'lodash'
|
|
2
|
-
import {Groups} from './groups'
|
|
3
|
-
import type {Project} from './gitlab-types'
|
|
4
|
-
import {Projects} from './projects'
|
|
5
|
-
import React from 'react'
|
|
6
|
-
|
|
7
|
-
export function GroupedProjects({projects, projectsOrder, groupSuccessfulProjects, zoom, columns, now, screen}: {projects: Project[], projectsOrder: string[], groupSuccessfulProjects: boolean, zoom: number, columns: number, now: number, screen: {id: number, total: number}}): JSX.Element {
|
|
8
|
-
if (groupSuccessfulProjects) {
|
|
9
|
-
return renderProjectsGrouped(projects, projectsOrder, zoom, columns, now, screen)
|
|
10
|
-
}
|
|
11
|
-
return renderProjects(projects, projectsOrder, zoom, columns, now, screen)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function renderProjectsGrouped(projects: Project[], projectsOrder: string[], zoom: number, columns: number, now: number, screen: {id: number, total: number}) {
|
|
15
|
-
const successfullProjects: Project[] = []
|
|
16
|
-
const otherProjects: Project[] = []
|
|
17
|
-
projects.forEach((project) => {
|
|
18
|
-
if (project.status === 'success') {
|
|
19
|
-
successfullProjects.push(project)
|
|
20
|
-
} else {
|
|
21
|
-
otherProjects.push(project)
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
const groupedProjects = _.groupBy(successfullProjects, 'group')
|
|
25
|
-
return <React.Fragment>
|
|
26
|
-
{renderProjects(otherProjects, projectsOrder, zoom, columns, now, screen)}
|
|
27
|
-
{renderGroupedProjects(groupedProjects, zoom, columns, now)}
|
|
28
|
-
</React.Fragment>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function renderProjects(projects: Project[], projectsOrder: string[], zoom: number, columns: number, now: number, screen: {id: number, total: number}) {
|
|
32
|
-
return <Projects now={now} zoom={zoom} columns={columns}
|
|
33
|
-
projects={projects || []} projectsOrder={projectsOrder}
|
|
34
|
-
screen={screen}/>
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function renderGroupedProjects(groupedProjects: {[groupname: string]: Project[]}, zoom: number, columns: number, now: number) {
|
|
38
|
-
return <Groups zoom={zoom} columns={columns} now={now}
|
|
39
|
-
groupedProjects={groupedProjects || []} />
|
|
40
|
-
}
|
package/src/client/groups.tsx
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type {Pipeline, Project} from './gitlab-types'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import {renderTimestamp} from './renderTimestamp'
|
|
4
|
-
|
|
5
|
-
export function Groups({groupedProjects, now, zoom, columns}: {groupedProjects: {[groupname: string]: Project[]}, now: number, zoom: number, columns: number}): JSX.Element {
|
|
6
|
-
return <ol className="groups" style={zoomStyle(zoom)}>
|
|
7
|
-
{Object
|
|
8
|
-
.entries(groupedProjects)
|
|
9
|
-
.sort(([groupName1], [groupName2]) => groupName1.localeCompare(groupName2))
|
|
10
|
-
.map(([groupName, projects]) => <GroupElement columns={columns} groupName={groupName} key={groupName} projects={projects} now={now}/>)
|
|
11
|
-
}
|
|
12
|
-
</ol>
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function GroupElement({groupName, projects, now, columns}: {groupName: string, projects: Project[], now: number, columns: number}) {
|
|
16
|
-
const pipelines: (Pipeline & {project: string})[] = []
|
|
17
|
-
projects.forEach((project) => {
|
|
18
|
-
project.pipelines.forEach((pipeline) => {
|
|
19
|
-
pipelines.push({
|
|
20
|
-
...pipeline,
|
|
21
|
-
project: project.nameWithoutNamespace
|
|
22
|
-
})
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
return <li className={'group'} style={style(columns)}>
|
|
27
|
-
<h2>{groupName}</h2>
|
|
28
|
-
<div className={'group-info'}>{projects.length} Project{projects.length > 1 ? 's' : ''}</div>
|
|
29
|
-
<GroupInfoElement now={now} pipeline={pipelines[0]}/>
|
|
30
|
-
</li>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function GroupInfoElement({now, pipeline}: {now: number, pipeline: (Pipeline & {project: string})}) {
|
|
34
|
-
return <div className="pipeline-info">
|
|
35
|
-
<div>
|
|
36
|
-
<span>{pipeline.commit ? pipeline.commit.author : '-'}</span>
|
|
37
|
-
<span>{pipeline.commit ? pipeline.project : '-'}</span>
|
|
38
|
-
</div>
|
|
39
|
-
<div>
|
|
40
|
-
<span>{renderTimestamp(pipeline.stages, now)}</span>
|
|
41
|
-
<span>on {pipeline.ref}</span>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function zoomStyle(zoom: number) {
|
|
47
|
-
const widthPercentage = Math.round(100 / zoom)
|
|
48
|
-
return {
|
|
49
|
-
transform: `scale(${zoom})`,
|
|
50
|
-
width: `${widthPercentage}vmax`
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function style(columns: number) {
|
|
55
|
-
const widthPercentage = Math.round(90 / columns)
|
|
56
|
-
return {
|
|
57
|
-
width: `${widthPercentage}%`
|
|
58
|
-
}
|
|
59
|
-
}
|