generate static examples without api call [apm appveyor cdnjs clojars gem npm uptimerobot] (#1740)

* allow service classes to define a static example
* define static example for some services
  (apm, appveyor, cdnjs, clojars, gem, librariesio, npm, uptimerobot)
* add/update tests


This allows us to show an example without making an API call to a live service for better performance.

We can now specify 3 fields in the example definition:

* urlPattern for the version with placeholders e.g: /npm/dw/:package.svg
* ExampleUrl/Uri for the concrete example e.g: /npm/dw/localeval.svg
* PreviewUrl/Uri for the static (or live) image we will actually show
This commit is contained in:
chris48s
2018-08-23 20:22:24 +01:00
committed by GitHub
parent a0c43ed219
commit ae190c5f07
22 changed files with 265 additions and 90 deletions

View File

@@ -6,8 +6,9 @@ import resolveBadgeUrl from '../lib/badge-url'
const Badge = ({
title,
previewUri,
exampleUri,
previewUri,
urlPattern,
documentation,
baseUri,
longCache,
@@ -15,7 +16,14 @@ const Badge = ({
onClick,
}) => {
const handleClick = onClick
? () => onClick({ title, previewUri, exampleUri, documentation })
? () =>
onClick({
title,
exampleUri,
previewUri,
urlPattern,
documentation,
})
: undefined
const previewImage = previewUri ? (
@@ -29,7 +37,7 @@ const Badge = ({
'\u00a0'
) // non-breaking space
const resolvedExampleUri = resolveBadgeUrl(
exampleUri || previewUri,
urlPattern || previewUri,
baseUri,
{ longCache: false }
)
@@ -59,8 +67,9 @@ const Badge = ({
}
Badge.propTypes = {
title: PropTypes.string.isRequired,
previewUri: PropTypes.string,
exampleUri: PropTypes.string,
previewUri: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
baseUri: PropTypes.string,
longCache: PropTypes.bool.isRequired,
@@ -101,8 +110,9 @@ Category.propTypes = {
examples: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
previewUri: PropTypes.string,
exampleUri: PropTypes.string,
previewUri: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
})
).isRequired,

View File

@@ -10,8 +10,9 @@ export default class MarkupModal extends React.Component {
static propTypes = {
example: PropTypes.shape({
title: PropTypes.string.isRequired,
previewUri: PropTypes.string,
exampleUri: PropTypes.string,
previewUri: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
link: PropTypes.string,
}),
@@ -20,6 +21,7 @@ export default class MarkupModal extends React.Component {
}
state = {
exampleUri: null,
badgeUri: null,
link: null,
style: 'flat',
@@ -38,10 +40,13 @@ export default class MarkupModal extends React.Component {
// Transfer `badgeUri` and `link` into state so they can be edited by the
// user.
const { exampleUri, previewUri, link } = example
const { exampleUri, urlPattern, previewUri, link } = example
this.setState({
exampleUri: exampleUri
? resolveBadgeUrl(exampleUri, baseUri || window.location.href)
: null,
badgeUri: resolveBadgeUrl(
exampleUri || previewUri,
urlPattern || previewUri,
baseUri || window.location.href
),
link,
@@ -126,6 +131,18 @@ export default class MarkupModal extends React.Component {
/>
</label>
</p>
{this.state.exampleUri && (
<p>
Example&nbsp;
<ClickToSelect>
<input
className="code clickable"
readOnly
value={this.state.exampleUri}
/>
</ClickToSelect>
</p>
)}
<p>
<label>
Style&nbsp;

View File

@@ -120,22 +120,26 @@ const allBadgeExamples = [
{
title: 'Travis (.org)',
previewUri: '/travis/rust-lang/rust.svg',
exampleUri: '/travis/USER/REPO.svg',
urlPattern: '/travis/:user/:repo.svg',
exampleUri: '/travis/rust-lang/rust.svg',
},
{
title: 'Travis (.org) branch',
previewUri: '/travis/rust-lang/rust/master.svg',
exampleUri: '/travis/USER/REPO/BRANCH.svg',
urlPattern: '/travis/:user/:repo/:branch.svg',
exampleUri: '/travis/rust-lang/rust/master.svg',
},
{
title: 'Travis (.com)',
previewUri: '/travis/com/ivandelabeldad/rackian-gateway.svg',
exampleUri: '/travis/com/USER/REPO.svg',
urlPattern: '/travis/com/:user/:repo.svg',
exampleUri: '/travis/com/ivandelabeldad/rackian-gateway.svg',
},
{
title: 'Travis (.com) branch',
previewUri: '/travis/com/ivandelabeldad/rackian-gateway/master.svg',
exampleUri: '/travis/com/USER/REPO/BRANCH.svg',
urlPattern: '/travis/com/:user/:repo/:branch.svg',
exampleUri: '/travis/com/ivandelabeldad/rackian-gateway/master.svg',
},
{
title: 'TeamCity CodeBetter',
@@ -148,7 +152,7 @@ const allBadgeExamples = [
{
title: 'TeamCity (full build status)',
keywords: ['teamcity'],
exampleUri: '/teamcity/http/teamcity.jetbrains.com/e/bt345.svg',
previewUri: '/teamcity/http/teamcity.jetbrains.com/e/bt345.svg',
},
{
title: 'Buildkite',
@@ -176,8 +180,10 @@ const allBadgeExamples = [
title: 'CircleCI token',
previewUri:
'/circleci/project/github/RedSparr0w/node-csgo-parser/master.svg',
urlPattern:
'/circleci/token/:token/project/github/RedSparr0w/node-csgo-parser/master.svg',
exampleUri:
'/circleci/token/YOURTOKEN/project/github/RedSparr0w/node-csgo-parser/master.svg',
'/circleci/token/b90b5c49e59a4c67ba3a92f7992587ac7a0408c2/project/github/RedSparr0w/node-csgo-parser/master.svg',
},
{
title: 'Visual Studio Team services',
@@ -281,8 +287,9 @@ const allBadgeExamples = [
{
title: 'Codecov private',
previewUri: '/codecov/c/github/codecov/example-python.svg',
urlPattern: '/codecov/c/token/:token/github/codecov/example-python.svg',
exampleUri:
'/codecov/c/token/YOURTOKEN/github/codecov/example-python.svg',
'/codecov/c/token/My0A8VL917/github/codecov/example-python.svg',
},
{
title: 'Coverity Scan',
@@ -312,8 +319,9 @@ const allBadgeExamples = [
title: 'Dockbit',
previewUri:
'/dockbit/DockbitStatus/health.svg?token=TvavttxFHJ4qhnKstDxrvBXM',
urlPattern: '/dockbit/:organisation/:pipeline.svg?token=:token',
exampleUri:
'/dockbit/ORGANIZATION_NAME/PIPELINE_NAME.svg?token=PIPELINE_TOKEN',
'/dockbit/DockbitStatus/health.svg?token=TvavttxFHJ4qhnKstDxrvBXM',
},
{
title: 'continuousphp',
@@ -333,7 +341,10 @@ const allBadgeExamples = [
title: 'Bitrise',
previewUri:
'/bitrise/cde737473028420d/master.svg?token=GCIdEzacE4GW32jLVrZb7A',
exampleUri: '/bitrise/APP-ID/BRANCH.svg?token=APP-STATUS-BADGE-TOKEN',
urlPattern:
'/bitrise/:app-id/:branch.svg?token=:app-status-badge-token',
exampleUri:
'/bitrise/cde737473028420d/master.svg?token=GCIdEzacE4GW32jLVrZb7A',
},
{
title: 'Code Climate',
@@ -1440,7 +1451,8 @@ const allBadgeExamples = [
{
title: 'iTunes App Store',
previewUri: '/itunes/v/803453959.svg',
exampleUri: '/itunes/v/BUNDLE_ID.svg',
urlPattern: '/itunes/v/:bundle-id.svg',
exampleUri: '/itunes/v/803453959.svg',
},
{
title: 'JitPack',

View File

@@ -15,14 +15,16 @@ describe('The badge examples', function() {
expect(appVeyorBuildExamples).to.deep.equal([
{
title: 'AppVeyor',
previewUri: '/appveyor/ci/gruntjs/grunt.svg',
exampleUri: undefined,
exampleUri: '/appveyor/ci/gruntjs/grunt.svg',
previewUri: '/badge/build-passing-brightgreen.svg',
urlPattern: '/appveyor/ci/:user/:repo.svg',
documentation: undefined,
},
{
title: 'AppVeyor branch',
previewUri: '/appveyor/ci/gruntjs/grunt/master.svg',
exampleUri: undefined,
exampleUri: '/appveyor/ci/gruntjs/grunt/master.svg',
previewUri: '/badge/build-passing-brightgreen.svg',
urlPattern: '/appveyor/ci/:user/:repo/:branch.svg',
documentation: undefined,
},
])

View File

@@ -29,15 +29,6 @@ class BaseAPMService extends BaseJsonService {
static get defaultBadgeData() {
return { label: 'apm' }
}
static get examples() {
return [
{
previewUrl: 'vim-mode',
keywords: ['atom'],
},
]
}
}
class APMDownloads extends BaseAPMService {
@@ -65,6 +56,17 @@ class APMDownloads extends BaseAPMService {
capture: ['repo'],
}
}
static get examples() {
return [
{
exampleUrl: 'vim-mode',
urlPattern: ':package',
staticExample: this.render({ downloads: '60043' }),
keywords: ['atom'],
},
]
}
}
class APMVersion extends BaseAPMService {
@@ -94,6 +96,17 @@ class APMVersion extends BaseAPMService {
capture: ['repo'],
}
}
static get examples() {
return [
{
exampleUrl: 'vim-mode',
urlPattern: ':package',
staticExample: this.render({ version: '0.6.0' }),
keywords: ['atom'],
},
]
}
}
class APMLicense extends BaseAPMService {
@@ -127,6 +140,17 @@ class APMLicense extends BaseAPMService {
capture: ['repo'],
}
}
static get examples() {
return [
{
exampleUrl: 'vim-mode',
urlPattern: ':package',
staticExample: this.render({ license: 'MIT' }),
keywords: ['atom'],
},
]
}
}
module.exports = {

View File

@@ -11,11 +11,15 @@ module.exports = class AppVeyorCi extends AppVeyorBase {
return [
{
title: 'AppVeyor',
previewUrl: 'gruntjs/grunt',
exampleUrl: 'gruntjs/grunt',
urlPattern: ':user/:repo',
staticExample: this.render({ status: 'success' }),
},
{
title: 'AppVeyor branch',
previewUrl: 'gruntjs/grunt/master',
exampleUrl: 'gruntjs/grunt/master',
urlPattern: ':user/:repo/:branch',
staticExample: this.render({ status: 'success' }),
},
]
}

View File

@@ -86,19 +86,35 @@ class BaseService {
return '/' + [this.url.base, partialUrl].filter(Boolean).join('/')
}
static _makeStaticExampleUrl(serviceData) {
const badgeData = this._makeBadgeData({}, serviceData)
const color = badgeData.colorscheme || badgeData.colorB
return `/badge/${encodeURIComponent(
badgeData.text[0]
)}-${encodeURIComponent(badgeData.text[1])}-${color}`
}
/**
* Return an array of examples. Each example is prepared according to the
* schema in `lib/all-badge-examples.js`. Four keys are supported:
* - title
* - previewUrl
* - exampleUrl
* - documentation
* schema in `lib/all-badge-examples.js`.
*/
static prepareExamples() {
return this.examples.map(
({ title, previewUrl, query, exampleUrl, documentation }) => {
if (!previewUrl) {
throw Error(`Example for ${this.name} is missing required previewUrl`)
({
title,
query,
exampleUrl,
previewUrl,
urlPattern,
staticExample,
documentation,
}) => {
if (!previewUrl && !staticExample) {
throw Error(
`Example for ${
this.name
} is missing required previewUrl or staticExample`
)
}
const stringified = queryString.stringify(query)
@@ -106,10 +122,15 @@ class BaseService {
return {
title: title ? `${title}` : this.name,
previewUri: `${this._makeFullUrl(previewUrl, query)}.svg${suffix}`,
exampleUri: exampleUrl
? `${this._makeFullUrl(exampleUrl, query)}.svg${suffix}`
: undefined,
previewUri: staticExample
? `${this._makeStaticExampleUrl(staticExample)}.svg`
: `${this._makeFullUrl(previewUrl, query)}.svg${suffix}`,
urlPattern: urlPattern
? `${this._makeFullUrl(urlPattern, query)}.svg${suffix}`
: undefined,
documentation,
}
}

View File

@@ -16,17 +16,29 @@ const BaseService = require('./base')
require('../lib/register-chai-plugins.spec')
class DummyService extends BaseService {
static render({ namedParamA, queryParamA }) {
return {
message: `Hello namedParamA: ${namedParamA} with queryParamA: ${queryParamA}`,
}
}
async handle({ namedParamA }, { queryParamA }) {
return { message: `Hello ${namedParamA}${queryParamA}` }
return this.constructor.render({ namedParamA, queryParamA })
}
static get category() {
return 'cat'
}
static get examples() {
return [
{ previewUrl: 'World' },
{ previewUrl: 'World', query: { queryParamA: '!!!' } },
{
urlPattern: ':world',
exampleUrl: 'World',
staticExample: this.render({ namedParamA: 'foo', queryParamA: 'bar' }),
},
]
}
static get url() {
@@ -87,7 +99,9 @@ describe('BaseService', function() {
{ namedParamA: 'bar.bar.bar' },
{ queryParamA: '!' }
)
expect(serviceData).to.deep.equal({ message: 'Hello bar.bar.bar!' })
expect(serviceData).to.deep.equal({
message: 'Hello namedParamA: bar.bar.bar with queryParamA: !',
})
})
describe('Logging', function() {
@@ -294,7 +308,7 @@ describe('BaseService', function() {
const expectedFormat = 'svg'
expect(mockSendBadge).to.have.been.calledOnce
expect(mockSendBadge).to.have.been.calledWith(expectedFormat, {
text: ['cat', 'Hello bar?'],
text: ['cat', 'Hello namedParamA: bar with queryParamA: ?'],
colorscheme: 'lightgrey',
template: undefined,
logo: undefined,
@@ -307,17 +321,27 @@ describe('BaseService', function() {
describe('prepareExamples', function() {
it('returns the expected result', function() {
const [first, second] = DummyService.prepareExamples()
const [first, second, third] = DummyService.prepareExamples()
expect(first).to.deep.equal({
title: 'DummyService',
previewUri: '/foo/World.svg',
exampleUri: undefined,
previewUri: '/foo/World.svg',
urlPattern: undefined,
documentation: undefined,
})
expect(second).to.deep.equal({
title: 'DummyService',
previewUri: '/foo/World.svg?queryParamA=%21%21%21',
exampleUri: undefined,
previewUri: '/foo/World.svg?queryParamA=%21%21%21',
urlPattern: undefined,
documentation: undefined,
})
expect(third).to.deep.equal({
title: 'DummyService',
exampleUri: '/foo/World.svg',
previewUri:
'/badge/cat-Hello%20namedParamA%3A%20foo%20with%20queryParamA%3A%20bar-lightgrey.svg',
urlPattern: '/foo/:world.svg',
documentation: undefined,
})
})

View File

@@ -59,7 +59,9 @@ module.exports = class Cdnjs extends BaseJsonService {
static get examples() {
return [
{
previewUrl: 'jquery',
urlPattern: ':library',
exampleUrl: 'jquery',
staticExample: this.render({ version: '1.5.2' }),
keywords: ['cdn', 'cdnjs'],
},
]

View File

@@ -56,6 +56,12 @@ module.exports = class Clojars extends BaseJsonService {
}
static get examples() {
return [{ previewUrl: 'prismic' }]
return [
{
exampleUrl: 'prismic',
urlPattern: ':package',
staticExample: this.render({ clojar: 'clojar', version: '1.2' }),
},
]
}
}

View File

@@ -47,7 +47,7 @@ module.exports = class GemDownloads extends BaseJsonService {
}
}
_getLabel(version, info) {
static _getLabel(version, info) {
if (version) {
return 'downloads@' + version
} else {
@@ -65,7 +65,7 @@ module.exports = class GemDownloads extends BaseJsonService {
let version =
splitRubygem.length > 1 ? splitRubygem[splitRubygem.length - 1] : null
version = version === 'stable' ? version : semver.valid(version)
const label = this._getLabel(version, info)
const label = this.constructor._getLabel(version, info)
const json = await this.fetch({ repo, info })
let downloads
@@ -122,22 +122,42 @@ module.exports = class GemDownloads extends BaseJsonService {
return [
{
title: 'Gem',
previewUrl: 'dv/rails/stable',
exampleUrl: 'dv/rails/stable',
urlPattern: 'dv/:package/stable',
staticExample: this.render({
label: this._getLabel('stable', 'dv'),
downloads: 70000,
}),
keywords: ['ruby'],
},
{
title: 'Gem',
previewUrl: 'dv/rails/4.1.0',
exampleUrl: 'dv/rails/4.1.0',
urlPattern: 'dv/:package/:version',
staticExample: this.render({
label: this._getLabel('4.1.0', 'dv'),
downloads: 50000,
}),
keywords: ['ruby'],
},
{
title: 'Gem',
previewUrl: 'dtv/rails',
exampleUrl: 'dtv/rails',
urlPattern: 'dtv/:package',
staticExample: this.render({
label: this._getLabel(undefined, 'dtv'),
downloads: 70000,
}),
keywords: ['ruby'],
},
{
title: 'Gem',
previewUrl: 'dt/rails',
exampleUrl: 'dt/rails',
urlPattern: 'dt/:package',
staticExample: this.render({
label: this._getLabel(undefined, 'dt'),
downloads: 900000,
}),
keywords: ['ruby'],
},
]

View File

@@ -49,7 +49,9 @@ module.exports = class GemOwner extends BaseJsonService {
return [
{
title: 'Gems',
previewUrl: 'raphink',
exampleUrl: 'raphink',
urlPattern: ':user',
staticExample: this.render({ count: 34 }),
keywords: ['ruby'],
},
]

View File

@@ -25,8 +25,8 @@ const dailySchema = Joi.array()
.required()
module.exports = class GemRank extends BaseJsonService {
async fetch({ info, repo }) {
const totalRank = info === 'rt'
async fetch({ period, repo }) {
const totalRank = period === 'rt'
const endpoint = totalRank ? '/total_ranking.json' : '/daily_ranking.json'
const url = `http://bestgems.org/api/v1/gems/${repo}${endpoint}`
const schema = totalRank ? totalSchema : dailySchema
@@ -36,23 +36,20 @@ module.exports = class GemRank extends BaseJsonService {
})
}
static render({ message, count }) {
static render({ period, rank }) {
const count = Math.floor(100000 / rank)
let message = ordinalNumber(rank)
message += period === 'rt' ? '' : ' daily'
return {
message: message,
color: floorCountColor(count, 10, 50, 100),
}
}
async handle({ info, repo }) {
const json = await this.fetch({ info, repo })
const totalRank = info === 'rt'
const rank = totalRank ? json[0].total_ranking : json[0].daily_ranking
const count = Math.floor(100000 / rank)
let message = ordinalNumber(rank)
message += totalRank ? '' : ' daily'
return this.constructor.render({ message, count })
async handle({ period, repo }) {
const json = await this.fetch({ period, repo })
const rank = period === 'rt' ? json[0].total_ranking : json[0].daily_ranking
return this.constructor.render({ period, rank })
}
// Metadata
@@ -68,7 +65,7 @@ module.exports = class GemRank extends BaseJsonService {
return {
base: 'gem',
format: '(rt|rd)/(.+)',
capture: ['info', 'repo'],
capture: ['period', 'repo'],
}
}
@@ -76,12 +73,16 @@ module.exports = class GemRank extends BaseJsonService {
return [
{
title: 'Gem download rank',
previewUrl: 'rt/puppet',
exampleUrl: 'rt/puppet',
urlPattern: 'rt/:package',
staticExample: this.render({ period: 'rt', rank: 332 }),
keywords: ['ruby'],
},
{
title: 'Gem download rank (daily)',
previewUrl: 'rd/facter',
exampleUrl: 'rd/facter',
urlPattern: 'rd/:package',
staticExample: this.render({ period: 'rd', rank: 656 }),
keywords: ['ruby'],
},
]

View File

@@ -55,7 +55,9 @@ module.exports = class GemVersion extends BaseJsonService {
return [
{
title: 'Gem',
previewUrl: 'formatador',
exampleUrl: 'formatador',
urlPattern: ':package',
staticExample: this.render({ version: '2.1.0' }),
keywords: ['ruby'],
},
]

View File

@@ -23,7 +23,9 @@ class LibrariesIoDependentRepos extends LibrariesIoBase {
return [
{
title: 'Dependent repos (via libraries.io)',
previewUrl: 'npm/got',
exampleUrl: 'npm/got',
urlPattern: ':platform/:library',
staticExample: this.render({ dependentReposCount: 84000 }),
},
]
}

View File

@@ -23,7 +23,9 @@ class LibrariesIoDependents extends LibrariesIoBase {
return [
{
title: 'Dependents (via libraries.io)',
previewUrl: 'npm/got',
exampleUrl: 'npm/got',
urlPattern: ':platform/:library',
staticExample: this.render({ dependentCount: 2000 }),
},
]
}

View File

@@ -24,7 +24,9 @@ class LibrariesIoSourcerank extends LibrariesIoBase {
return [
{
title: 'Libraries.io SourceRank',
previewUrl: 'npm/got',
exampleUrl: 'npm/got',
urlPattern: ':platform/:library',
staticExample: this.render({ rank: 25 }),
},
]
}

View File

@@ -62,7 +62,9 @@ function DownloadsForInterval(interval) {
return [
{
title: 'npm',
previewUrl: 'localeval',
exampleUrl: 'localeval',
urlPattern: ':package',
staticExample: this.render({ downloads: 30000 }),
keywords: ['node'],
},
]

View File

@@ -20,11 +20,15 @@ module.exports = class NpmLicense extends NpmBase {
static get examples() {
return [
{
previewUrl: 'express',
exampleUrl: 'express',
urlPattern: ':package',
staticExample: this.render({ licenses: ['MIT'] }),
keywords: ['node'],
},
{
previewUrl: 'express',
exampleUrl: 'express',
urlPattern: ':package',
staticExample: this.render({ licenses: ['MIT'] }),
query: { registry_uri: 'https://registry.npmjs.com' },
keywords: ['node'],
},

View File

@@ -28,28 +28,38 @@ module.exports = class NpmVersion extends NpmBase {
return [
{
title: 'npm',
previewUrl: 'npm',
exampleUrl: 'npm',
urlPattern: ':package',
staticExample: this.render({ version: '6.3.0' }),
keywords: ['node'],
},
{
title: 'npm (scoped)',
previewUrl: '@cycle/core',
exampleUrl: '@cycle/core',
urlPattern: ':scope/:package',
staticExample: this.render({ version: '7.0.0' }),
keywords: ['node'],
},
{
title: 'npm (tag)',
previewUrl: 'npm/next',
exampleUrl: 'npm/next',
urlPattern: ':package/:tag',
staticExample: this.render({ tag: 'latest', version: '6.3.0' }),
keywords: ['node'],
},
{
title: 'npm (custom registry)',
previewUrl: 'npm/next',
exampleUrl: 'npm/next',
urlPattern: ':package/:tag',
staticExample: this.render({ tag: 'latest', version: '7.0.0' }),
query: { registry_uri: 'https://registry.npmjs.com' },
keywords: ['node'],
},
{
title: 'npm (scoped with tag)',
previewUrl: '@cycle/core/canary',
exampleUrl: '@cycle/core/canary',
staticExample: this.render({ tag: 'latest', version: '6.3.0' }),
urlPattern: ':scope/:package/:tag',
keywords: ['node'],
},
]

View File

@@ -24,16 +24,20 @@ module.exports = class UptimeRobotRatio extends UptimeRobotBase {
return [
{
title: 'Uptime Robot ratio (30 days)',
previewUrl: 'm778918918-3e92c097147760ee39d02d36',
exampleUrl: 'm778918918-3e92c097147760ee39d02d36',
urlPattern: ':monitor-specific-key',
staticExample: this.render({ ratio: 100 }),
},
{
title: 'Uptime Robot ratio (7 days)',
previewUrl: '7/m778918918-3e92c097147760ee39d02d36',
exampleUrl: '7/m778918918-3e92c097147760ee39d02d36',
urlPattern: '7/:monitor-specific-key',
staticExample: this.render({ ratio: 100 }),
},
]
}
static async render({ ratio }) {
static render({ ratio }) {
return {
message: `${ratio}%`,
color: ratioColor(ratio),

View File

@@ -21,12 +21,14 @@ module.exports = class UptimeRobotStatus extends UptimeRobotBase {
return [
{
title: 'Uptime Robot status',
previewUrl: 'm778918918-3e92c097147760ee39d02d36',
exampleUrl: 'm778918918-3e92c097147760ee39d02d36',
urlPattern: ':monitor-specific-key',
staticExample: this.render({ status: 2 }),
},
]
}
static async render({ status }) {
static render({ status }) {
switch (status) {
case 0:
return { message: 'paused', color: 'yellow' }