0
bundle/.yarnclean
Normal file
@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"license": "MPL-2.0",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=development PORT=3069 REACT_APP_GQL_PORT=3069 REACT_APP_GQL_PROTOCOL=http node src/index.js",
|
||||
"start": "UMD=1 NODE_ENV=development PORT=3069 REACT_APP_GQL_PORT=3069 REACT_APP_GQL_HOSTNAME=localhost REACT_APP_GQL_PROTOCOL=http node src/index.js",
|
||||
"lint-ci": "echo 0",
|
||||
"lint": "echo 0",
|
||||
"test-ci": "echo 0",
|
||||
@ -12,12 +12,14 @@
|
||||
"prepublish": "echo 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"brok": "^2.0.0",
|
||||
"brule": "^3.1.0",
|
||||
"cloudapi-gql": "^4.6.0",
|
||||
"hapi": "^17.2.0",
|
||||
"hapi-triton-auth": "^1.0.0",
|
||||
"inert": "^5.1.0",
|
||||
"joyent-navigation": "*",
|
||||
"my-images-console": "*",
|
||||
"my-joy-beta": "*",
|
||||
"rollover": "^1.0.0"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
const Brule = require('brule');
|
||||
const Hapi = require('hapi');
|
||||
const Rollover = require('rollover');
|
||||
const Brok = require('brok');
|
||||
const { homedir } = require('os');
|
||||
const { join } = require('path');
|
||||
|
||||
@ -10,7 +11,6 @@ process.env.SDC_KEY_PATH =
|
||||
process.env.SDC_KEY_PATH || join(homedir(), '.ssh/id_rsa');
|
||||
|
||||
const Sso = require('hapi-triton-auth');
|
||||
const Ui = require('my-joy-beta');
|
||||
const Nav = require('joyent-navigation');
|
||||
const Api = require('cloudapi-gql');
|
||||
|
||||
@ -24,16 +24,28 @@ const {
|
||||
SDC_URL,
|
||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
||||
ROLLBAR_SERVER_TOKEN,
|
||||
NODE_ENV = 'development'
|
||||
NODE_ENV = 'development',
|
||||
CONSOLE = 'my-joy-beta'
|
||||
} = process.env;
|
||||
|
||||
const Ui = require(CONSOLE);
|
||||
|
||||
const server = Hapi.server({
|
||||
compression: {
|
||||
minBytes: 1
|
||||
},
|
||||
debug: {
|
||||
request: ['error']
|
||||
},
|
||||
port: PORT,
|
||||
host: '127.0.0.1'
|
||||
});
|
||||
|
||||
async function main() {
|
||||
await server.register([
|
||||
{
|
||||
plugin: Brok
|
||||
},
|
||||
{
|
||||
plugin: Rollover,
|
||||
options: {
|
||||
|
@ -20,16 +20,16 @@
|
||||
"dependencies": {
|
||||
"remcalc": "^1.0.10",
|
||||
"rnd-id": "^2.0.2",
|
||||
"styled-components": "^3.1.4"
|
||||
"styled-components": "^3.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"eslint": "^4.16.0",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
"react": "^16.2.0",
|
||||
"redrun": "^5.10.0"
|
||||
"redrun": "^5.10.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.2.0"
|
||||
|
@ -1,3 +1,7 @@
|
||||
{
|
||||
"presets": "joyent-portal"
|
||||
"ignore": ["_document.js"],
|
||||
"presets": [["joyent-portal", {
|
||||
"aliases": true,
|
||||
"autoAliases": true
|
||||
}]]
|
||||
}
|
||||
|
@ -2,3 +2,4 @@
|
||||
coverage
|
||||
dist
|
||||
build
|
||||
lib/app
|
2
packages/images/.gitignore
vendored
@ -21,3 +21,5 @@ yarn-error.log*
|
||||
|
||||
**/__diff_output__
|
||||
|
||||
|
||||
lib/app
|
@ -1,22 +1,104 @@
|
||||
const Inert = require('inert');
|
||||
const Path = require('path');
|
||||
const Execa = require('execa');
|
||||
const { readFile } = require('mz/fs');
|
||||
const RenderReact = require('hapi-render-react');
|
||||
const Wreck = require('wreck');
|
||||
const Url = require('url');
|
||||
|
||||
exports.register = async server => {
|
||||
await Execa('npm', ['run', 'build'], {
|
||||
cwd: Path.join(__dirname, '..'),
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
const indexFile = await readFile(
|
||||
Path.join(__dirname, '../build/index.html'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
await server.register(Inert);
|
||||
await server.register([
|
||||
{
|
||||
plugin: Inert
|
||||
},
|
||||
{
|
||||
plugin: RenderReact,
|
||||
options: {
|
||||
relativeTo: Path.join(__dirname, 'app')
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
server.route([
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/service-worker.js',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: {
|
||||
file: {
|
||||
path: Path.join(__dirname, '../build/service-worker.js')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/favicon.ico',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: {
|
||||
file: {
|
||||
path: Path.join(__dirname, '../build/favicon.ico')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/font/{pathname*}',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: async (request, h) => {
|
||||
const { params } = request;
|
||||
const { pathname } = params;
|
||||
|
||||
const location = Url.format({
|
||||
protocol: 'https:',
|
||||
slashes: true,
|
||||
host: 'fonts.gstatic.com',
|
||||
pathname
|
||||
});
|
||||
|
||||
const res = await Wreck.request('GET', location);
|
||||
return h.response(res);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/fonts/css',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: async (request, h) => {
|
||||
const { query, headers } = request;
|
||||
const { family } = query;
|
||||
const { host } = headers;
|
||||
const url = Url.parse(`http://${host}`);
|
||||
|
||||
const location = Url.format({
|
||||
protocol: 'https:',
|
||||
slashes: true,
|
||||
host: 'fonts.googleapis.com',
|
||||
pathname: '/css',
|
||||
query: { family }
|
||||
});
|
||||
|
||||
const res = await Wreck.request('GET', location);
|
||||
const body = await Wreck.read(res);
|
||||
|
||||
const _body = body.toString().replace(
|
||||
/https:\/\/fonts\.gstatic\.com/g,
|
||||
`http://${url.host}/font`
|
||||
);
|
||||
|
||||
return h
|
||||
.response(_body)
|
||||
.header('content-type', res.headers['content-type'])
|
||||
.header('expires', res.headers.expires)
|
||||
.header('date', res.headers.date)
|
||||
.header('cache-control', res.headers['cache-control']);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/static/{path*}',
|
||||
@ -31,12 +113,21 @@ exports.register = async server => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: '*',
|
||||
path: '/~server-error',
|
||||
handler: {
|
||||
view: {
|
||||
name: 'server-error'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: '*',
|
||||
path: '/{path*}',
|
||||
config: {
|
||||
handler: (request, h) => {
|
||||
return h.response(indexFile).type('text/html');
|
||||
handler: {
|
||||
view: {
|
||||
name: 'app'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,23 +8,28 @@
|
||||
"scripts": {
|
||||
"dev": "REACT_APP_GQL_PORT=4000 PORT=3070 REACT_APP_GQL_PROTOCOL=http joyent-react-scripts start",
|
||||
"start": "PORT=3069 joyent-react-scripts start",
|
||||
"build": "NODE_ENV=production joyent-react-scripts build",
|
||||
"build:app": "NODE_ENV=production joyent-react-scripts build",
|
||||
"build:lib": "NODE_ENV=production SSR=1 UMD=1 babel src --out-dir lib/app --copy-files",
|
||||
"lint-ci": "eslint . --ext .js --ext .md",
|
||||
"lint": "eslint . --fix --ext .js --ext .md",
|
||||
"test-ci": "NODE_ENV=test joyent-react-scripts test --env=jsdom --testPathIgnorePatterns='.ui.js'",
|
||||
"test": "DEFAULT_TIMEOUT_INTERVAL=100000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
||||
"prepublish": "echo 0"
|
||||
"postinstall": "npm run build:app",
|
||||
"prepublish": "npm run build:lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manaflair/redux-batch": "^0.1.0",
|
||||
"apollo": "^0.2.2",
|
||||
"apollo-cache-inmemory": "^1.1.7",
|
||||
"apollo-client": "^2.2.3",
|
||||
"apollo-link-http": "^1.3.3",
|
||||
"apollo-cache-inmemory": "^1.1.9",
|
||||
"apollo-client": "^2.2.5",
|
||||
"apollo-link-http": "^1.5.1",
|
||||
"apr-intercept": "^3.0.3",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"date-fns": "^1.29.0",
|
||||
"declarative-redux-form": "^2.0.8",
|
||||
"force-array": "^3.1.0",
|
||||
"hapi-render-react": "^2.1.0",
|
||||
"hapi-render-react-joyent-document": "^4.2.3",
|
||||
"joyent-logo-assets": "^1.0.0",
|
||||
"joyent-react-styled-flexboxgrid": "^2.2.3",
|
||||
"joyent-ui-toolkit": "^5.0.0",
|
||||
@ -41,7 +46,7 @@
|
||||
"react": "^16.2.0",
|
||||
"react-apollo": "^2.0.4",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-redux-values": "^1.1.2",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
@ -51,17 +56,17 @@
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"styled-components": "^3.1.6",
|
||||
"styled-components-spacing": "^2.1.3",
|
||||
"styled-flex-component": "^2.2.0",
|
||||
"styled-flex-component": "^2.2.1",
|
||||
"styled-is": "^1.1.2",
|
||||
"title-case": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"eslint": "^4.16.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1",
|
||||
"jest-image-snapshot": "^2.3.0",
|
||||
"jest-styled-components": "^4.11.0-0",
|
||||
"joyent-react-scripts": "^7.2.2",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
"react-screenshot-renderer": "^1.1.2",
|
||||
"react-test-renderer": "^16.2.0"
|
||||
}
|
||||
|
@ -6,16 +6,11 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="theme-color" content="#1E313B">
|
||||
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> -->
|
||||
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> -->
|
||||
<title>My Joyent Images β</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="header"></div>
|
||||
<div id="root"></div>
|
||||
<script src="/nav-static/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
12
packages/images/src/_aliases.js
Normal file
@ -0,0 +1,12 @@
|
||||
const path = require('path');
|
||||
|
||||
const { SSR } = process.env;
|
||||
|
||||
const aliases = {};
|
||||
|
||||
if (SSR) {
|
||||
aliases['scroll-to-element'] = './src/mocks/scroll-to-element';
|
||||
aliases['^joyent-ui-toolkit/dist/es/editor$'] = './src/mocks/editor';
|
||||
}
|
||||
|
||||
module.exports = aliases;
|
34
packages/images/src/_document.js
Normal file
@ -0,0 +1,34 @@
|
||||
const get = require('lodash.get');
|
||||
const Document = require('hapi-render-react-joyent-document');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
const { default: theme } = require('./state/theme');
|
||||
const { default: createClient } = require('./state/apollo-client');
|
||||
const { default: createStore } = require('./state/redux-store');
|
||||
|
||||
const indexFile = path.join(__dirname, '../../build/index.html');
|
||||
|
||||
const getState = request => {
|
||||
const { req, res } = request.raw;
|
||||
|
||||
const _font = get(theme, 'font.href', () => '');
|
||||
const _mono = get(theme, 'monoFont.href', () => '');
|
||||
const _addr = url.parse(`http://${req.headers.host}`);
|
||||
const _theme = Object.assign({}, theme, {
|
||||
font: Object.assign({}, theme.font, {
|
||||
href: () => _font(_addr)
|
||||
}),
|
||||
monoFont: Object.assign({}, theme.monoFont, {
|
||||
href: () => _mono(_addr)
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
theme: _theme,
|
||||
createClient,
|
||||
createStore
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Document({ indexFile, getState });
|
@ -1,21 +1,10 @@
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
|
||||
import { theme, RootContainer } from 'joyent-ui-toolkit';
|
||||
|
||||
import { client, store } from '@state/store';
|
||||
import Router from '@root/router';
|
||||
import { RootContainer } from 'joyent-ui-toolkit';
|
||||
import Routes from '@root/routes';
|
||||
|
||||
export default () => (
|
||||
<ApolloProvider client={client}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ReduxProvider store={store}>
|
||||
<RootContainer>
|
||||
<Router />
|
||||
</RootContainer>
|
||||
</ReduxProvider>
|
||||
</ThemeProvider>
|
||||
</ApolloProvider>
|
||||
<RootContainer>
|
||||
<Routes />
|
||||
</RootContainer>
|
||||
);
|
||||
|
@ -95,7 +95,7 @@ export const Image = ({
|
||||
height: '24'
|
||||
})}
|
||||
</Margin>
|
||||
<A to={`/${name}`} component={Link}>
|
||||
<A to={`/${name}/summary`} component={Link}>
|
||||
{name}
|
||||
</A>
|
||||
</Flex>
|
||||
|
@ -17,7 +17,7 @@ import Animated from '@containers/create-image/animated';
|
||||
import Details from '@components/create-image/details';
|
||||
import Description from '@components/description';
|
||||
import GetRandomName from '@graphql/get-random-name.gql';
|
||||
import { client } from '@state/store';
|
||||
import createStore from '@state/apollo-client';
|
||||
import { Forms } from '@root/constants';
|
||||
|
||||
const NameContainer = ({
|
||||
@ -111,7 +111,10 @@ const NameContainer = ({
|
||||
export default compose(
|
||||
Animated,
|
||||
graphql(GetRandomName, {
|
||||
fetchPolicy: 'network-only',
|
||||
options: () => ({
|
||||
fetchPolicy: 'network-only',
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => ({
|
||||
placeholderName: data.rndName || ''
|
||||
})
|
||||
@ -168,7 +171,7 @@ export default compose(
|
||||
dispatch(set({ name: 'create-image-name-randomizing', value: true }));
|
||||
|
||||
const [err, res] = await intercept(
|
||||
client.query({
|
||||
createStore().query({
|
||||
fetchPolicy: 'network-only',
|
||||
query: GetRandomName
|
||||
})
|
||||
|
@ -95,6 +95,7 @@ export default compose(
|
||||
graphql(CreateImage, { name: 'createImage' }),
|
||||
graphql(GetInstance, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
}
|
||||
|
@ -99,8 +99,10 @@ export default compose(
|
||||
name: 'removeImage'
|
||||
}),
|
||||
graphql(ListImages, {
|
||||
fetchPolicy: 'network-only',
|
||||
pollInterval: 1000,
|
||||
options: () => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000
|
||||
}),
|
||||
props: ({ data: { images, loading, error, refetch } }) => ({
|
||||
images,
|
||||
loading,
|
||||
|
@ -67,6 +67,7 @@ export default compose(
|
||||
graphql(RemoveImage, { name: 'removeImage' }),
|
||||
graphql(GetImage, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
variables: {
|
||||
name: get(match, 'params.image')
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ export default compose(
|
||||
}),
|
||||
graphql(GetTags, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
fetchPolicy: 'network-only',
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
|
@ -1,8 +1,16 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { ThemeProvider, consolidateStreamedStyles } from 'styled-components';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import isFunction from 'lodash.isfunction';
|
||||
import isFinite from 'lodash.isfinite';
|
||||
|
||||
import { theme } from 'joyent-ui-toolkit';
|
||||
|
||||
import createStore from '@state/redux-store';
|
||||
import createClient from '@state/apollo-client';
|
||||
import { register } from './sw';
|
||||
import App from './app';
|
||||
|
||||
@ -10,6 +18,19 @@ if (!isFunction(Number.isFinite)) {
|
||||
Number.isFinite = isFinite;
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
consolidateStreamedStyles();
|
||||
|
||||
ReactDOM.hydrate(
|
||||
<ApolloProvider client={createClient()}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ReduxProvider store={createStore()}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</ReduxProvider>
|
||||
</ThemeProvider>
|
||||
</ApolloProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
register();
|
||||
|
@ -1 +1,8 @@
|
||||
module.exports = {};
|
||||
module.exports = {
|
||||
'^joyent-ui-toolkit/dist/es/editor$': '<rootDir>/src/mocks/editor',
|
||||
'^redux-form$': '<rootDir>/src/mocks/redux-form',
|
||||
'^react-responsive$': '<rootDir>/src/mocks/react-responsive',
|
||||
'^react-router-dom$': '<rootDir>/src/mocks/react-router-dom',
|
||||
'^declarative-redux-form$': '<rootDir>/src/mocks/declarative-redux-form',
|
||||
'^scroll-to-element': '<rootDir>/src/mocks/scroll-to-element'
|
||||
};
|
||||
|
3
packages/images/src/mocks/declarative-redux-form.js
Normal file
@ -0,0 +1,3 @@
|
||||
import React from 'react';
|
||||
|
||||
export default ({ children, ...props }) => React.createElement(children, props);
|
3
packages/images/src/mocks/editor.js
Normal file
@ -0,0 +1,3 @@
|
||||
import React from 'react';
|
||||
|
||||
export default () => <span>joyent-maifest-editor</span>;
|
3
packages/images/src/mocks/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as Router } from './router';
|
||||
export { default as Store } from './store';
|
||||
export { default as Theme } from './theme';
|
7
packages/images/src/mocks/react-responsive.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
export default ({ query, children }) => (
|
||||
<span name="react-responsive-mock" query={query}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
4
packages/images/src/mocks/react-router-dom.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Field = ({ children, ...rest }) =>
|
||||
React.createElement('a', rest, children);
|
4
packages/images/src/mocks/redux-form.js
Normal file
@ -0,0 +1,4 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Field = ({ component = 'input', children, ...rest }) =>
|
||||
React.createElement(component, rest, children);
|
4
packages/images/src/mocks/router.js
Normal file
@ -0,0 +1,4 @@
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
export default ({ children }) => <MemoryRouter>{children}</MemoryRouter>;
|
1
packages/images/src/mocks/scroll-to-element.js
Normal file
@ -0,0 +1 @@
|
||||
export default () => null;
|
8
packages/images/src/mocks/store.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
|
||||
import createClient from '@state/apollo-client';
|
||||
|
||||
export default ({ children }) => (
|
||||
<ApolloProvider client={createClient()}>{children}</ApolloProvider>
|
||||
);
|
22
packages/images/src/mocks/theme.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import {
|
||||
theme,
|
||||
RootContainer,
|
||||
PageContainer,
|
||||
ViewContainer
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
export default ({ children, ss }) => (
|
||||
<ThemeProvider theme={theme}>
|
||||
{ss ? (
|
||||
<RootContainer>
|
||||
<PageContainer>
|
||||
<ViewContainer>{children}</ViewContainer>
|
||||
</PageContainer>
|
||||
</RootContainer>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</ThemeProvider>
|
||||
);
|
@ -1,54 +0,0 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { PageContainer } from 'joyent-ui-toolkit';
|
||||
import Breadcrumb from '@containers/breadcrumb';
|
||||
import Menu from '@containers/menu';
|
||||
import List from '@containers/list';
|
||||
import Summary from '@containers/summary';
|
||||
import Create from '@containers/create';
|
||||
import Tags from '@containers/tags';
|
||||
import Footer from '@components/footer';
|
||||
|
||||
export default () => (
|
||||
<BrowserRouter>
|
||||
<PageContainer>
|
||||
{/* Breadcrumb */}
|
||||
<Switch>
|
||||
<Route path="/~create/:instance/:step?" exact component={Breadcrumb} />
|
||||
<Route path="/:image?" component={Breadcrumb} />
|
||||
</Switch>
|
||||
{/* Menu */}
|
||||
<Switch>
|
||||
<Route path="/:image/:section?" component={Menu} />
|
||||
<Route path="/~create/:instance/:step?" component={() => {}} />
|
||||
</Switch>
|
||||
{/* Images */}
|
||||
<Switch>
|
||||
<Route path="/" exact component={List} />
|
||||
<Route path="/:image/summary" exact component={Summary} />
|
||||
<Route path="/:image/tags" exact component={Tags} />
|
||||
<Route
|
||||
path="/:image"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/${get(match, 'params.image')}/summary`} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
{/* Create Image */}
|
||||
<Switch>
|
||||
<Route
|
||||
path="/~create/:instance?"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/~create/${match.params.instance}/name`} />
|
||||
)}
|
||||
/>
|
||||
<Route path="/~create/:instance/:step" component={Create} />
|
||||
</Switch>
|
||||
<Footer />
|
||||
</PageContainer>
|
||||
</BrowserRouter>
|
||||
);
|
80
packages/images/src/routes.js
Normal file
@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import {
|
||||
PageContainer,
|
||||
RootContainer,
|
||||
ViewContainer,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Breadcrumb from '@containers/breadcrumb';
|
||||
import Menu from '@containers/menu';
|
||||
import List from '@containers/list';
|
||||
import Summary from '@containers/summary';
|
||||
import Create from '@containers/create';
|
||||
import Tags from '@containers/tags';
|
||||
import Footer from '@components/footer';
|
||||
import { Route as ServerError } from '@root/server-error';
|
||||
|
||||
export default () => (
|
||||
<PageContainer>
|
||||
{/* Breadcrumb */}
|
||||
<Switch>
|
||||
<Route path="/~server-error" component={Breadcrumb} />
|
||||
<Route path="/~create/:instance/:step?" exact component={Breadcrumb} />
|
||||
<Route path="/:image?" component={Breadcrumb} />
|
||||
</Switch>
|
||||
|
||||
{/* Menu */}
|
||||
<Switch>
|
||||
<Route path="/~server-error" component={() => null} />
|
||||
<Route path="/:image/:section?" component={Menu} />
|
||||
<Route path="/~create/:instance/:step?" component={() => {}} />
|
||||
</Switch>
|
||||
|
||||
{/* Images */}
|
||||
<Switch>
|
||||
<Route path="/~server-error" component={() => null} />
|
||||
<Route path="/" exact component={List} />
|
||||
<Route path="/:image/summary" exact component={Summary} />
|
||||
<Route path="/:image/tags" exact component={Tags} />
|
||||
<Route
|
||||
path="/:image"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/${get(match, 'params.image')}/summary`} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
|
||||
{/* Create Image */}
|
||||
<Switch>
|
||||
<Route
|
||||
path="/~create/:instance?"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/~create/${match.params.instance}/name`} />
|
||||
)}
|
||||
/>
|
||||
<Route path="/~create/:instance/:step" component={Create} />
|
||||
</Switch>
|
||||
|
||||
<Route path="/~server-error" component={ServerError} />
|
||||
|
||||
<noscript>
|
||||
<ViewContainer main>
|
||||
<Message warning>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
You need to enable JavaScript to run this app.
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
</ViewContainer>
|
||||
</noscript>
|
||||
<Footer />
|
||||
</PageContainer>
|
||||
);
|
38
packages/images/src/server-error.js
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import {
|
||||
RootContainer,
|
||||
PageContainer,
|
||||
ViewContainer,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle,
|
||||
Divider
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Breadcrumb from '@containers/breadcrumb';
|
||||
|
||||
export const Route = () => (
|
||||
<ViewContainer main>
|
||||
<Divider height={remcalc(30)} transparent />
|
||||
<Margin bottom={4}>
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
An error occurred while loading your page
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
</Margin>
|
||||
</ViewContainer>
|
||||
);
|
||||
|
||||
export default () => (
|
||||
<RootContainer>
|
||||
<PageContainer>
|
||||
<Breadcrumb />
|
||||
<Route />
|
||||
</PageContainer>
|
||||
</RootContainer>
|
||||
);
|
33
packages/images/src/state/apollo-client.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import fetch from 'cross-fetch';
|
||||
|
||||
import global from './global';
|
||||
|
||||
const {
|
||||
REACT_APP_GQL_PORT = global.port,
|
||||
REACT_APP_GQL_PROTOCOL = global.protocol,
|
||||
REACT_APP_GQL_HOSTNAME = global.hostname
|
||||
} = process.env;
|
||||
|
||||
const PORT = REACT_APP_GQL_PORT ? `:${REACT_APP_GQL_PORT}` : '';
|
||||
const URI = `${REACT_APP_GQL_PROTOCOL}://${REACT_APP_GQL_HOSTNAME}${PORT}/graphql`;
|
||||
|
||||
export default (opts = {}) => {
|
||||
let cache = new InMemoryCache();
|
||||
|
||||
if (global.__APOLLO_STATE__) {
|
||||
cache = cache.restore(global.__APOLLO_STATE__);
|
||||
}
|
||||
|
||||
return new ApolloClient({
|
||||
cache,
|
||||
link: new HttpLink({
|
||||
uri: URI,
|
||||
credentials: 'same-origin',
|
||||
fetch
|
||||
}),
|
||||
...opts
|
||||
});
|
||||
};
|
16
packages/images/src/state/global.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { canUseDOM } from 'exenv';
|
||||
|
||||
export default (() => {
|
||||
if (!canUseDOM) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
port: window.location.port,
|
||||
protocol: window.location.protocol.replace(/:$/, ''),
|
||||
hostname: window.location.hostname,
|
||||
__REDUX_DEVTOOLS_EXTENSION__: window.__REDUX_DEVTOOLS_EXTENSION__,
|
||||
__APOLLO_STATE__: window.__APOLLO_STATE__,
|
||||
__REDUX_STATE__: window.__REDUX_STATE__
|
||||
};
|
||||
})();
|
27
packages/images/src/state/redux-store.js
Normal file
@ -0,0 +1,27 @@
|
||||
import { reduxBatch } from '@manaflair/redux-batch';
|
||||
import { createStore, combineReducers, compose } from 'redux';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { reducer as valuesReducer } from 'react-redux-values';
|
||||
import paramCase from 'param-case';
|
||||
import global from './global';
|
||||
|
||||
const initialState = {};
|
||||
|
||||
export default () => {
|
||||
return createStore(
|
||||
combineReducers({
|
||||
values: valuesReducer,
|
||||
form: formReducer,
|
||||
ui: (state = {}) => state
|
||||
}),
|
||||
global.__REDUX_STATE__ || initialState,
|
||||
compose(
|
||||
reduxBatch,
|
||||
// If you are using the devToolsExtension, you can add it here also
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
typeof global.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined'
|
||||
? global.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
: f => f
|
||||
)
|
||||
);
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
import { reduxBatch } from '@manaflair/redux-batch';
|
||||
import { createStore, combineReducers, compose } from 'redux';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import { reducer as valuesReducer } from 'react-redux-values';
|
||||
|
||||
const {
|
||||
REACT_APP_GQL_PORT = 443,
|
||||
REACT_APP_GQL_PROTOCOL = 'https',
|
||||
REACT_APP_GQL_HOSTNAME = window.location.hostname
|
||||
} = process.env;
|
||||
|
||||
export const client = new ApolloClient({
|
||||
cache: new InMemoryCache(),
|
||||
link: new HttpLink({
|
||||
uri: `${REACT_APP_GQL_PROTOCOL}://${REACT_APP_GQL_HOSTNAME}:${REACT_APP_GQL_PORT}/graphql`
|
||||
})
|
||||
});
|
||||
|
||||
const initialState = {};
|
||||
|
||||
export const store = createStore(
|
||||
combineReducers({
|
||||
values: valuesReducer,
|
||||
form: formReducer,
|
||||
ui: (state = {}) => state
|
||||
}),
|
||||
initialState,
|
||||
compose(
|
||||
reduxBatch,
|
||||
// If you are using the devToolsExtension, you can add it here also
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined'
|
||||
? window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
: f => f
|
||||
)
|
||||
);
|
@ -19,17 +19,17 @@
|
||||
"apr-for-each": "^3.0.3",
|
||||
"apr-main": "^4.0.3",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"eslint": "^4.16.0",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1",
|
||||
"execa": "^0.9.0",
|
||||
"globby": "^7.1.1",
|
||||
"globby": "^8.0.1",
|
||||
"htmltojsx": "^0.3.0",
|
||||
"joyent-react-scripts": "^7.2.2",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
"mz": "^2.7.0",
|
||||
"prettier": "^1.10.2",
|
||||
"react": "^16.2.0",
|
||||
"redrun": "^5.10.0"
|
||||
"redrun": "^5.10.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.2.0"
|
||||
|
@ -1,3 +1,7 @@
|
||||
{
|
||||
"presets": "joyent-portal"
|
||||
"ignore": ["_document.js", "_aliases.js"],
|
||||
"presets": [["joyent-portal", {
|
||||
"aliases": true,
|
||||
"autoAliases": true
|
||||
}]]
|
||||
}
|
||||
|
@ -2,3 +2,4 @@
|
||||
coverage
|
||||
dist
|
||||
build
|
||||
lib/app
|
2
packages/my-joy-beta/.gitignore
vendored
@ -21,3 +21,5 @@ yarn-error.log*
|
||||
|
||||
**/__diff_output__
|
||||
|
||||
lib/app
|
||||
|
||||
|
@ -1,16 +1,104 @@
|
||||
const Inert = require('inert');
|
||||
const Path = require('path');
|
||||
const { readFile } = require('mz/fs');
|
||||
const RenderReact = require('hapi-render-react');
|
||||
const Wreck = require('wreck');
|
||||
const Url = require('url');
|
||||
|
||||
exports.register = async server => {
|
||||
const indexFile = await readFile(
|
||||
Path.join(__dirname, '../build/index.html'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
await server.register(Inert);
|
||||
await server.register([
|
||||
{
|
||||
plugin: Inert
|
||||
},
|
||||
{
|
||||
plugin: RenderReact,
|
||||
options: {
|
||||
relativeTo: Path.join(__dirname, 'app')
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
server.route([
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/service-worker.js',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: {
|
||||
file: {
|
||||
path: Path.join(__dirname, '../build/service-worker.js')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/favicon.ico',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: {
|
||||
file: {
|
||||
path: Path.join(__dirname, '../build/favicon.ico')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/font/{pathname*}',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: async (request, h) => {
|
||||
const { params } = request;
|
||||
const { pathname } = params;
|
||||
|
||||
const location = Url.format({
|
||||
protocol: 'https:',
|
||||
slashes: true,
|
||||
host: 'fonts.gstatic.com',
|
||||
pathname
|
||||
});
|
||||
|
||||
const res = await Wreck.request('GET', location);
|
||||
return h.response(res);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/fonts/css',
|
||||
config: {
|
||||
auth: false,
|
||||
handler: async (request, h) => {
|
||||
const { query, headers } = request;
|
||||
const { family } = query;
|
||||
const { host } = headers;
|
||||
const url = Url.parse(`http://${host}`);
|
||||
|
||||
const location = Url.format({
|
||||
protocol: 'https:',
|
||||
slashes: true,
|
||||
host: 'fonts.googleapis.com',
|
||||
pathname: '/css',
|
||||
query: { family }
|
||||
});
|
||||
|
||||
const res = await Wreck.request('GET', location);
|
||||
const body = await Wreck.read(res);
|
||||
|
||||
const _body = body.toString().replace(
|
||||
/https:\/\/fonts\.gstatic\.com/g,
|
||||
`http://${url.host}/font`
|
||||
);
|
||||
|
||||
return h
|
||||
.response(_body)
|
||||
.header('content-type', res.headers['content-type'])
|
||||
.header('expires', res.headers.expires)
|
||||
.header('date', res.headers.date)
|
||||
.header('cache-control', res.headers['cache-control']);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/static/{path*}',
|
||||
@ -25,12 +113,21 @@ exports.register = async server => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: '*',
|
||||
path: '/~server-error',
|
||||
handler: {
|
||||
view: {
|
||||
name: 'server-error'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
method: '*',
|
||||
path: '/{path*}',
|
||||
config: {
|
||||
handler: (request, h) => {
|
||||
return h.response(indexFile).type('text/html');
|
||||
handler: {
|
||||
view: {
|
||||
name: 'app'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,29 +8,34 @@
|
||||
"scripts": {
|
||||
"dev": "REACT_APP_GQL_PORT=4000 PORT=3069 REACT_APP_GQL_PROTOCOL=http joyent-react-scripts start",
|
||||
"start": "PORT=3069 joyent-react-scripts start",
|
||||
"build": "NODE_ENV=production joyent-react-scripts build",
|
||||
"build:app": "NODE_ENV=production joyent-react-scripts build",
|
||||
"build:lib": "NODE_ENV=production SSR=1 UMD=1 babel src --out-dir lib/app --copy-files",
|
||||
"lint-ci": "eslint . --ext .js --ext .md",
|
||||
"lint": "eslint . --fix --ext .js --ext .md",
|
||||
"test-ci": "NODE_ENV=test joyent-react-scripts test --env=jsdom --testPathIgnorePatterns='.ui.js'",
|
||||
"test": "DEFAULT_TIMEOUT_INTERVAL=100000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
||||
"postinstall": "npm run build",
|
||||
"prepublish": "echo 0"
|
||||
"postinstall": "npm run build:app",
|
||||
"prepublish": "npm run build:lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manaflair/redux-batch": "^0.1.0",
|
||||
"apollo": "0.2.2",
|
||||
"apollo": "^0.2.2",
|
||||
"apr-intercept": "^3.0.3",
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"bytes": "^3.0.0",
|
||||
"clipboard-copy": "^1.2.1",
|
||||
"clipboard-copy": "^1.4.2",
|
||||
"constant-case": "^2.0.0",
|
||||
"cross-fetch": "^1.1.1",
|
||||
"date-fns": "^1.29.0",
|
||||
"declarative-redux-form": "^2.0.8",
|
||||
"execa": "^0.9.0",
|
||||
"exenv": "^1.2.2",
|
||||
"fuse.js": "^3.2.0",
|
||||
"hapi-render-react": "^2.1.0",
|
||||
"hapi-render-react-joyent-document": "^4.2.3",
|
||||
"inert": "^5.1.0",
|
||||
"joyent-logo-assets": "^1.0.0",
|
||||
"joyent-manifest-editor": "^1.4.0",
|
||||
"joyent-manifest-editor": "^3.0.1",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
"joyent-react-styled-flexboxgrid": "^2.2.3",
|
||||
"joyent-ui-toolkit": "^5.0.0",
|
||||
@ -41,7 +46,7 @@
|
||||
"lodash.isarray": "^4.0.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isfinite": "^3.3.2",
|
||||
"lodash.isfunction": "^3.0.8",
|
||||
"lodash.isfunction": "^3.0.9",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.omit": "^4.5.0",
|
||||
"lodash.reverse": "^4.0.1",
|
||||
@ -56,22 +61,23 @@
|
||||
"react": "^16.2.0",
|
||||
"react-apollo": "^2.0.4",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-redux-values": "^1.1.2",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"redux": "^3.7.2",
|
||||
"redux-actions": "^2.2.1",
|
||||
"redux-form": "^7.2.1",
|
||||
"redux-form": "^7.2.3",
|
||||
"remcalc": "^1.0.10",
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"styled-components": "^3.1.4",
|
||||
"styled-components": "^3.1.6",
|
||||
"styled-components-spacing": "^2.1.3",
|
||||
"styled-flex-component": "^2.2.0",
|
||||
"styled-flex-component": "^2.2.1",
|
||||
"title-case": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^4.16.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1",
|
||||
"jest-image-snapshot": "^2.3.0",
|
||||
"jest-styled-components": "^4.11.0-0",
|
||||
|
@ -6,16 +6,12 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="theme-color" content="#1E313B">
|
||||
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> -->
|
||||
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> -->
|
||||
<title>My Joyent β</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="header"></div>
|
||||
<div id="root"></div>
|
||||
<script src="/nav-static/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
12
packages/my-joy-beta/src/_aliases.js
Normal file
@ -0,0 +1,12 @@
|
||||
const path = require('path');
|
||||
|
||||
const { SSR } = process.env;
|
||||
|
||||
const aliases = {};
|
||||
|
||||
if (SSR) {
|
||||
aliases['scroll-to-element'] = './src/mocks/scroll-to-element';
|
||||
aliases['^joyent-ui-toolkit/dist/es/editor$'] = './src/mocks/editor';
|
||||
}
|
||||
|
||||
module.exports = aliases;
|
34
packages/my-joy-beta/src/_document.js
Normal file
@ -0,0 +1,34 @@
|
||||
const get = require('lodash.get');
|
||||
const Document = require('hapi-render-react-joyent-document');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
const { default: theme } = require('./state/theme');
|
||||
const { default: createClient } = require('./state/apollo-client');
|
||||
const { default: createStore } = require('./state/redux-store');
|
||||
|
||||
const indexFile = path.join(__dirname, '../../build/index.html');
|
||||
|
||||
const getState = request => {
|
||||
const { req, res } = request.raw;
|
||||
|
||||
const _font = get(theme, 'font.href', () => '');
|
||||
const _mono = get(theme, 'monoFont.href', () => '');
|
||||
const _addr = url.parse(`http://${req.headers.host}`);
|
||||
const _theme = Object.assign({}, theme, {
|
||||
font: Object.assign({}, theme.font, {
|
||||
href: () => _font(_addr)
|
||||
}),
|
||||
monoFont: Object.assign({}, theme.monoFont, {
|
||||
href: () => _mono(_addr)
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
theme: _theme,
|
||||
createClient,
|
||||
createStore
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Document({ indexFile, getState });
|
@ -1,35 +1,10 @@
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
|
||||
import { theme, RootContainer } from 'joyent-ui-toolkit';
|
||||
|
||||
import { client, store } from '@state/store';
|
||||
import Router from '@root/router';
|
||||
|
||||
const { NODE_ENV } = process.env;
|
||||
const IS_PRODUCTION = NODE_ENV === 'production';
|
||||
|
||||
const fullTheme = {
|
||||
...theme,
|
||||
font: {
|
||||
...theme.font,
|
||||
href: !IS_PRODUCTION
|
||||
? theme.font.href
|
||||
: () =>
|
||||
'https://fonts.googleapis.com/css?family=Libre+Franklin:400,500,600,700'
|
||||
}
|
||||
};
|
||||
import { RootContainer } from 'joyent-ui-toolkit';
|
||||
import Routes from '@root/routes';
|
||||
|
||||
export default () => (
|
||||
<ApolloProvider client={client}>
|
||||
<ThemeProvider theme={fullTheme}>
|
||||
<ReduxProvider store={store}>
|
||||
<RootContainer>
|
||||
<Router />
|
||||
</RootContainer>
|
||||
</ReduxProvider>
|
||||
</ThemeProvider>
|
||||
</ApolloProvider>
|
||||
<RootContainer>
|
||||
<Routes />
|
||||
</RootContainer>
|
||||
);
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
@ -107,6 +107,9 @@ const CNSContainer = ({
|
||||
|
||||
export default compose(
|
||||
graphql(GetAccount, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data: { account: { id = '<account-id>' } = [] } }) => ({
|
||||
id
|
||||
})
|
||||
|
@ -172,6 +172,7 @@ export default compose(
|
||||
),
|
||||
graphql(ListFwRules, {
|
||||
options: ({ tags, expanded, enabled }) => ({
|
||||
ssr: false,
|
||||
fetchPolicy: expanded && enabled ? 'cache-first' : 'cache-only',
|
||||
variables: {
|
||||
tags: tags.map(({ name, value }) => ({ name, value }))
|
||||
@ -201,86 +202,3 @@ export default compose(
|
||||
}
|
||||
})
|
||||
)(Firewall);
|
||||
|
||||
// <ReduxForm
|
||||
// form="fw-enabled"
|
||||
// destroyOnUnmount={false}
|
||||
// forceUnregisterOnUnmount={true}
|
||||
// initialValues={{ enabled }}
|
||||
// onSubmit={handleEnabledToggle}
|
||||
// >
|
||||
// {props =>
|
||||
// loading ? null : (
|
||||
// <Fragment>
|
||||
// <Margin bottom={7}>
|
||||
// <ToggleFirewallForm {...props} />
|
||||
// </Margin>
|
||||
// <Divider height={remcalc(1)} />
|
||||
// </Fragment>
|
||||
// )
|
||||
// }
|
||||
// </ReduxForm>
|
||||
// <ReduxForm
|
||||
// form="fw-inactive"
|
||||
// destroyOnUnmount={false}
|
||||
// forceUnregisterOnUnmount={true}
|
||||
// initialValues={{ inactive }}
|
||||
// >
|
||||
// {props =>
|
||||
// !enabled || loading ? null : (
|
||||
// <Margin top={4}>
|
||||
// <ToggleInactiveForm {...props} />
|
||||
// </Margin>
|
||||
// )
|
||||
// }
|
||||
// </ReduxForm>
|
||||
// {!loading && !defaultRules.length && !tagRules.length ? (
|
||||
// <Margin top={5}>
|
||||
// <Empty>Sorry, but we weren’t able to find any firewall rules.</Empty>
|
||||
// </Margin>
|
||||
// ) : null}
|
||||
// {!loading && enabled && defaultRules.length ? (
|
||||
// <Margin top={5}>
|
||||
// <DefaultRules rules={defaultRules} />
|
||||
// </Margin>
|
||||
// ) : null}
|
||||
// {!loading && enabled && tagRules.length ? (
|
||||
// <Margin top={8}>
|
||||
// <TagRules rules={tagRules} />
|
||||
// </Margin>
|
||||
// ) : null}
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// <ReduxForm
|
||||
// form={FORM_NAME}
|
||||
// destroyOnUnmount={false}
|
||||
// forceUnregisterOnUnmount={true}
|
||||
// >
|
||||
// {props =>
|
||||
// expanded && !loading ? (
|
||||
// <FirewallForm
|
||||
// {...props}
|
||||
// defaultRules={defaultRules}
|
||||
// tagRules={tagRules}
|
||||
// enabled={enabled}
|
||||
// />
|
||||
// ) : null
|
||||
// }
|
||||
// </ReduxForm>
|
||||
// {expanded ? (
|
||||
// <Margin bottom={4}>
|
||||
// <Button type="button" onClick={handleNext}>
|
||||
// Next
|
||||
// </Button>
|
||||
// </Margin>
|
||||
// ) : proceeded ? (
|
||||
// <Margin bottom={4}>
|
||||
// <Button type="button" onClick={handleEdit} secondary>
|
||||
// Edit
|
||||
// </Button>
|
||||
// </Margin>
|
||||
// ) : null}
|
||||
|
@ -149,6 +149,9 @@ export default compose(
|
||||
})
|
||||
),
|
||||
graphql(GetImages, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ ownProps, data }) => {
|
||||
const { image = '', query } = ownProps;
|
||||
const { loading = false, images = [] } = data;
|
||||
|
@ -16,7 +16,7 @@ import Name from '@components/create-instance/name';
|
||||
import Description from '@components/description';
|
||||
import GetInstance from '@graphql/get-instance-small.gql';
|
||||
import GetRandomName from '@graphql/get-random-name.gql';
|
||||
import { client } from '@state/store';
|
||||
import createClient from '@state/apollo-client';
|
||||
import parseError from '@state/parse-error';
|
||||
import { fieldError } from '@root/constants';
|
||||
|
||||
@ -90,7 +90,9 @@ const NameContainer = ({
|
||||
|
||||
export default compose(
|
||||
graphql(GetRandomName, {
|
||||
fetchPolicy: 'network-only',
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => ({
|
||||
placeholderName: data.rndName || ''
|
||||
})
|
||||
@ -133,7 +135,7 @@ export default compose(
|
||||
}
|
||||
|
||||
const [err, res] = await intercept(
|
||||
client.query({
|
||||
createClient().query({
|
||||
fetchPolicy: 'network-only',
|
||||
query: GetInstance,
|
||||
variables: { name }
|
||||
@ -172,7 +174,7 @@ export default compose(
|
||||
);
|
||||
|
||||
const [err, res] = await intercept(
|
||||
client.query({
|
||||
createClient().query({
|
||||
fetchPolicy: 'network-only',
|
||||
query: GetRandomName
|
||||
})
|
||||
|
@ -112,6 +112,9 @@ export const Networks = ({
|
||||
|
||||
export default compose(
|
||||
graphql(ListNetworks, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { networks = [], loading = false, error = null, refetch } = data;
|
||||
|
||||
|
@ -136,6 +136,9 @@ const PackageContainer = ({
|
||||
|
||||
export default compose(
|
||||
graphql(getPackages, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data: { loading, packages = [] } }) => ({
|
||||
loading,
|
||||
packages: packages.map(pkg => {
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -129,6 +129,9 @@ export default compose(
|
||||
graphql(UpdateTags, { name: 'updateTags' }),
|
||||
graphql(DeleteTag, { name: 'deleteTag' }),
|
||||
graphql(GetAccount, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { account = {} } = data;
|
||||
const { id = '<account-id>' } = account;
|
||||
@ -137,6 +140,9 @@ export default compose(
|
||||
}
|
||||
}),
|
||||
graphql(GetTags, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
options: ({ match }) => ({
|
||||
variables: {
|
||||
fetchPolicy: 'network-only',
|
||||
|
@ -133,6 +133,7 @@ export default compose(
|
||||
graphql(DisableFirewall, { name: 'disableFirewall' }),
|
||||
graphql(GetFirewallRules, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
variables: {
|
||||
fetchPolicy: 'network-only',
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -181,6 +181,7 @@ export default compose(
|
||||
graphql(RemoveInstance, { name: 'remove' }),
|
||||
graphql(ListInstances, {
|
||||
options: () => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000
|
||||
}),
|
||||
props: ({ data: { machines, loading, error, refetch } }) => {
|
||||
|
@ -156,6 +156,7 @@ export default compose(
|
||||
graphql(DeleteMetadata, { name: 'deleteMetadata' }),
|
||||
graphql(GetMetadata, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -170,6 +170,7 @@ export default compose(
|
||||
graphql(CreateSnapshotMutation, { name: 'createSnapshot' }),
|
||||
graphql(GetSnapshots, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -84,6 +84,7 @@ export default compose(
|
||||
graphql(RemoveInstance, { name: 'remove' }),
|
||||
graphql(GetInstance, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -149,6 +149,7 @@ export default compose(
|
||||
graphql(DeleteTag, { name: 'deleteTag' }),
|
||||
graphql(GetTags, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -47,6 +47,7 @@ export const UserScript = ({ metadata, loading = false, error = null }) => (
|
||||
export default compose(
|
||||
graphql(GetMetadata, {
|
||||
options: ({ match }) => ({
|
||||
ssr: false,
|
||||
variables: {
|
||||
fetchPolicy: 'network-only',
|
||||
name: get(match, 'params.instance')
|
||||
|
@ -1,8 +1,16 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { ThemeProvider, consolidateStreamedStyles } from 'styled-components';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import isFunction from 'lodash.isfunction';
|
||||
import isFinite from 'lodash.isfinite';
|
||||
|
||||
import { theme } from 'joyent-ui-toolkit';
|
||||
|
||||
import createStore from '@state/redux-store';
|
||||
import createClient from '@state/apollo-client';
|
||||
import { register } from './sw';
|
||||
import App from './app';
|
||||
|
||||
@ -10,6 +18,19 @@ if (!isFunction(Number.isFinite)) {
|
||||
Number.isFinite = isFinite;
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
consolidateStreamedStyles();
|
||||
|
||||
ReactDOM.hydrate(
|
||||
<ApolloProvider client={createClient()}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ReduxProvider store={createStore()}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</ReduxProvider>
|
||||
</ThemeProvider>
|
||||
</ApolloProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
register();
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React from 'react';
|
||||
import { client, store } from '@root/state/store';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
|
||||
import createClient from '@state/apollo-client';
|
||||
|
||||
export default ({ children }) => (
|
||||
<ApolloProvider client={client} store={store}>
|
||||
{children}
|
||||
</ApolloProvider>
|
||||
<ApolloProvider client={createClient()}>{children}</ApolloProvider>
|
||||
);
|
||||
|
@ -1,87 +0,0 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { PageContainer } from 'joyent-ui-toolkit';
|
||||
|
||||
import { Breadcrumb, Menu } from '@containers/navigation';
|
||||
import Footer from '@components/navigation/footer';
|
||||
import CreateInstance from '@containers/create-instance';
|
||||
|
||||
import {
|
||||
List as Instances,
|
||||
Summary as InstanceSummary,
|
||||
Tags as InstanceTags,
|
||||
Metadata as InstanceMetadata,
|
||||
Networks as InstanceNetworks,
|
||||
Firewall as InstanceFirewall,
|
||||
Cns as InstanceCns,
|
||||
Snapshots as InstanceSnapshots,
|
||||
UserScript as InstanceUserScript
|
||||
} from '@containers/instances';
|
||||
|
||||
export default () => (
|
||||
<BrowserRouter>
|
||||
<PageContainer>
|
||||
{/* Breadcrumb */}
|
||||
<Switch>
|
||||
<Route path="/~create/:section?" exact component={Breadcrumb} />
|
||||
<Route path="/~:action/:instance?" exact component={Breadcrumb} />
|
||||
<Route path="/:instance?" component={Breadcrumb} />
|
||||
</Switch>
|
||||
|
||||
{/* Menu */}
|
||||
<Switch>
|
||||
<Route path="/~:action/:id?" exact component={Menu} />
|
||||
<Route path="/:instance?/:section?" component={Menu} />
|
||||
</Switch>
|
||||
|
||||
{/* Instances List */}
|
||||
<Switch>
|
||||
<Route path="/" exact component={Instances} />
|
||||
</Switch>
|
||||
|
||||
{/* Instance Sections */}
|
||||
<Switch>
|
||||
<Route path="/~:action" component={() => null} />
|
||||
<Route path="/:instance/summary" exact component={InstanceSummary} />
|
||||
<Route path="/:instance/tags" exact component={InstanceTags} />
|
||||
<Route path="/:instance/metadata" exact component={InstanceMetadata} />
|
||||
<Route path="/:instance/networks" exact component={InstanceNetworks} />
|
||||
<Route path="/:instance/firewall" exact component={InstanceFirewall} />
|
||||
<Route
|
||||
path="/:instance/snapshots"
|
||||
exact
|
||||
component={InstanceSnapshots}
|
||||
/>
|
||||
<Route path="/:instance/cns" exact component={InstanceCns} />
|
||||
<Route
|
||||
path="/:instance/user-script"
|
||||
exact
|
||||
component={InstanceUserScript}
|
||||
/>
|
||||
<Route
|
||||
path="/:instance"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/${get(match, 'params.instance')}/summary`} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
|
||||
{/* Actions */}
|
||||
<Switch>
|
||||
{/* Create Instance */}
|
||||
<Route
|
||||
path="/~create/"
|
||||
exact
|
||||
component={({ match, location }) => (
|
||||
<Redirect to={`/~create/name${location.search}`} />
|
||||
)}
|
||||
/>
|
||||
<Route path="/~create/:step" component={CreateInstance} />
|
||||
</Switch>
|
||||
<Footer />
|
||||
</PageContainer>
|
||||
</BrowserRouter>
|
||||
);
|
103
packages/my-joy-beta/src/routes.js
Normal file
@ -0,0 +1,103 @@
|
||||
import React from 'react';
|
||||
import { Redirect, Route, Switch } from 'react-router-dom';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import {
|
||||
PageContainer,
|
||||
RootContainer,
|
||||
ViewContainer,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import { Breadcrumb, Menu } from '@containers/navigation';
|
||||
import Footer from '@components/navigation/footer';
|
||||
import CreateInstance from '@containers/create-instance';
|
||||
import { Route as ServerError } from '@root/server-error';
|
||||
|
||||
import {
|
||||
List as Instances,
|
||||
Summary as InstanceSummary,
|
||||
Tags as InstanceTags,
|
||||
Metadata as InstanceMetadata,
|
||||
Networks as InstanceNetworks,
|
||||
Firewall as InstanceFirewall,
|
||||
Cns as InstanceCns,
|
||||
Snapshots as InstanceSnapshots,
|
||||
UserScript as InstanceUserScript
|
||||
} from '@containers/instances';
|
||||
|
||||
export default () => (
|
||||
<PageContainer>
|
||||
{/* Breadcrumb */}
|
||||
<Switch>
|
||||
<Route path="/~create/:section?" exact component={Breadcrumb} />
|
||||
<Route path="/~:action/:instance?" exact component={Breadcrumb} />
|
||||
<Route path="/:instance?" component={Breadcrumb} />
|
||||
</Switch>
|
||||
|
||||
{/* Menu */}
|
||||
<Switch>
|
||||
<Route path="/~server-error" component={() => null} />
|
||||
<Route path="/~:action/:id?" exact component={Menu} />
|
||||
<Route path="/:instance?/:section?" component={Menu} />
|
||||
</Switch>
|
||||
|
||||
{/* Instances List */}
|
||||
<Switch>
|
||||
<Route path="/" exact component={Instances} />
|
||||
</Switch>
|
||||
|
||||
{/* Instance Sections */}
|
||||
<Switch>
|
||||
<Route path="/~:action" component={() => null} />
|
||||
<Route path="/:instance/summary" exact component={InstanceSummary} />
|
||||
<Route path="/:instance/tags" exact component={InstanceTags} />
|
||||
<Route path="/:instance/metadata" exact component={InstanceMetadata} />
|
||||
<Route path="/:instance/networks" exact component={InstanceNetworks} />
|
||||
<Route path="/:instance/firewall" exact component={InstanceFirewall} />
|
||||
<Route path="/:instance/snapshots" exact component={InstanceSnapshots} />
|
||||
<Route path="/:instance/cns" exact component={InstanceCns} />
|
||||
<Route
|
||||
path="/:instance/user-script"
|
||||
exact
|
||||
component={InstanceUserScript}
|
||||
/>
|
||||
<Route
|
||||
path="/:instance"
|
||||
exact
|
||||
component={({ match }) => (
|
||||
<Redirect to={`/${get(match, 'params.instance')}/summary`} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
|
||||
{/* Actions */}
|
||||
<Switch>
|
||||
{/* Create Instance */}
|
||||
<Route
|
||||
path="/~create/"
|
||||
exact
|
||||
component={({ match, location }) => (
|
||||
<Redirect to={`/~create/name${location.search}`} />
|
||||
)}
|
||||
/>
|
||||
<Route path="/~create/:step" component={CreateInstance} />
|
||||
</Switch>
|
||||
|
||||
<Route path="/~server-error" exact component={ServerError} />
|
||||
|
||||
<noscript>
|
||||
<ViewContainer main>
|
||||
<Message warning>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
You need to enable JavaScript to run this app.
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
</ViewContainer>
|
||||
</noscript>
|
||||
<Footer />
|
||||
</PageContainer>
|
||||
);
|
38
packages/my-joy-beta/src/server-error.js
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import {
|
||||
RootContainer,
|
||||
PageContainer,
|
||||
ViewContainer,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle,
|
||||
Divider
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Breadcrumb from '@containers/navigation/breadcrumb';
|
||||
|
||||
export const Route = () => (
|
||||
<ViewContainer main>
|
||||
<Divider height={remcalc(30)} transparent />
|
||||
<Margin bottom={4}>
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
An error occurred while loading your page
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
</Margin>
|
||||
</ViewContainer>
|
||||
);
|
||||
|
||||
export default () => (
|
||||
<RootContainer>
|
||||
<PageContainer>
|
||||
<Breadcrumb />
|
||||
<Route />
|
||||
</PageContainer>
|
||||
</RootContainer>
|
||||
);
|
33
packages/my-joy-beta/src/state/apollo-client.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import fetch from 'cross-fetch';
|
||||
|
||||
import global from './global';
|
||||
|
||||
const {
|
||||
REACT_APP_GQL_PORT = global.port,
|
||||
REACT_APP_GQL_PROTOCOL = global.protocol,
|
||||
REACT_APP_GQL_HOSTNAME = global.hostname
|
||||
} = process.env;
|
||||
|
||||
const PORT = REACT_APP_GQL_PORT ? `:${REACT_APP_GQL_PORT}` : '';
|
||||
const URI = `${REACT_APP_GQL_PROTOCOL}://${REACT_APP_GQL_HOSTNAME}${PORT}/graphql`;
|
||||
|
||||
export default (opts = {}) => {
|
||||
let cache = new InMemoryCache();
|
||||
|
||||
if (global.__APOLLO_STATE__) {
|
||||
cache = cache.restore(global.__APOLLO_STATE__);
|
||||
}
|
||||
|
||||
return new ApolloClient({
|
||||
cache,
|
||||
link: new HttpLink({
|
||||
uri: URI,
|
||||
credentials: 'same-origin',
|
||||
fetch
|
||||
}),
|
||||
...opts
|
||||
});
|
||||
};
|
16
packages/my-joy-beta/src/state/global.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { canUseDOM } from 'exenv';
|
||||
|
||||
export default (() => {
|
||||
if (!canUseDOM) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
port: window.location.port,
|
||||
protocol: window.location.protocol.replace(/:$/, ''),
|
||||
hostname: window.location.hostname,
|
||||
__REDUX_DEVTOOLS_EXTENSION__: window.__REDUX_DEVTOOLS_EXTENSION__,
|
||||
__APOLLO_STATE__: window.__APOLLO_STATE__,
|
||||
__REDUX_STATE__: window.__REDUX_STATE__
|
||||
};
|
||||
})();
|
45
packages/my-joy-beta/src/state/redux-store.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { reduxBatch } from '@manaflair/redux-batch';
|
||||
import { createStore, combineReducers, compose } from 'redux';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { reducer as valuesReducer } from 'react-redux-values';
|
||||
import paramCase from 'param-case';
|
||||
import global from './global';
|
||||
|
||||
const initialState = {
|
||||
ui: {
|
||||
sections: {
|
||||
instances: [
|
||||
'Summary',
|
||||
'CNS',
|
||||
'Snapshots',
|
||||
'Tags',
|
||||
'Metadata',
|
||||
'User Script',
|
||||
'Networks',
|
||||
'Firewall'
|
||||
].map(name => ({
|
||||
pathname: paramCase(name),
|
||||
name
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default () => {
|
||||
return createStore(
|
||||
combineReducers({
|
||||
values: valuesReducer,
|
||||
form: formReducer,
|
||||
ui: (state = {}) => state
|
||||
}),
|
||||
global.__REDUX_STATE__ || initialState,
|
||||
compose(
|
||||
reduxBatch,
|
||||
// If you are using the devToolsExtension, you can add it here also
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
typeof global.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined'
|
||||
? global.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
: f => f
|
||||
)
|
||||
);
|
||||
};
|
@ -1,62 +0,0 @@
|
||||
import { reduxBatch } from '@manaflair/redux-batch';
|
||||
import { createStore, combineReducers, compose } from 'redux';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import { reducer as valuesReducer } from 'react-redux-values';
|
||||
import paramCase from 'param-case';
|
||||
|
||||
const {
|
||||
REACT_APP_GQL_PORT = window.location.port,
|
||||
REACT_APP_GQL_PROTOCOL = window.location.protocol.replace(/:$/, ''),
|
||||
REACT_APP_GQL_HOSTNAME = window.location.hostname
|
||||
} = process.env;
|
||||
|
||||
const PORT = REACT_APP_GQL_PORT ? `:${REACT_APP_GQL_PORT}` : '';
|
||||
const URI = `${REACT_APP_GQL_PROTOCOL}://${REACT_APP_GQL_HOSTNAME}${PORT}/graphql`;
|
||||
|
||||
export const client = new ApolloClient({
|
||||
cache: new InMemoryCache(),
|
||||
link: new HttpLink({
|
||||
credentials: 'same-origin',
|
||||
uri: URI
|
||||
})
|
||||
});
|
||||
|
||||
const initialState = {
|
||||
ui: {
|
||||
sections: {
|
||||
instances: [
|
||||
'Summary',
|
||||
'CNS',
|
||||
'Snapshots',
|
||||
'Tags',
|
||||
'Metadata',
|
||||
'User Script',
|
||||
'Networks',
|
||||
'Firewall'
|
||||
].map(name => ({
|
||||
pathname: paramCase(name),
|
||||
name
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const store = createStore(
|
||||
combineReducers({
|
||||
values: valuesReducer,
|
||||
form: formReducer,
|
||||
ui: (state = {}) => state
|
||||
}),
|
||||
initialState,
|
||||
compose(
|
||||
reduxBatch,
|
||||
// If you are using the devToolsExtension, you can add it here also
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined'
|
||||
? window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
: f => f
|
||||
)
|
||||
);
|
@ -14,15 +14,15 @@
|
||||
"prepublish": "echo 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-cache-inmemory": "^1.1.5",
|
||||
"apollo-client": "^2.2.0",
|
||||
"apollo-link": "^1.0.7",
|
||||
"apollo-link-http": "^1.3.2",
|
||||
"apollo-link-state": "^0.3.1",
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"apollo-cache-inmemory": "^1.1.9",
|
||||
"apollo-client": "^2.2.5",
|
||||
"apollo-link": "^1.2.1",
|
||||
"apollo-link-http": "^1.5.1",
|
||||
"apollo-link-state": "^0.4.0",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"emotion": "^8.0.12",
|
||||
"emotion-theming": "^8.0.12",
|
||||
"graphql-tag": "^2.6.1",
|
||||
"graphql-tag": "^2.8.0",
|
||||
"inert": "^5.1.0",
|
||||
"joyent-icons": "^5.0.0",
|
||||
"joyent-ui-toolkit": "^5.0.0",
|
||||
@ -40,8 +40,8 @@
|
||||
"remcalc": "^1.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^8.2.1",
|
||||
"eslint": "^4.16.0",
|
||||
"babel-eslint": "^8.2.2",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1"
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ const RegionContainer = emotion('div')`
|
||||
padding-bottom: ${remcalc(24)};
|
||||
`;
|
||||
|
||||
const getDatacenters = gql`
|
||||
const GetDatacenters = gql`
|
||||
{
|
||||
regions @client {
|
||||
name
|
||||
@ -80,7 +80,10 @@ const Datacenters = ({ expanded, regions = [] }) =>
|
||||
) : null;
|
||||
|
||||
export default compose(
|
||||
graphql(getDatacenters, {
|
||||
graphql(GetDatacenters, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const {
|
||||
regions = [],
|
||||
|
@ -74,12 +74,18 @@ const Services = ({ expanded = false, categories = [], products = [] }) =>
|
||||
|
||||
export default compose(
|
||||
graphql(GetCategories, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { categories = [] } = data;
|
||||
return { categories };
|
||||
}
|
||||
}),
|
||||
graphql(GetProducts, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { products = [] } = data;
|
||||
return { products };
|
||||
|
@ -20,20 +20,20 @@ import {
|
||||
HeaderSpace
|
||||
} from './components';
|
||||
|
||||
const updateHeaderMutation = gql`
|
||||
const UpdateHeaderMutation = gql`
|
||||
mutation updateHeader($isOpen: Boolean!, $activePanel: String!) {
|
||||
updateHeader(isOpen: $isOpen, activePanel: $activePanel) @client
|
||||
}
|
||||
`;
|
||||
|
||||
const getHeader = gql`
|
||||
const GetHeader = gql`
|
||||
{
|
||||
isOpen @client
|
||||
activePanel @client
|
||||
}
|
||||
`;
|
||||
|
||||
const getAccount = gql`
|
||||
const GetAccount = gql`
|
||||
{
|
||||
account {
|
||||
login
|
||||
@ -96,7 +96,10 @@ const Navigation = ({ login, toggleSectionOpen, isOpen, activePanel }) => (
|
||||
);
|
||||
|
||||
export default compose(
|
||||
graphql(getAccount, {
|
||||
graphql(GetAccount, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { account = {}, loading = false, error = null } = data;
|
||||
const { login } = account;
|
||||
@ -104,7 +107,10 @@ export default compose(
|
||||
return { login, loading, error };
|
||||
}
|
||||
}),
|
||||
graphql(getHeader, {
|
||||
graphql(GetHeader, {
|
||||
options: () => ({
|
||||
ssr: false
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const {
|
||||
isOpen = false,
|
||||
@ -116,7 +122,7 @@ export default compose(
|
||||
return { isOpen, activePanel, loading, error };
|
||||
}
|
||||
}),
|
||||
graphql(updateHeaderMutation, {
|
||||
graphql(UpdateHeaderMutation, {
|
||||
props: ({ mutate, ownProps }) => ({
|
||||
toggleSectionOpen: (name = '') => {
|
||||
const { isOpen, activePanel } = ownProps;
|
||||
|
@ -21,7 +21,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"camel-case": "^3.0.0",
|
||||
"clipboard-copy": "^1.4.1",
|
||||
"clipboard-copy": "^1.4.2",
|
||||
"exenv": "^1.2.2",
|
||||
"joy-react-broadcast": "^0.6.9",
|
||||
"joyent-icons": "^5.0.0",
|
||||
"joyent-react-styled-flexboxgrid": "^2.2.3",
|
||||
@ -35,19 +36,19 @@
|
||||
"pascal-case": "^2.0.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-bundle": "^1.1.0",
|
||||
"react-popper": "^0.7.5",
|
||||
"react-responsive": "^4.0.3",
|
||||
"react-popper": "^0.8.2",
|
||||
"react-responsive": "^4.0.4",
|
||||
"remcalc": "^1.0.10",
|
||||
"rnd-id": "^2.0.2",
|
||||
"styled-components": "^3.1.4",
|
||||
"styled-components": "^3.1.6",
|
||||
"styled-is": "^1.1.2",
|
||||
"unitcalc": "^1.1.2"
|
||||
"unitcalc": "^1.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-preset-joyent-portal": "^6.0.3",
|
||||
"babel-preset-joyent-portal": "^7.0.1",
|
||||
"classnames": "^2.2.5",
|
||||
"eslint": "^4.16.0",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-config-joyent-portal": "^3.3.1",
|
||||
"jest-styled-components": "^4.11.0-0",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
@ -56,12 +57,12 @@
|
||||
"react-docgen": "^3.0.0-beta8",
|
||||
"react-docgen-displayname-handler": "^1.0.1",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-styleguidist": "^6.2.0",
|
||||
"react-styleguidist": "^6.2.5",
|
||||
"react-test-renderer": "^16.2.0",
|
||||
"redrun": "^5.10.0",
|
||||
"redrun": "^5.10.5",
|
||||
"styled-components-spacing": "^2.1.3",
|
||||
"styled-flex-component": "^2.2.0",
|
||||
"webpack": "^3.10.0"
|
||||
"styled-flex-component": "^2.2.1",
|
||||
"webpack": "^3.11.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"codemirror": "^5.32.0",
|
||||
|
@ -1,4 +1,16 @@
|
||||
import remcalc from 'remcalc';
|
||||
import { canUseDOM } from 'exenv';
|
||||
|
||||
const globals = (() => {
|
||||
if (!canUseDOM) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
protocol: window.location.protocol,
|
||||
host: window.location.host
|
||||
};
|
||||
})();
|
||||
|
||||
const flexboxgrid = {
|
||||
gridSize: 12, // rem
|
||||
@ -138,10 +150,12 @@ export const font = {
|
||||
family: '"Libre Franklin"',
|
||||
families:
|
||||
'"Libre Franklin", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica, sans-serif',
|
||||
href: () =>
|
||||
`${document.location.protocol}//${
|
||||
document.location.host
|
||||
}/fonts/css?family=Libre+Franklin:400,500,600,700`,
|
||||
href: ({ protocol, host } = {}) => {
|
||||
const _protocol = protocol || globals.protocol;
|
||||
const _host = host || globals.host;
|
||||
|
||||
return `${_protocol}//${_host}/fonts/css?family=Libre+Franklin:400,500,600,700`;
|
||||
},
|
||||
weight: {
|
||||
bold: 700,
|
||||
semibold: 600,
|
||||
@ -157,10 +171,12 @@ export const monoFont = {
|
||||
textMuted: base.secondary,
|
||||
family: '"Roboto Mono"',
|
||||
families: '"Roboto Mono", monospace',
|
||||
href: () =>
|
||||
`${document.location.protocol}//${
|
||||
document.location.host
|
||||
}/fonts/css?family=Roboto+Mono:700,400`,
|
||||
href: ({ protocol, host } = {}) => {
|
||||
const _protocol = protocol || globals.protocol;
|
||||
const _host = host || globals.host;
|
||||
|
||||
return `${_protocol}//${_host}/fonts/css?family=Roboto+Mono:700,400`;
|
||||
},
|
||||
weight: {
|
||||
bold: 700,
|
||||
normal: 400
|
||||
|
@ -31,7 +31,7 @@
|
||||
"styled-components": "^3.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-joyent-portal": "^6.0.1",
|
||||
"babel-preset-joyent-portal": "^7.0.0",
|
||||
"eslint": "^4.11.0",
|
||||
"eslint-config-joyent-portal": "^3.2.0",
|
||||
"joyent-react-scripts": "^7.3.0",
|
||||
|