Skip to content

Commit

Permalink
Merge pull request #13 from devfreddy/wip-rollup-multi-config
Browse files Browse the repository at this point in the history
Alpha with rollupjs
  • Loading branch information
devfreddy authored Jan 3, 2020
2 parents ae80cbd + 7e35e8e commit 95551bb
Show file tree
Hide file tree
Showing 17 changed files with 1,355 additions and 51 deletions.
509 changes: 504 additions & 5 deletions package-lock.json

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
"npm": ">=5"
},
"scripts": {
"clean": "rimraf dist/",
"test": "cross-env CI=1 react-scripts test --env=jsdom",
"test:watch": "react-scripts test --env=jsdom",
"build": "rollup -c",
"build": "npm run clean && rollup -c",
"start": "rollup -c -w",
"prepare": "npm run build",
"predeploy": "cd example && npm install && npm run build",
Expand All @@ -27,12 +28,11 @@
"peerDependencies": {
"prop-types": "^15.5.4",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
"react-dom": "^15.0.0 || ^16.0.0",
"nr1": ""
},
"devDependencies": {
"@newrelic/eslint-plugin-newrelic": "^0.3.0",
"eslint": "^6.6.0",
"prettier": "^1.19.1",
"@semantic-release/changelog": "^3.0.5",
"@semantic-release/git": "^7.0.18",
"@svgr/rollup": "^2.4.1",
Expand All @@ -43,10 +43,16 @@
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"cross-env": "^5.1.4",
"eslint": "^6.6.0",
"gh-pages": "^1.2.0",
"node-sass": "^4.13.0",
"prettier": "^1.19.1",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "^1.1.4",
"react-moment": "^0.9.7",
"moment": "^2.24.0",
"rimraf": "^3.0.0",
"rollup": "^0.64.1",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-commonjs": "^9.1.3",
Expand All @@ -57,5 +63,6 @@
},
"files": [
"dist"
]
],
"dependencies": {}
}
87 changes: 72 additions & 15 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,34 @@ import svgr from '@svgr/rollup';

import pkg from './package.json';

