(mozaik.rocks)
Β
How to create TV dashboard for devs
Przemek Suchodolski / @przemuh / przemuh.pl
@przemuh / przemuh.pl
As a dev since 2012
π°π· korpo, π΅π± software-house, πΊπΈ startup
Musician amateur
"Gamer" / PS4
client
widgets
config.yaml
api poll interval
WS
react - ^0.13.3
react-mixins
sass
poor DX
good UX
latest react
composition
css-in-js (styled-components)
great DX (live-reload)
better UX
git clone git@github.com:plouc/mozaik-demo.git
cd mozaik-demo
git checkout mozaik-2
npm install
npm start
git clone git@github.com:plouc/mozaik-demo.git
cd mozaik-demo
git checkout mozaik-2
npm install
npm start
git clone git@github.com:plouc/mozaik-demo.git
cd mozaik-demo
git checkout mozaik-2
npm install
npm start
git clone git@github.com:plouc/mozaik-demo.git
cd mozaik-demo
git checkout mozaik-2
npm install
npm start
Compiled successfully!
You can now view mozaik-demo in the browser.
Local: http://localhost:3000/
On Your Network: http://192.168.43.16:3000/
Note that the development build is not optimized.
To create a production build, use yarn build.
Proxy error: Could not proxy request /config from localhost:3000 to http://localhost:5000.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNREFUSED).
[HPM] Error occurred while trying to proxy request /config from localhost:3000 to http://localhost:5000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
$ node server.js
internal/modules/cjs/loader.js:584
throw err;
^
Error: Cannot find module 'dotenv'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
at Function.Module._load (internal/modules/cjs/loader.js:508:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/Users/psuchodolski/Dev/github/mozaik-demo/server.js:1:63)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
$ npm install dotenv@6 request
> using config file: 'conf/config.yml'
info: Registered API 'mozaik' (mode: poll)
info: serving static contents from /Users/psuchodolski/Dev/github/mozaik-demo/build
info: MozaΓ―k server started on port 5000
but...
Β Β Β "@mozaik/themes": "1.0.0-alpha.16",
Β Β Β "@mozaik/ui": "^2.0.0-alpha.15",
+Β Β "dotenv": "^6.2.0",
Β Β Β "nivo": "^0.15.0",
-Β Β "react": "^15.6.1",
-Β Β "react-dom": "^15.6.1"
+Β Β "react": "^16.8.6",
+Β Β "react-dom": "^16.8.6",
+Β Β "request": "^2.88.0"
Β Β },
Β Β "devDependencies": {
Β Β Β "react-scripts": "1.0.10"
error: [github] github.repositoryContributorsStats.plouc/mozaik - status code: 403
error: [travis] travis.repository.plouc.mozaik - status code: 403
error: [travis] travis.repositoryBuildHistory.plouc.mozaik.10 - status code: 403
error: [travis] travis.repositoryBuildHistory.plouc.mozaik.20 - status code: 403
error: [github] github.branches.plouc/mozaik - status code: 403
error: [github] github.user.plouc - status code: 403
error: [github] github.pullRequests.plouc/mozaik - status code: 403
error: [github] github.repository.plouc/mozaik - status code: 403
error: [github] github.organization.ekino - status code: 403
error: [github] github.status - status code: 404
columns: 3 +ββββββββββββββββββ+ββββββββββββββββββ+ββββββββββββββββββ+ | | | | A -> x: 0 y: 0 | B -> x: 1 y: 0 | | columns: 1 | columns: 2 | | rows: 1 | rows: 1 | | | | +ββββββββββββββββββ+ββββββββββββββββββ+ββββββββββββββββββ+ rows: 2 | | | | C -> x: 0 y: 1 | D -> x: 2 y: 1 | | columns: 2 | columns: 1 | | rows: 1 | rows: 1 | | | | +ββββββββββββββββββ+ββββββββββββββββββ+ββββββββββββββββββ+
port: 8888
host: 10.0.2.35
rotationDuration: 15
apis:
pollInterval: 30000
dashboards:
- columns: 4
rows: 8
title: Main
widgets:
-
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
-
extension: jenkins
widget: JobStatus
job: delphi-platform-bazel/job/develop
title: Develop
columns: 1
rows: 3
x: 0
y: 2
port: 8888
host: 10.0.2.35
rotationDuration: 15
apis:
pollInterval: 30000
dashboards:
- columns: 4
rows: 8
title: Main
widgets:
-
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
-
extension: jenkins
widget: JobStatus
job: delphi-platform-bazel/job/develop
title: Develop
columns: 1
rows: 3
x: 0
y: 2
port: 8888
host: 10.0.2.35
rotationDuration: 15
apis:
pollInterval: 30000
dashboards:
- columns: 4
rows: 8
title: Main
widgets:
-
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
-
extension: jenkins
widget: JobStatus
job: delphi-platform-bazel/job/develop
title: Develop
columns: 1
rows: 3
x: 0
y: 2
port: 8888
host: 10.0.2.35
rotationDuration: 15
apis:
pollInterval: 30000
dashboards:
- columns: 4
rows: 8
title: Main
widgets:
-
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
-
extension: jenkins
widget: JobStatus
job: delphi-platform-bazel/job/develop
title: Develop
columns: 1
rows: 3
x: 0
y: 2
port: 8888
host: 10.0.2.35
rotationDuration: 15
apis:
pollInterval: 30000
dashboards:
- columns: 4
rows: 8
title: Main
widgets:
-
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
-
extension: jenkins
widget: JobStatus
job: delphi-platform-bazel/job/develop
title: Develop
columns: 1
rows: 3
x: 0
y: 2
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./register_themes";
import "./register_extensions";
import Mozaik from "@mozaik/ui";
ReactDOM.render(<Mozaik />, document.getElementById("root"));
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./register_themes";
import "./register_extensions";
import Mozaik from "@mozaik/ui";
ReactDOM.render(<Mozaik />, document.getElementById("root"));
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./register_themes";
import "./register_extensions";
import Mozaik from "@mozaik/ui";
ReactDOM.render(<Mozaik />, document.getElementById("root"));
import { Registry } from "@mozaik/ui";
import monitoring from "./ext-monitoring/components";
import jenkins from "./ext-jenkins/components";
import jira from "./ext-jira/components";
import gitlab from "./ext-gitlab/components";
Registry.addExtensions({
monitoring,
jenkins,
jira,
gitlab,
});
import { Registry } from "@mozaik/ui";
import monitoring from "./ext-monitoring/components";
import jenkins from "./ext-jenkins/components";
import jira from "./ext-jira/components";
import gitlab from "./ext-gitlab/components";
Registry.addExtensions({
monitoring,
jenkins,
jira,
gitlab,
});
import { Registry } from "@mozaik/ui";
import monitoring from "./ext-monitoring/components";
import jenkins from "./ext-jenkins/components";
import jira from "./ext-jira/components";
import gitlab from "./ext-gitlab/components";
Registry.addExtensions({
monitoring,
jenkins,
jira,
gitlab,
});
import { Registry } from "@mozaik/ui";
import monitoring from "./ext-monitoring/components";
import jenkins from "./ext-jenkins/components";
import jira from "./ext-jira/components";
import gitlab from "./ext-gitlab/components";
Registry.addExtensions({
monitoring,
jenkins,
jira,
gitlab,
});
import Versions from "./Versions";
import FailingScans from "./FailingScans";
export default {
Versions,
FailingScans,
};
extension: monitoring
widget: Versions
columns: 4
rows: 2
x: 0
y: 0
import React, { Component } from "react";
import { TrapApiError, Widget, WidgetLoader } from "@mozaik/ui";
class Versions extends Component {
static getApiRequest() {
return {
id: "monitoring.deployedVersions",
};
}
render() {
const { apiData, apiError } = this.props;
const body = apiData
? <div>{ apiData.join(",") }</div>
: <WidgetLoader />;
return (
<Widget>
<TrapApiError error={apiError}>
{body}
</TrapApiError>
</Widget>
);
}
}
export default Versions;
import React, { Component } from "react";
import { TrapApiError, Widget, WidgetLoader } from "@mozaik/ui";
class Versions extends Component {
static getApiRequest() {
return {
id: "monitoring.deployedVersions",
};
}
render() {
const { apiData, apiError } = this.props;
const body = apiData
? <div>{ apiData.join(",") }</div>
: <WidgetLoader />;
return (
<Widget>
<TrapApiError error={apiError}>
{body}
</TrapApiError>
</Widget>
);
}
}
export default Versions;
import React, { Component } from "react";
import { TrapApiError, Widget, WidgetLoader } from "@mozaik/ui";
class Versions extends Component {
static getApiRequest() {
return {
id: "monitoring.deployedVersions",
};
}
render() {
const { apiData, apiError } = this.props;
const body = apiData
? <div>{ apiData.join(",") }</div>
: <WidgetLoader />;
return (
<Widget>
<TrapApiError error={apiError}>
{body}
</TrapApiError>
</Widget>
);
}
}
export default Versions;
import React, { Component } from "react";
import { TrapApiError, Widget, WidgetLoader } from "@mozaik/ui";
class Versions extends Component {
static getApiRequest() {
return {
id: "monitoring.deployedVersions",
};
}
render() {
const { apiData, apiError } = this.props;
const body = apiData
? <div>{ apiData.join(",") }</div>
: <WidgetLoader />;
return (
<Widget>
<TrapApiError error={apiError}>
{body}
</TrapApiError>
</Widget>
);
}
}
export default Versions;
import React, { Component } from "react";
import { TrapApiError, Widget, WidgetLoader } from "@mozaik/ui";
class Versions extends Component {
static getApiRequest() {
return {
id: "monitoring.deployedVersions",
};
}
render() {
const { apiData, apiError } = this.props;
const body = apiData
? <div>{ apiData.join(",") }</div>
: <WidgetLoader />;
return (
<Widget>
<TrapApiError error={apiError}>
{body}
</TrapApiError>
</Widget>
);
}
}
export default Versions;
require("dotenv").load({ silent: true });
const path = require("path");
const Mozaik = require("@mozaik/server").default;
let configFile = process.argv[2] || "conf/config.yml";
console.log(`> using config file: '${configFile}'\n`);
Mozaik.configureFromFile(path.join(__dirname, configFile))
.then((config) => {
require("./src/register_apis")(Mozaik, configFile, config);
Mozaik.start();
})
.catch((err) => {
console.error(err);
});
require("dotenv").load({ silent: true });
const path = require("path");
const Mozaik = require("@mozaik/server").default;
let configFile = process.argv[2] || "conf/config.yml";
console.log(`> using config file: '${configFile}'\n`);
Mozaik.configureFromFile(path.join(__dirname, configFile))
.then((config) => {
require("./src/register_apis")(Mozaik, configFile, config);
Mozaik.start();
})
.catch((err) => {
console.error(err);
});
require("dotenv").load({ silent: true });
const path = require("path");
const Mozaik = require("@mozaik/server").default;
let configFile = process.argv[2] || "conf/config.yml";
console.log(`> using config file: '${configFile}'\n`);
Mozaik.configureFromFile(path.join(__dirname, configFile))
.then((config) => {
require("./src/register_apis")(Mozaik, configFile, config);
Mozaik.start();
})
.catch((err) => {
console.error(err);
});
require("dotenv").load({ silent: true });
const path = require("path");
const Mozaik = require("@mozaik/server").default;
let configFile = process.argv[2] || "conf/config.yml";
console.log(`> using config file: '${configFile}'\n`);
Mozaik.configureFromFile(path.join(__dirname, configFile))
.then((config) => {
require("./src/register_apis")(Mozaik, configFile, config);
Mozaik.start();
})
.catch((err) => {
console.error(err);
});
module.exports = (Mozaik /* configFile, config */) => {
Mozaik.registerApi("monitoring", require("./ext-monitoring/client"));
Mozaik.registerApi("jenkins", require("./ext-jenkins/client"));
Mozaik.registerApi("jira", require("./ext-jira/client"));
Mozaik.registerApi("gitlab", require("./ext-gitlab/client"));
};
module.exports = (Mozaik /* configFile, config */) => {
Mozaik.registerApi("monitoring", require("./ext-monitoring/client"));
Mozaik.registerApi("jenkins", require("./ext-jenkins/client"));
Mozaik.registerApi("jira", require("./ext-jira/client"));
Mozaik.registerApi("gitlab", require("./ext-gitlab/client"));
};
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}
const chalk = require("chalk");
module.exports = (mozaik) => {
return {
deployedVersions() {
const options = {
uri: "https://yourAPI.dot.com",
json: true
};
mozaik.logger.info(chalk.yellow("[monitoring] fetching data"));
return mozaik.request.get(options)
.then(apiData => {
mozaik.logger.info(
chalk.green("[monitoring] fetching success")
);
})
.catch(error => {
mozaik.logger.error(
chalk.red(`[monitoring] ${error.error}`)
);
throw error;
})
}
}
}