diff --git a/.extended-webpackrc.js b/.extended-webpackrc.js
new file mode 100644
index 0000000..902e04b
--- /dev/null
+++ b/.extended-webpackrc.js
@@ -0,0 +1,15 @@
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: /\.(png|jpe?g|gif|svg|ttf|eot|woff2)$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {},
+ },
+ ],
+ },
+ ],
+ },
+};
\ No newline at end of file
diff --git a/nerdlets/maintainer-dashboard/index.js b/nerdlets/maintainer-dashboard/index.js
index efe4271..dd3b379 100644
--- a/nerdlets/maintainer-dashboard/index.js
+++ b/nerdlets/maintainer-dashboard/index.js
@@ -34,10 +34,14 @@ import {
Icon,
Modal,
TextField,
- Link
+ Link,
+ Select,
+ SelectItem,
+ UserStorageMutation,
} from 'nr1';
-import { GitHub } from 'react-feather';
import { getGithubData } from './githubData';
+import { IssueLabel, KNOWN_LABEL_COLORS } from './issueLabel';
+import SettingsUI from './settings';
import PullRequestLogo from './img/git-pull-request-16.svg';
import IssueLogo from './img/issue-opened-16.svg';
import NewRelicUsers from './data/userdata-sample.json';
@@ -48,21 +52,8 @@ const STALE_TIME = 1000 * 60 * 60 * 24 * 14; // 2 weeks in ms
const RELICS = Object.values(NewRelicUsers)
.filter(u => u.user_type === 'relic' || u.user_type === 'contractor')
- .map(u => u.login);
-
-const KNOWN_LABEL_COLORS = new Map([
- ['bug', 'd73a4a'],
- ['documentation', '0075ca'],
- ['duplicate', 'cfd3d7'],
- ['enhancement', 'a2eeef'],
- ['good first issue', '7057ff'],
- ['help wanted', '008672'],
- ['invalid', 'e4e669'],
- ['question', 'd876e3'],
- ['wontfix', 'ffffff'],
- ['dependencies', '0366d6'],
- ['repolinter', 'fbca04'],
-]);
+ .map(u => u.login)
+ .sort();
const REPOS = [
'newrelic/go-agent',
@@ -117,15 +108,6 @@ const REPOS = [
'newrelic/k8s-webhook-cert-manager' */
];
-// stolen from https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
-function pickTextColorBasedOnBgColor(bgColor, lightColor, darkColor) {
- const color = bgColor.charAt(0) === '#' ? bgColor.substring(1, 7) : bgColor;
- const r = parseInt(color.substring(0, 2), 16); // hexToR
- const g = parseInt(color.substring(2, 4), 16); // hexToG
- const b = parseInt(color.substring(4, 6), 16); // hexToB
- return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? darkColor : lightColor;
-}
-
class IssueTable extends React.PureComponent {
constructor(props) {
super(props);
@@ -226,44 +208,7 @@ class IssueTable extends React.PureComponent {
}),
filterValue: cell => cell.map(({ name }) => name),
formatter: cell =>
- cell.map(({ name, color }) => {
- const bgColor = KNOWN_LABEL_COLORS.has(name)
- ? KNOWN_LABEL_COLORS.get(name)
- : color;
- return (
-
-
- {name}
-
-
- );
- }),
+ cell.map(({ name, color }) => ),
},
{
dataField: 'title',
@@ -343,104 +288,10 @@ export default class MaintainerDashboard extends React.Component {
return (
this.setState({ settingsHidden: true })}>
-
-
-
- Dashboard Configuration
-
-
-
-
- Supply a personal access token to allow this dashboard to access GitHub's GraphQL API. The token does not need to have any special permissions.
- See the{' '}
- GitHub documentation for
- more information on creating and using personal access tokens.
-
-
-
-
- Your personal access token will stored in NerdStorage vault, and only be accessible to you. The token can be removed or revoked at any time.
-
-
-
-
-
-
-
-
-
- Remove Token
-
-
-
-
-
-
- Select which repositories you would like this tool to scan.
-
-
-
- ({ repo }))
- )}
- >
-
- 'delete'}
- width="80px"
- />
- item.repo}>
- Repositories
-
-
- {({ item }) =>
- item.first ? (
-
-
-
- {}}
- >
- Add another repository
-
-
-
- ) : (
-
-
- {}}
- />
-
- {item.repo}
-
- )
- }
-
-
-
+ ({name, color}))}
+ onSubmit={() => this.setState({ settingsHidden: true })} />
{!this.state.newSearchItems || !this.state.staleSearchItems ? (
diff --git a/nerdlets/maintainer-dashboard/issueLabel.js b/nerdlets/maintainer-dashboard/issueLabel.js
new file mode 100644
index 0000000..28a78b7
--- /dev/null
+++ b/nerdlets/maintainer-dashboard/issueLabel.js
@@ -0,0 +1,66 @@
+import React from 'react';
+import { BlockText } from 'nr1';
+
+export const KNOWN_LABEL_COLORS = new Map([
+ ['bug', 'd73a4a'],
+ ['documentation', '0075ca'],
+ ['duplicate', 'cfd3d7'],
+ ['enhancement', 'a2eeef'],
+ ['good first issue', '7057ff'],
+ ['help wanted', '008672'],
+ ['invalid', 'e4e669'],
+ ['question', 'd876e3'],
+ ['wontfix', 'ffffff'],
+ ['dependencies', '0366d6'],
+ ['repolinter', 'fbca04']
+]);
+
+// stolen from https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
+function pickTextColorBasedOnBgColor(bgColor, lightColor, darkColor) {
+ const color = bgColor.charAt(0) === '#' ? bgColor.substring(1, 7) : bgColor;
+ const r = parseInt(color.substring(0, 2), 16); // hexToR
+ const g = parseInt(color.substring(2, 4), 16); // hexToG
+ const b = parseInt(color.substring(4, 6), 16); // hexToB
+ return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? darkColor : lightColor;
+}
+
+export class IssueLabel extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ const bgColor = KNOWN_LABEL_COLORS.has(this.props.name)
+ ? KNOWN_LABEL_COLORS.get(this.props.name)
+ : this.props.color;
+ return (
+
+
+ {this.props.name}
+
+
+ );
+ }
+}
diff --git a/nerdlets/maintainer-dashboard/settings.js b/nerdlets/maintainer-dashboard/settings.js
new file mode 100644
index 0000000..928c758
--- /dev/null
+++ b/nerdlets/maintainer-dashboard/settings.js
@@ -0,0 +1,368 @@
+import gql from 'graphql-tag';
+import React from 'react';
+import {
+ HeadingText,
+ Stack,
+ StackItem,
+ Button,
+ BlockText,
+ Icon,
+ TextField,
+ Link,
+ Select,
+ SelectItem
+} from 'nr1';
+import { Multiselect } from 'react-widgets';
+import { IssueLabel } from './issueLabel';
+import {
+ writeToken,
+ writeSettings,
+ readToken,
+ readSettings,
+ removeToken,
+} from './storageUtil';
+
+const GET_CUR_USER_INFO = gql`
+ query($repoCursor: String) {
+ viewer {
+ login
+ repositories(
+ affiliations: [OWNER, COLLABORATOR, ORGANIZATION_MEMBER]
+ first: 100
+ after: $repoCursor
+ ) {
+ nodes {
+ nameWithOwner
+ }
+ }
+ }
+ }
+`;
+
+export default class SettingsUI extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ repoValue: [],
+ labelValue: [],
+ userValue: [],
+ timeUnit: 60,
+ timeValue: 0,
+ token: '',
+ patStatus: {},
+ submitting: false
+ };
+ this.handlePATToken = this.handlePATToken.bind(this);
+ this.handlePATRemove = this.handlePATRemove.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.curFetchIndex = 0;
+ }
+
+ async componentDidMount() {
+ const [prevToken, prevSettings] = await Promise.all([
+ readToken(),
+ readSettings()
+ ]);
+ // add saved values back into settings
+ // TODO: do not write the previous token back to the input form, as it may be unsafe
+ if (prevSettings) {
+ const { repos, labels, users, staleTime } = prevSettings;
+ this.setState({
+ repoValue: repos || [],
+ labelValue: labels || [],
+ userValue: users || [],
+ timeValue: staleTime ? staleTime / 60 : 0,
+ patStatus: prevToken ? { valid: true } : {},
+ token: prevToken || ''
+ });
+ }
+ // re-test the PAT
+ if (prevToken) await this.updateUserInfo(prevToken);
+ }
+
+ async updateUserInfo(token) {
+ // indicate we are currently testing the token
+ this.setState({
+ patStatus: {
+ testing: true
+ }
+ });
+ // test the token with a user information query
+ const curNum = ++this.curFetchIndex;
+ return this.props.client
+ .query({
+ query: GET_CUR_USER_INFO,
+ fetchPolicy: 'network-only',
+ context: {
+ headers: {
+ authorization: `Bearer ${token}`
+ }
+ }
+ })
+ .then(({ data }) => {
+ // prevent race conditions
+ if (curNum === this.curFetchIndex) {
+ this.setState({
+ patStatus: {
+ valid: true,
+ userName: data?.viewer?.login,
+ repoOptions: data?.viewer?.repositories?.nodes?.map?.(
+ ({ nameWithOwner }) => nameWithOwner
+ )
+ }
+ });
+ }
+ })
+ .catch(e => {
+ // prevent race condition
+ if (curNum === this.curFetchIndex) {
+ if (e?.networkError?.statusCode === 401)
+ this.setState({
+ patStatus: {
+ valid: false,
+ message: 'Token returned authorization error'
+ }
+ });
+ else
+ this.setState({
+ patStatus: {
+ valid: false,
+ message: 'Unknown GitHub API error'
+ }
+ });
+ }
+ });
+ }
+
+ handlePATToken(event) {
+ const token = event.target.value;
+ this.setState({ token });
+ // error if the token is invalid
+ if (token.length < 20) {
+ return this.setState({
+ patStatus: {
+ valid: false,
+ message: 'Token is less than 20 characters in length'
+ }
+ });
+ }
+ // else update the user information using the token
+ this.updateUserInfo(token);
+ }
+
+ async handlePATRemove() {
+ this.setState({ token: '', patStatus: {} });
+ await removeToken();
+ }
+
+ async handleSubmit() {
+ // tell the user we are currently submitting
+ this.setState({ submitting: true });
+ // write the token to NerdVault
+ // write the everything else to UserStorage
+ await Promise.all([
+ writeToken(this.state.token),
+ writeSettings({
+ repos: this.state.repoValue,
+ users: this.state.userValue,
+ labels: this.state.labelValue,
+ staleTime: this.state.timeValue * this.state.timeUnit
+ })
+ ]);
+ // tell the user we're done
+ this.setState({ submitting: false });
+ // call the callback
+ this.props.onSubmit();
+ }
+
+ getFormError() {
+ if (!this.state.patStatus.valid) return 'Please enter a valid PAT';
+ if (this.state.repoValue.length === 0)
+ return 'Please select at least one repository';
+ else if (isNaN(this.state.timeValue) || this.state.timeValue === 0)
+ return 'Please enter a valid stale time';
+ return null;
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/nerdlets/maintainer-dashboard/storageUtil.js b/nerdlets/maintainer-dashboard/storageUtil.js
new file mode 100644
index 0000000..472094e
--- /dev/null
+++ b/nerdlets/maintainer-dashboard/storageUtil.js
@@ -0,0 +1,49 @@
+import { UserSecretsMutation, UserSecretsQuery } from '@newrelic/nr1-community';
+import { UserStorageMutation, UserStorageQuery } from 'nr1';
+
+const GH_TOKEN_KEY = 'githubToken';
+const SETTINGS_KEY = 'nr1OspoSettings';
+
+export async function writeToken(token) {
+ return UserSecretsMutation.mutate({
+ actionType: UserSecretsMutation.ACTION_TYPE.WRITE_SECRET,
+ name: GH_TOKEN_KEY,
+ value: token
+ });
+}
+
+export async function readToken() {
+ const { data } = await UserSecretsQuery.query({
+ name: GH_TOKEN_KEY
+ });
+ return data?.value;
+}
+
+export async function removeToken() {
+ return UserSecretsMutation.mutate({
+ actionType: UserSecretsMutation.ACTION_TYPE.DELETE_SECRET,
+ name: GH_TOKEN_KEY
+ });
+}
+
+export async function writeSettings({ repos, labels, users, staleTime }) {
+ return UserStorageMutation.mutate({
+ actionType: UserStorageMutation.ACTION_TYPE.WRITE_DOCUMENT,
+ collection: SETTINGS_KEY,
+ documentId: SETTINGS_KEY,
+ document: {
+ repos,
+ labels,
+ users,
+ staleTime
+ }
+ });
+}
+
+export async function readSettings() {
+ const { data } = await UserStorageQuery.query({
+ collection: SETTINGS_KEY,
+ documentId: SETTINGS_KEY
+ });
+ return data;
+}
diff --git a/nerdlets/maintainer-dashboard/styles.scss b/nerdlets/maintainer-dashboard/styles.scss
index 197777e..18b7567 100644
--- a/nerdlets/maintainer-dashboard/styles.scss
+++ b/nerdlets/maintainer-dashboard/styles.scss
@@ -1,5 +1,8 @@
-@use 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
-@use 'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css';
+@import '~react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
+@import '~react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css';
+$font-path: '~react-widgets/lib/fonts';
+$img-path: '~react-widgets/lib/img';
+@import '~react-widgets/lib/scss/react-widgets';
.ospo-tableheader {
line-height: 30px;
diff --git a/package-lock.json b/package-lock.json
index 00cccac..d86c7f1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -142,12 +142,12 @@
}
},
"@newrelic/nr1-community": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@newrelic/nr1-community/-/nr1-community-1.2.0.tgz",
- "integrity": "sha512-lYPJRxoUjqIEVlSft/w3qmp4iSODKx8twDkVEYiFnSWVZUtfy24dK7nVKijBP8GXLP4pwGz7cGvGNzdaSje2MA==",
+ "version": "1.3.0-alpha.5",
+ "resolved": "https://registry.npmjs.org/@newrelic/nr1-community/-/nr1-community-1.3.0-alpha.5.tgz",
+ "integrity": "sha512-wBY4qhTIDgRmkf3/nRGxpwiBj49b7dJDVM41kKhT9inZfp9pFoCWGDgbf85Mg/qujwgHNuc5ZbTxxqBsvZQH9A==",
"requires": {
"crypto-random-string": "^3.2.0",
- "date-fns": "^2.13.0",
+ "date-fns": "^2.15.0",
"funnel-graph-js": "^1.4.2",
"lodash.get": "^4.4.2",
"nice-color-palettes": "^3.0.0"
@@ -223,6 +223,20 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.5.tgz",
"integrity": "sha512-jVFzDV6NTbrLMxm4xDSIW/gKnk8rQLF9wAzLWIOg+5nU6ACrIMndeBdXci0FGtqJbP9tQvm6V39eshc96TO2wQ=="
},
+ "@types/prop-types": {
+ "version": "15.7.3",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
+ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
+ },
+ "@types/react": {
+ "version": "16.9.52",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.52.tgz",
+ "integrity": "sha512-EHRjmnxiNivwhGdMh9sz1Yw9AUxTSZFxKqdBWAAzyZx3sufWwx6ogqHYh/WB1m/I4ZpjkoZLExF5QTy2ekVi/Q==",
+ "requires": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.2"
+ }
+ },
"@types/zen-observable": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.1.tgz",
@@ -716,6 +730,11 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag=="
},
+ "date-arithmetic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-3.1.0.tgz",
+ "integrity": "sha1-H80D29UEudvuK5B4yFpfHH08wtM="
+ },
"date-fns": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
@@ -738,6 +757,11 @@
"mimic-response": "^1.0.0"
}
},
+ "deconstruct-number-format": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/deconstruct-number-format/-/deconstruct-number-format-0.0.1.tgz",
+ "integrity": "sha1-+7XX3NRb0rL6Dlee2RtZx+KbOGo="
+ },
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -1408,6 +1432,20 @@
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
"dev": true
},
+ "format-number": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/format-number/-/format-number-2.0.2.tgz",
+ "integrity": "sha1-i+Kqb6bvXsQ4MIkrHa7nJwX5tGI="
+ },
+ "format-number-with-string": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/format-number-with-string/-/format-number-with-string-0.0.2.tgz",
+ "integrity": "sha1-65bo8WQMkh90FEZsz43LO7aALLo=",
+ "requires": {
+ "deconstruct-number-format": "~0.0.1",
+ "format-number": "^2.0.1"
+ }
+ },
"fs-extra": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
@@ -1719,6 +1757,14 @@
"side-channel": "^1.0.2"
}
},
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -2381,6 +2427,25 @@
"react-is": "^16.8.1"
}
},
+ "prop-types-extra": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
+ "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
+ "requires": {
+ "react-is": "^16.3.2",
+ "warning": "^4.0.0"
+ },
+ "dependencies": {
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ }
+ }
+ },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -2435,6 +2500,15 @@
"version": "https://gitpkg.now.sh/prototypicalpro/react-bootstrap-table2/packages/react-bootstrap-table2-filter?feat/with-build",
"integrity": "sha512-3cyXzg8a4Ic7YRsoY2ck6m/2/SMayg15iZ3bhxcEU5vy7Shzbk9STEeuqnLIfOhK22u7x8p1fUnAas1BinvdWA=="
},
+ "react-component-managers": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-component-managers/-/react-component-managers-3.2.2.tgz",
+ "integrity": "sha512-SqtB09hS1ir0koBNybvNbNAB3k/r7IbIGbXSxvkkTV0m50s+4oJ59KYsbPAQ/2DhE169Rc5V26d674EcGcDbGA==",
+ "requires": {
+ "prop-types": "^15.6.1",
+ "spy-on-component": "^1.1.0"
+ }
+ },
"react-dom": {
"version": "16.6.3",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.6.3.tgz",
@@ -2447,19 +2521,16 @@
"scheduler": "^0.11.2"
}
},
- "react-feather": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.8.tgz",
- "integrity": "sha512-J0dCEOvOxpovHeOVj3+8mAhN3/UERTfX6rSxnV6x4E+0s+STY536jhSjRfpSvTQA0SSFjYr4KrpPfdsLmK+zZg==",
- "requires": {
- "prop-types": "^15.7.2"
- }
- },
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
"react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
@@ -2471,6 +2542,53 @@
"prop-types": "^15.6.2"
}
},
+ "react-widgets": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/react-widgets/-/react-widgets-4.6.0.tgz",
+ "integrity": "sha512-rfQhu5Eoh2V/qhjkJQy4ZrtGYmldmpyCN6pNFWldGhAUVGTRr8reXfVqD/LDzOycal8XeRVUaW6oABPSgn14FQ==",
+ "requires": {
+ "classnames": "^2.2.6",
+ "date-arithmetic": "^3.1.0",
+ "dom-helpers": "^3.3.1",
+ "invariant": "^2.2.4",
+ "prop-types-extra": "^1.0.1",
+ "react-component-managers": "^3.1.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "react-transition-group": "^2.4.0",
+ "uncontrollable": "^7.1.1",
+ "warning": "^3.0.0"
+ },
+ "dependencies": {
+ "dom-helpers": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+ "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+ "requires": {
+ "@babel/runtime": "^7.1.2"
+ }
+ },
+ "react-transition-group": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
+ "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
+ "requires": {
+ "dom-helpers": "^3.4.0",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ }
+ }
+ },
+ "react-widgets-simple-number": {
+ "version": "4.1.25",
+ "resolved": "https://registry.npmjs.org/react-widgets-simple-number/-/react-widgets-simple-number-4.1.25.tgz",
+ "integrity": "sha512-xBFx2IHPxs2cxvLePgj6S9aBtW04vhym4+tybEenQOGUti2kG/PcRA5Sf1xRjDxjX3TV3aeKvrBsZFFYXkfKtA==",
+ "requires": {
+ "deconstruct-number-format": "^0.0.1",
+ "format-number-with-string": "^0.0.2"
+ }
+ },
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@@ -2708,6 +2826,11 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
+ "spy-on-component": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/spy-on-component/-/spy-on-component-1.1.3.tgz",
+ "integrity": "sha512-a7jgnoBSdkcDWIQQwtEgUq4etajwG6+wGIjfC9ARUKwKOdHxJd+utgHTgLn81ETizpsw4xddUS3W8VePedtaIQ=="
+ },
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -2939,6 +3062,17 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
},
+ "uncontrollable": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.1.1.tgz",
+ "integrity": "sha512-EcPYhot3uWTS3w00R32R2+vS8Vr53tttrvMj/yA1uYRhf8hbTG2GyugGqWDY0qIskxn0uTTojVd6wPYW9ZEf8Q==",
+ "requires": {
+ "@babel/runtime": "^7.6.3",
+ "@types/react": "^16.9.11",
+ "invariant": "^2.2.4",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ },
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
@@ -2983,6 +3117,14 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 7248aff..18da06d 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"email": "opensource+nr1-ospo@newrelic.com"
},
"dependencies": {
- "@newrelic/nr1-community": "latest",
+ "@newrelic/nr1-community": "^1.3.0-alpha.5",
"apollo-cache-inmemory": "^1.6.5",
"apollo-client": "^2.6.8",
"apollo-link": "^1.2.13",
@@ -29,7 +29,8 @@
"react-apollo": "~2",
"react-bootstrap-table-next": "https://gitpkg.now.sh/prototypicalpro/react-bootstrap-table2/packages/react-bootstrap-table2?feat/with-build",
"react-bootstrap-table2-filter": "https://gitpkg.now.sh/prototypicalpro/react-bootstrap-table2/packages/react-bootstrap-table2-filter?feat/with-build",
- "react-feather": "^2.0.8"
+ "react-widgets": "^4.6.0",
+ "react-widgets-simple-number": "^4.1.25"
},
"browserslist": [
"last 2 versions",