export default {
const glob = require('glob');

/*
* Generate an instance for each "config"
*/
function getPlugins() {
return [
external(),
postcss({
extract: true,
modules: true,
use: ['sass']
}),
url(),
svgr(),
babel({
exclude: 'node_modules/**',
plugins: ['external-helpers']
}),
resolve(),
commonjs()
];
}

/*
* Base Config
*/
const baseConfig = {
input: 'src/index.js',
output: [
{
Expand All @@ -22,18 +49,48 @@ export default {
sourcemap: true
}
],
plugins: [
external(),
postcss({
modules: true
}),
url(),
svgr(),
babel({
exclude: 'node_modules/**',
plugins: ['external-helpers']
}),
resolve(),
commonjs()
]
plugins: getPlugins()
};

const allConfigs = [];
allConfigs.push(baseConfig);

/*
* Build a rollup config for every component
*
* https://github.com/egoist/rollup-plugin-postcss/issues/160
*
* Generate a CSS output for each component so we can selectively pull in per-component styles
*
* The downside to this approach is the JS code is output twice. Once because we're exporting it
* for easy import, and once for the css file generation.
*
* rollup-plugin-postcss is only good at consolidating css output, and does not seem actively maintained
* We would need to fork it, and allow for per css input file output
*/

const modularStyles = false; // Leaving here for future evaluation, but not currently in use

if (modularStyles) {
const componentEntryPoints = glob.sync('./src/components/*/index.js');
componentEntryPoints.forEach(entryPoint => {
const outputs = baseConfig.output;
const plugins = getPlugins();
const outputPath = entryPoint
.replace('src/', 'dist/')
.replace('/index.js', '');

const config = {
...baseConfig,
input: entryPoint,
output: outputs.map(outputDest => {
return { ...outputDest, file: outputPath };
}),
plugins
};

allConfigs.push(config);
});
}

export default allConfigs;
53 changes: 53 additions & 0 deletions src/components/AccountDropdown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# AccountDropdown

## Description

Applications (Nerdpacks) developed in New Relic One are limited (for security purposes) to data in the account they are installed (subscribed) to and hierarchically to any child accounts.

Often the goal is to limit the view by a given account to ensure accurate context.

This component provides a common interface for choosing an account with a callback (`onSelect`) that allows for integration into the rest of your application.

## Installation

1. Install nr1-community

```bash
npm i nr1-community
```

2. Install peer dependencies

```bash
npm i moment react-moment
```

3. Import styles

Add:

```scss
@import '~nr1-community/dist/components/AccountDropdown.css';
```

to your `styles.scss`

## Usage

```jsx
import { AccountDropdown } from 'nr1-community';

render () {
<AccountDropdown></AccountDropdown>
}
```

## Props

```jsx
onSelect: PropTypes.func,
urlState: PropTypes.object,
className: PropTypes.string,
style: PropTypes.object,
title: PropTypes.string
```
176 changes: 176 additions & 0 deletions src/components/AccountDropdown/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
navigation,
UserStorageQuery,
UserStorageMutation,
AccountsQuery,
Dropdown,
DropdownItem,
Spinner
} from 'nr1';

import styles from './styles.scss';

const collection = 'nr1-community:AccountDropdown';
const documentId = 'default-account';

export class AccountDropdown extends React.Component {
static propTypes = {
onSelect: PropTypes.func,
urlState: PropTypes.object,
className: PropTypes.string,
style: PropTypes.object,
title: PropTypes.string
};

static defaultProps = {
title: 'Select account...'
};

constructor(props) {
super(props);

this.state = {
accounts: null,
defaultAccount: undefined,
selected: null
};

this.select = this.select.bind(this);
}

async componentDidMount() {
await Promise.all([this.loadAccounts(), this.loadDefaultAccount()]);

this.setState(state => {
if (this.props.urlState && this.props.urlState.account) {
const account = this.state.accounts.find(
account => account.id === this.props.urlState.account
);
if (account) {
return {
selectedFromUrlState: true,
selected: account
};
}
}

if (state.selected === null && state.defaultAccount && state.accounts) {
const account = this.state.accounts.find(
account => account.id === this.state.defaultAccount
);
if (account) {
return {
selected: account
};
}
}

return null;
});
}

async componentDidUpdate(prevProps, prevState) {
const prevAccount = prevState.selected;
const account = this.state.selected;

if (account && (!prevAccount || account.id !== prevAccount.id)) {
this.props.onSelect(account);

if (!this.state.selectedFromUrlState) {
if (this.state.selected.id !== this.state.defaultAccount) {
this.updateDefaultAccount(this.state.selected);
}

if (
this.props.urlState &&
this.state.selected.id !== this.props.urlState.account
) {
navigation.setUrlState({
account: this.state.selected.id
});
}
}
}
}

async loadDefaultAccount() {
const result = await UserStorageQuery.query({ collection, documentId });
const id =
((((result.data || {}).actor || {}).nerdStorage || {}).document || {})
.id || null;
this.setState(() => ({
defaultAccount: id
}));
}

async loadAccounts() {
// eslint-disable-next-line no-unused-vars
const { loading, data, errors } = await AccountsQuery.query();

if (!data) {
// TO DO
}

if (errors) {
// TO DO
}

this.setState({
accounts: data
});
}

async updateDefaultAccount(account) {
await UserStorageMutation.mutate({
actionType: UserStorageMutation.ACTION_TYPE.WRITE_DOCUMENT,
collection,
documentId,
document: { id: account.id }
});

this.setState({
defaultAccount: account.id
});
}

select(account) {
this.setState(state => {
if (!state.selected || state.selected.id !== account.id) {
return {
selectedFromUrlState: false,
selected: account
};
}

return {};
});
}

render() {
// eslint-disable-next-line no-unused-vars
const { className, style, title } = this.props;
const { accounts, defaultAccount, selected } = this.state;

if (!accounts || defaultAccount === undefined) {
return <Spinner />;
}

const items = accounts.map(account => (
<DropdownItem key={account.id} onClick={() => this.select(account)}>
{account.name}
</DropdownItem>
));

return (
<Dropdown
title={(selected || {}).name || title}
className={styles.big}
style={style}
>
{items}
</Dropdown>
);
}
}
3 changes: 3 additions & 0 deletions src/components/AccountDropdown/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.big {
min-height: 150px;
}
Loading

0 comments on commit 95551bb

Please sign in to comment.