mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-15 17:50:48 +02:00
Migrate to create-react-app and react-scripts (#263)
* Setup create-react-app and typescript Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
This commit is contained in:
parent
30e3f468eb
commit
22795e251f
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
|
||||||
"plugins": [
|
|
||||||
["@babel/plugin-proposal-decorators", { "legacy": true }],
|
|
||||||
"@babel/plugin-proposal-class-properties",
|
|
||||||
"@babel/plugin-transform-runtime"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"test": {
|
|
||||||
"plugins": ["@babel/plugin-transform-modules-commonjs"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
bundle.js
|
|
||||||
dist
|
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"finn",
|
|
||||||
"finn/node",
|
|
||||||
"finn-prettier"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"no-shadow": 0,
|
|
||||||
"prettier/prettier": [
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
"tabWidth": 4,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"printWidth": 120
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["**/__tests__/*"],
|
|
||||||
"env": { "jest": true }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
2
frontend/.github/workflows/node.js.yml
vendored
2
frontend/.github/workflows/node.js.yml
vendored
@ -25,4 +25,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: yarn
|
- run: yarn
|
||||||
- run: yarn run test:ci
|
- run: yarn run test
|
||||||
|
1
frontend/.gitignore
vendored
1
frontend/.gitignore
vendored
@ -41,6 +41,7 @@ typings/
|
|||||||
|
|
||||||
# Built
|
# Built
|
||||||
dist
|
dist
|
||||||
|
build
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Unleash [development]</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id='app'></div>
|
|
||||||
<script src="/static/bundle.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
publicFolder: path.join(__dirname, 'dist'),
|
publicFolder: path.join(__dirname, 'build'),
|
||||||
};
|
};
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
// We have set timezone to make sure tests are correct
|
|
||||||
module.exports = () => {
|
|
||||||
process.env.TZ = 'UTC';
|
|
||||||
};
|
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "unleash-frontend",
|
"name": "unleash-frontend",
|
||||||
"description": "unleash your features",
|
"description": "unleash your features",
|
||||||
"version": "4.0.0-alpha.1",
|
"version": "3.15.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"unleash",
|
"unleash",
|
||||||
"feature toggle",
|
"feature toggle",
|
||||||
@ -10,7 +10,7 @@
|
|||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
"dist/"
|
"build/"
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -20,106 +20,93 @@
|
|||||||
"url": "https://github.com/Unleash/unleash-frontend"
|
"url": "https://github.com/Unleash/unleash-frontend"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:assets && npm run build:html && npm run build:img && npm run build:ico",
|
"build": "react-scripts build",
|
||||||
"build:assets": "NODE_ENV=production webpack -p --display-optimization-bailout",
|
"start": "react-scripts start",
|
||||||
"build:html": "cp public/*.html dist/.",
|
"start:heroku": "UNLEASH_API=https://unleash.herokuapp.com yarn run start",
|
||||||
"build:ico": "cp public/*.ico dist/.",
|
"test": "react-scripts test",
|
||||||
"build:img": "cp public/*.png dist/public/. && cp public/*.svg dist/public/.",
|
"prepublish": "yarn run build"
|
||||||
"start": "NODE_ENV=development webpack-dev-server --progress --colors",
|
|
||||||
"start:heroku": "UNLEASH_API=https://unleash.herokuapp.com npm run start",
|
|
||||||
"lint": "eslint . --ext js,jsx",
|
|
||||||
"lint:fix": "eslint . --ext js,jsx --fix",
|
|
||||||
"test": "jest",
|
|
||||||
"test:ci": "npm run lint && npm run build && npm run test",
|
|
||||||
"prepublish": "npm run build"
|
|
||||||
},
|
},
|
||||||
"main": "./index.js",
|
"dependencies": {
|
||||||
"devDependencies": {
|
|
||||||
"@material-ui/lab": "4.0.0-alpha.57",
|
|
||||||
"@babel/core": "^7.9.0",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
|
||||||
"@babel/plugin-proposal-decorators": "^7.8.3",
|
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.9.0",
|
|
||||||
"@babel/plugin-transform-runtime": "^7.9.0",
|
|
||||||
"@babel/preset-env": "^7.9.5",
|
|
||||||
"@babel/preset-react": "^7.9.4",
|
|
||||||
"@material-ui/core": "^4.11.3",
|
"@material-ui/core": "^4.11.3",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@material-ui/styles": "^4.11.3",
|
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||||
"array-move": "^2.2.1",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"babel-eslint": "^10.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"babel-jest": "^25.3.0",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
"babel-loader": "^8.1.0",
|
"@types/enzyme": "^3.10.8",
|
||||||
"classnames": "^2.2.6",
|
"@types/enzyme-adapter-react-16": "^1.0.6",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"@types/jest": "^26.0.15",
|
||||||
"css-loader": "^2.1.1",
|
"@types/node": "^12.0.0",
|
||||||
"date-fns": "^2.17.0",
|
"@types/react": "^17.0.0",
|
||||||
"debounce": "^1.2.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
"debug": "^4.1.1",
|
"@types/react-router-dom": "^5.1.7",
|
||||||
"enzyme": "^3.9.0",
|
"array-move": "^3.0.1",
|
||||||
"enzyme-adapter-react-16": "^1.11.0",
|
"classnames": "^2.3.1",
|
||||||
"enzyme-to-json": "^3.3.5",
|
"css-loader": "^5.2.0",
|
||||||
"eslint": "^6.5.1",
|
"date-fns": "^2.19.0",
|
||||||
"eslint-config-finn": "^3.0.1",
|
"debounce": "^1.2.1",
|
||||||
"eslint-config-finn-prettier": "^3.0.2",
|
"enzyme": "^3.11.0",
|
||||||
"eslint-config-finn-react": "^2.0.2",
|
"enzyme-adapter-react-16": "^1.15.6",
|
||||||
"eslint-plugin-react": "^7.11.1",
|
|
||||||
"fetch-mock": "^9.11.0",
|
"fetch-mock": "^9.11.0",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"immutable": "^4.0.0-rc.12",
|
||||||
"immutable": "^3.8.1",
|
|
||||||
"jest": "^26.6.3",
|
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.flow": "^3.5.0",
|
"lodash.flow": "^3.5.0",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"node-sass": "^4.5.3",
|
"react": "^17.0.2",
|
||||||
"normalize.css": "^8.0.0",
|
"react-dnd": "^14.0.2",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.0",
|
"react-dnd-html5-backend": "^14.0.0",
|
||||||
"prettier": "^1.18.2",
|
"react-dom": "^17.0.2",
|
||||||
"prop-types": "^15.6.2",
|
"react-redux": "^7.2.3",
|
||||||
"react": "^16.14.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-dnd": "^11.1.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-dnd-html5-backend": "^11.1.3",
|
"react-timeago": "^5.2.0",
|
||||||
"react-dom": "^16.14.0",
|
|
||||||
"react-redux": "^7.2.0",
|
|
||||||
"react-router-dom": "^5.1.2",
|
|
||||||
"react-test-renderer": "^16.14.0",
|
|
||||||
"react-timeago": "^4.4.0",
|
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-devtools": "^3.7.0",
|
"redux-devtools-extension": "^2.13.9",
|
||||||
"redux-mock-store": "^1.5.4",
|
"redux-mock-store": "^1.5.4",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"sass-loader": "^7.0.1",
|
"sass": "^1.32.8",
|
||||||
"style-loader": "^1.0.0",
|
"typescript": "^4.2.3",
|
||||||
"toolbox-loader": "0.0.3",
|
"web-vitals": "^1.0.1"
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
|
||||||
"webpack": "^4.17.1",
|
|
||||||
"webpack-bundle-analyzer": "^4.4.0",
|
|
||||||
"webpack-cli": "^3.1.0",
|
|
||||||
"webpack-dev-server": "^3.11.2",
|
|
||||||
"whatwg-fetch": "^3.4.1"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/__mocks__/fileMock.js",
|
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/__mocks__/fileMock.js",
|
||||||
"\\.(css|scss)$": "identity-obj-proxy"
|
"\\.(css|scss)$": "identity-obj-proxy"
|
||||||
},
|
},
|
||||||
"setupFilesAfterEnv": [
|
|
||||||
"<rootDir>/src/setupTests.js"
|
|
||||||
],
|
|
||||||
"setupFiles": [
|
|
||||||
"<rootDir>/jest-setup.js"
|
|
||||||
],
|
|
||||||
"snapshotSerializers": [
|
"snapshotSerializers": [
|
||||||
"enzyme-to-json/serializer"
|
"enzyme-to-json/serializer"
|
||||||
],
|
|
||||||
"testPathIgnorePatterns": [
|
|
||||||
"/src/store/addons/__tests__/data.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-globals": "off",
|
||||||
|
"no-useless-computed-key": "off",
|
||||||
|
"import/no-anonymous-default-export": "off"
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"proxy": "http://localhost:4242",
|
||||||
|
"devDependencies": {
|
||||||
|
"enzyme-to-json": "^3.6.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,16 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="unleash">
|
<meta name="description" content="unleash">
|
||||||
|
|
||||||
<title>Unleash - Enterprise ready feature toggles</title>
|
<title>Unleash - Enterprise ready feature toggles</title>
|
||||||
<link rel="stylesheet" href="public/bundle.css">
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='app'></div>
|
<div id='app'></div>
|
||||||
<script src="public/bundle.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"parser": "babel-eslint",
|
|
||||||
"extends": [
|
|
||||||
"finn",
|
|
||||||
"finn-react",
|
|
||||||
"finn/es-modules",
|
|
||||||
"finn-prettier",
|
|
||||||
"finn-prettier/react"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"commonjs": true,
|
|
||||||
"es6": true
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"process": false
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 7,
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"experimentalObjectRestSpread": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"no-shadow": 0,
|
|
||||||
"react/sort-comp": 0,
|
|
||||||
"prettier/prettier": [
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
"tabWidth": 4,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"printWidth": 120
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,7 @@ const Reporting = ({ fetchFeatureToggles, projects }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchFeatureToggles();
|
fetchFeatureToggles();
|
||||||
setSelectedProject(projects[0].id);
|
setSelectedProject(projects[0].id);
|
||||||
}, []);
|
}, [fetchFeatureToggles, projects]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProjectOptions(formatProjectOptions(projects));
|
setProjectOptions(formatProjectOptions(projects));
|
||||||
@ -43,7 +43,7 @@ const Reporting = ({ fetchFeatureToggles, projects }) => {
|
|||||||
options={projectOptions}
|
options={projectOptions}
|
||||||
value={selectedProject}
|
value={selectedProject}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
inputProps={{ ['data-test']: REPORTING_SELECT_ID }}
|
inputProps={{ ['data-testid']: REPORTING_SELECT_ID }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,8 @@ import { Provider } from 'react-redux';
|
|||||||
import { HashRouter } from 'react-router-dom';
|
import { HashRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
import { mount } from 'enzyme/build';
|
|
||||||
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
|
|
||||||
import Reporting from '../Reporting';
|
import Reporting from '../Reporting';
|
||||||
import { REPORTING_SELECT_ID } from '../../../testIds';
|
import { REPORTING_SELECT_ID } from '../../../testIds';
|
||||||
@ -16,8 +17,8 @@ const mockStore = {
|
|||||||
};
|
};
|
||||||
const mockReducer = state => state;
|
const mockReducer = state => state;
|
||||||
|
|
||||||
test('changing projects renders only toggles from that project', () => {
|
test('changing projects renders only toggles from that project', async () => {
|
||||||
const wrapper = mount(
|
render(
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<Provider store={createStore(mockReducer, mockStore)}>
|
<Provider store={createStore(mockReducer, mockStore)}>
|
||||||
<Reporting projects={testProjects} features={testFeatures} fetchFeatureToggles={() => {}} />
|
<Reporting projects={testProjects} features={testFeatures} fetchFeatureToggles={() => {}} />
|
||||||
@ -25,14 +26,9 @@ test('changing projects renders only toggles from that project', () => {
|
|||||||
</HashRouter>
|
</HashRouter>
|
||||||
);
|
);
|
||||||
|
|
||||||
const select = wrapper.find(`input[data-test="${REPORTING_SELECT_ID}"][value="default"]`).first();
|
const table = await screen.findByRole("table");
|
||||||
|
|
||||||
let list = wrapper.find('tr');
|
|
||||||
/* Length of projects belonging to project (3) + header row (1) */
|
/* Length of projects belonging to project (3) + header row (1) */
|
||||||
expect(list.length).toBe(4);
|
expect(table.rows).toHaveLength(4);
|
||||||
|
fireEvent.change(await screen.findByTestId(REPORTING_SELECT_ID), { target: { value: 'myProject'}});
|
||||||
select.simulate('change', { target: { value: 'myProject' } });
|
expect(table.rows).toHaveLength(3);
|
||||||
list = wrapper.find('tr');
|
|
||||||
|
|
||||||
expect(list.length).toBe(3);
|
|
||||||
});
|
});
|
||||||
|
@ -15,11 +15,11 @@ const style = {
|
|||||||
const getIcon = name => {
|
const getIcon = name => {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'slack':
|
case 'slack':
|
||||||
return <img style={style} src="public/slack.svg" />;
|
return <img style={style} alt="Slack Logo" src="slack.svg" />;
|
||||||
case 'jira-comment':
|
case 'jira-comment':
|
||||||
return <img style={style} src="public/jira.svg" />;
|
return <img style={style} alt="JIRA Logo" src="jira.svg" />;
|
||||||
case 'webhook':
|
case 'webhook':
|
||||||
return <img style={style} src="public/webhooks.svg" />;
|
return <img style={style} alt="Generic Webhook logo" src="webhooks.svg" />;
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<Avatar>
|
<Avatar>
|
||||||
@ -34,7 +34,8 @@ const AddonList = ({ addons, providers, fetchAddons, removeAddon, toggleAddon, h
|
|||||||
if (addons.length === 0) {
|
if (addons.length === 0) {
|
||||||
fetchAddons();
|
fetchAddons();
|
||||||
}
|
}
|
||||||
}, []);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [addons.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -22,17 +22,17 @@ const AddonFormComponent = ({ editMode, provider, addon, fetch, cancel, submit }
|
|||||||
if (!provider) {
|
if (!provider) {
|
||||||
fetch();
|
fetch();
|
||||||
}
|
}
|
||||||
}, []); // empty array => fetch only first time
|
}, [fetch, provider]); // empty array => fetch only first time
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setConfig({ ...addon });
|
setConfig({ ...addon });
|
||||||
}, [addon.id]);
|
}, [addon]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (provider && !config.provider) {
|
if (provider && !config.provider) {
|
||||||
setConfig({ ...addon, provider: provider.name });
|
setConfig({ ...addon, provider: provider.name });
|
||||||
}
|
}
|
||||||
}, [provider]);
|
}, [provider, addon, config.provider]);
|
||||||
|
|
||||||
const setFieldValue = field => evt => {
|
const setFieldValue = field => evt => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
@ -104,7 +104,7 @@ const AddonFormComponent = ({ editMode, provider, addon, fetch, cancel, submit }
|
|||||||
<PageContent headerContent={`Configure ${name} addon`}>
|
<PageContent headerContent={`Configure ${name} addon`}>
|
||||||
<section className={styles.formSection}>
|
<section className={styles.formSection}>
|
||||||
{description}
|
{description}
|
||||||
<a href={documentationUrl} target="_blank">
|
<a href={documentationUrl} target="_blank" rel="noreferrer">
|
||||||
Read more
|
Read more
|
||||||
</a>
|
</a>
|
||||||
<p className={commonStyles.error}>{errors.general}</p>
|
<p className={commonStyles.error}>{errors.general}</p>
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
import { DndProvider, createDndContext } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import React, { useRef } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const RNDContext = createDndContext(HTML5Backend);
|
|
||||||
|
|
||||||
function useDNDProviderElement(props) {
|
function useDNDProviderElement(props) {
|
||||||
const manager = useRef(RNDContext);
|
|
||||||
|
|
||||||
if (!props.children) return null;
|
if (!props.children) return null;
|
||||||
|
|
||||||
return <DndProvider manager={manager.current.dragDropManager}>{props.children}</DndProvider>;
|
return <DndProvider backend={HTML5Backend}>{props.children}</DndProvider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DragAndDrop(props) {
|
export default function DragAndDrop(props) {
|
||||||
|
@ -108,7 +108,7 @@ export function getIcon(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const IconLink = ({ url, icon }) => (
|
export const IconLink = ({ url, icon }) => (
|
||||||
<a href={url} target="_blank" rel="noopener" className="mdl-color-text--grey-600">
|
<a href={url} target="_blank" rel="noreferrer" className="mdl-color-text--grey-600">
|
||||||
<Icon>{icon}</Icon>
|
<Icon>{icon}</Icon>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
@ -188,6 +188,7 @@ class AddContextComponent extends Component {
|
|||||||
<a
|
<a
|
||||||
href="https://unleash.github.io/docs/activation_strategy#flexiblerollout"
|
href="https://unleash.github.io/docs/activation_strategy#flexiblerollout"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
Read more
|
Read more
|
||||||
</a>
|
</a>
|
||||||
|
@ -5,6 +5,8 @@ import { MenuItem } from '@material-ui/core';
|
|||||||
import { MenuItemWithIcon } from '../../../common';
|
import { MenuItemWithIcon } from '../../../common';
|
||||||
import DropdownMenu from '../../../common/dropdown-menu';
|
import DropdownMenu from '../../../common/dropdown-menu';
|
||||||
import ProjectSelect from '../../../common/ProjectSelect';
|
import ProjectSelect from '../../../common/ProjectSelect';
|
||||||
|
import { useStyles } from './styles';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
const sortingOptions = [
|
const sortingOptions = [
|
||||||
{ type: 'name', displayName: 'Name' },
|
{ type: 'name', displayName: 'Name' },
|
||||||
@ -17,8 +19,6 @@ const sortingOptions = [
|
|||||||
{ type: 'metrics', displayName: 'Metrics' },
|
{ type: 'metrics', displayName: 'Metrics' },
|
||||||
];
|
];
|
||||||
|
|
||||||
import { useStyles } from './styles';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
const FeatureToggleListActions = ({ settings, setSort, toggleMetrics, updateSetting, loading }) => {
|
const FeatureToggleListActions = ({ settings, setSort, toggleMetrics, updateSetting, loading }) => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
@ -52,6 +52,7 @@ const FeatureView = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scrollToTop();
|
scrollToTop();
|
||||||
fetchTags(featureToggleName);
|
fetchTags(featureToggleName);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -62,6 +63,7 @@ const FeatureView = ({
|
|||||||
fetchArchive();
|
fetchArchive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [features]);
|
}, [features]);
|
||||||
|
|
||||||
const getTabComponent = key => {
|
const getTabComponent = key => {
|
||||||
@ -91,6 +93,8 @@ const FeatureView = ({
|
|||||||
);
|
);
|
||||||
case 'log':
|
case 'log':
|
||||||
return <HistoryComponent toggleName={featureToggleName} />;
|
return <HistoryComponent toggleName={featureToggleName} />;
|
||||||
|
default:
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getTabData = () => [
|
const getTabData = () => [
|
||||||
|
@ -103,7 +103,6 @@ class CopyFeatureComponent extends Component {
|
|||||||
label="Feature toggle name"
|
label="Feature toggle name"
|
||||||
name="name"
|
name="name"
|
||||||
value={newToggleName}
|
value={newToggleName}
|
||||||
error={nameError}
|
|
||||||
onBlur={this.onValidateName}
|
onBlur={this.onValidateName}
|
||||||
onChange={this.setValue}
|
onChange={this.setValue}
|
||||||
error={nameError !== undefined}
|
error={nameError !== undefined}
|
||||||
|
@ -20,11 +20,11 @@ function FeatureTagComponent({ tags, tagTypes, featureToggleName, untagFeature }
|
|||||||
if (tagType && tagType.icon) {
|
if (tagType && tagType.icon) {
|
||||||
switch (tagType.name) {
|
switch (tagType.name) {
|
||||||
case 'slack':
|
case 'slack':
|
||||||
return <img style={style} alt="slack" src="public/slack.svg" />;
|
return <img style={style} alt="slack" src="slack.svg" />;
|
||||||
case 'jira':
|
case 'jira':
|
||||||
return <img style={style} alt="jira" src="public/jira.svg" />;
|
return <img style={style} alt="jira" src="jira.svg" />;
|
||||||
case 'webhook':
|
case 'webhook':
|
||||||
return <img style={style} alt="webhook" src="public/webhooks.svg" />;
|
return <img style={style} alt="webhook" src="webhooks.svg" />;
|
||||||
default:
|
default:
|
||||||
return <Icon>label</Icon>;
|
return <Icon>label</Icon>;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export default function GeneralStrategyInput({ parameters, strategyDefinition, u
|
|||||||
maxLabel="on"
|
maxLabel="on"
|
||||||
/>
|
/>
|
||||||
{description && (
|
{description && (
|
||||||
<p className={styles.helpText} className={styles.helperText}>
|
<p className={styles.helpText}>
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
@ -67,6 +67,8 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
|||||||
show={<StrategyCardField title={paramDefinition.name} value={param} />}
|
show={<StrategyCardField title={paramDefinition.name} value={param} />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
default:
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ const StrategiesList = props => {
|
|||||||
if (!editStrategyIndex) {
|
if (!editStrategyIndex) {
|
||||||
updateEditableStrategies(cloneDeep(props.configuredStrategies));
|
updateEditableStrategies(cloneDeep(props.configuredStrategies));
|
||||||
}
|
}
|
||||||
}, [props.configuredStrategies]);
|
}, [props.configuredStrategies, editStrategyIndex]);
|
||||||
|
|
||||||
const updateStrategy = index => strategy => {
|
const updateStrategy = index => strategy => {
|
||||||
const newStrategy = { ...strategy };
|
const newStrategy = { ...strategy };
|
||||||
|
@ -499,6 +499,7 @@ exports[`renders correctly with with variants 1`] = `
|
|||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://unleash.github.io/docs/toggle_variants"
|
href="https://unleash.github.io/docs/toggle_variants"
|
||||||
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Read more
|
Read more
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { TextField, FormControl, FormControlLabel, Grid, Icon, Switch } from '@material-ui/core';
|
import { FormControl, FormControlLabel, Grid, Icon, Switch, TextField } from '@material-ui/core';
|
||||||
import Dialog from '../../common/Dialogue';
|
import Dialog from '../../common/Dialogue';
|
||||||
import MySelect from '../../common/select';
|
import MySelect from '../../common/select';
|
||||||
import { trim, modalStyles } from '../../common/util';
|
import { modalStyles, trim } from '../../common/util';
|
||||||
import { weightTypes } from './enums';
|
import { weightTypes } from './enums';
|
||||||
import OverrideConfig from './e-override-config';
|
import OverrideConfig from './e-override-config';
|
||||||
|
|
||||||
@ -46,6 +46,7 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
clear();
|
clear();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [editVariant]);
|
}, [editVariant]);
|
||||||
|
|
||||||
const setVariantValue = e => {
|
const setVariantValue = e => {
|
||||||
|
@ -111,7 +111,7 @@ class UpdateVariantComponent extends Component {
|
|||||||
>
|
>
|
||||||
By overriding the stickiness you can control which parameter you want to be used in order to ensure
|
By overriding the stickiness you can control which parameter you want to be used in order to ensure
|
||||||
consistent traffic allocation across variants.{' '}
|
consistent traffic allocation across variants.{' '}
|
||||||
<a href="https://unleash.github.io/docs/toggle_variants" target="_blank">
|
<a href="https://unleash.github.io/docs/toggle_variants" target="_blank" rel="noreferrer">
|
||||||
Read more
|
Read more
|
||||||
</a>
|
</a>
|
||||||
</small>
|
</small>
|
||||||
|
@ -33,7 +33,7 @@ export const Footer = () => (
|
|||||||
<ListItem key="github_link" className={styles.listItem}>
|
<ListItem key="github_link" className={styles.listItem}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
<a href="https://github.com/Unleash/unleash/" target="_blank">
|
<a href="https://github.com/Unleash/unleash/" target="_blank" rel="noreferrer">
|
||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ const Header = ({ uiConfig, init }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
init(uiConfig.flags);
|
init(uiConfig.flags);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { loadInitialData } from '../../../store/loader';
|
import { loadInitialData } from '../../../store/loader';
|
||||||
|
|
||||||
const mapStateToProps = state => ({ uiConfig: state.uiConfig.toJS() });
|
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({ uiConfig: state.uiConfig.toJS() });
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
export default connect(mapStateToProps, {
|
||||||
init: loadInitialData,
|
init: loadInitialData,
|
||||||
})(Header);
|
})(Header);
|
||||||
|
@ -43,7 +43,7 @@ function renderLink(link, toggleDrawer) {
|
|||||||
key={link.href}
|
key={link.href}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={[styles.navigationLink].join(' ')}
|
className={[styles.navigationLink].join(' ')}
|
||||||
title={link.title}
|
title={link.title} rel="noreferrer"
|
||||||
>
|
>
|
||||||
{getIcon(link.icon)} {link.value}
|
{getIcon(link.icon)} {link.value}
|
||||||
</a>
|
</a>
|
||||||
@ -56,7 +56,7 @@ export const DrawerMenu = ({ links = [], title = 'Unleash', flags = {}, open = f
|
|||||||
<div className={styles.drawerContainer}>
|
<div className={styles.drawerContainer}>
|
||||||
<div className={styles.drawerTitleContainer}>
|
<div className={styles.drawerTitleContainer}>
|
||||||
<span className={[styles.drawerTitle].join(' ')}>
|
<span className={[styles.drawerTitle].join(' ')}>
|
||||||
<img src="public/logo.png" width="32" height="32" className={styles.drawerTitleLogo} />
|
<img alt="Unleash Logo" src="logo.png" width="32" height="32" className={styles.drawerTitleLogo} />
|
||||||
<span className={styles.drawerTitleText}>{title}</span>
|
<span className={styles.drawerTitleText}>{title}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@ const ProjectList = ({ projects, fetchProjects, removeProject, history, hasPermi
|
|||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProjects();
|
fetchProjects();
|
||||||
}, []);
|
}, [fetchProjects]);
|
||||||
|
|
||||||
const addProjectButton = () => (
|
const addProjectButton = () => (
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
Avatar,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemSecondaryAction,
|
|
||||||
ListItemText,
|
|
||||||
ListItemAvatar,
|
|
||||||
Select,
|
|
||||||
MenuItem,
|
|
||||||
Icon,
|
|
||||||
IconButton,
|
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogTitle,
|
|
||||||
DialogContentText,
|
|
||||||
DialogContent,
|
DialogContent,
|
||||||
Button,
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemAvatar,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemText,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
|
|
||||||
import AddUserComponent from './access-add-user';
|
import AddUserComponent from './access-add-user';
|
||||||
@ -38,6 +38,7 @@ function AccessComponent({ projectId, project }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAccess();
|
fetchAccess();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [projectId]);
|
}, [projectId]);
|
||||||
|
|
||||||
if (!project) {
|
if (!project) {
|
||||||
|
@ -27,6 +27,7 @@ const StrategiesList = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchStrategies();
|
fetchStrategies();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const headerButton = () => (
|
const headerButton = () => (
|
||||||
|
@ -29,6 +29,7 @@ const TagTypeList = ({ tagTypes, fetchTagTypes, removeTagType, hasPermission })
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTagTypes();
|
fetchTagTypes();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
let header = (
|
let header = (
|
||||||
|
@ -18,6 +18,7 @@ const TagList = ({ tags, fetchTags, removeTag, hasPermission }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTags();
|
fetchTags();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const remove = (tag, evt) => {
|
const remove = (tag, evt) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CardActions, Button, TextField, Typography } from '@material-ui/core';
|
import { CardActions, Button, TextField, Typography, IconButton } from '@material-ui/core';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
import { useCommonStyles } from '../../../common.styles';
|
import { useCommonStyles } from '../../../common.styles';
|
||||||
@ -121,9 +121,9 @@ const PasswordAuth = ({ authDetails, passwordLogin, loadInitialData }) => {
|
|||||||
condition={showFields}
|
condition={showFields}
|
||||||
show={renderLoginForm()}
|
show={renderLoginForm()}
|
||||||
elseShow={
|
elseShow={
|
||||||
<a href="" onClick={onShowOptions}>
|
<IconButton> onClick={onShowOptions}>
|
||||||
Show more options
|
Show more options
|
||||||
</a>
|
</IconButton>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,7 +29,7 @@ const SimpleAuth = ({ insecureLogin, loadInitialData, history, authDetails }) =>
|
|||||||
<p>
|
<p>
|
||||||
This instance of Unleash is not set up with a secure authentication provider. You can read more
|
This instance of Unleash is not set up with a secure authentication provider. You can read more
|
||||||
about{' '}
|
about{' '}
|
||||||
<a href="https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md" target="_blank">
|
<a href="https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md" target="_blank" rel="noreferrer">
|
||||||
securing Unleash on GitHub
|
securing Unleash on GitHub
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Card, CardContent, CardHeader } from '@material-ui/core';
|
import { Card, CardContent, CardHeader } from '@material-ui/core';
|
||||||
import { styles as commonStyles } from '../common';
|
import { styles as commonStyles } from '../common';
|
||||||
|
|
||||||
export default class FeatureListComponent extends React.Component {
|
const LogoutComponent = ({logoutUser}) => {
|
||||||
static propTypes = {
|
useEffect(() => {
|
||||||
logoutUser: PropTypes.func.isRequired,
|
logoutUser();
|
||||||
};
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
return (<Card shadow={0} className={commonStyles.fullwidth}>
|
||||||
this.props.logoutUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Card shadow={0} className={commonStyles.fullwidth}>
|
|
||||||
<CardHeader>Logged out</CardHeader>
|
<CardHeader>Logged out</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
You have now been successfully logged out of Unleash. Thank you for using Unleash.{' '}
|
You have now been successfully logged out of Unleash. Thank you for using Unleash.{' '}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
LogoutComponent.propTypes = {
|
||||||
|
logoutUser: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogoutComponent;
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ export default class ShowUserComponent extends React.Component {
|
|||||||
const email = this.props.profile ? this.props.profile.email : '';
|
const email = this.props.profile ? this.props.profile.email : '';
|
||||||
const locale = this.getLocale();
|
const locale = this.getLocale();
|
||||||
let foundLocale = this.possibleLocales.find(l => l.value === locale);
|
let foundLocale = this.possibleLocales.find(l => l.value === locale);
|
||||||
const imageUrl = email ? this.props.profile.imageUrl : 'public/unknown-user.png';
|
const imageUrl = email ? this.props.profile.imageUrl : 'unknown-user.png';
|
||||||
const imageLocale = foundLocale ? `public/${foundLocale.image}.png` : `public/unknown-locale.png`;
|
const imageLocale = foundLocale ? `${foundLocale.image}.png` : `unknown-locale.png`;
|
||||||
return (
|
return (
|
||||||
<div className={styles.showUserSettings}>
|
<div className={styles.showUserSettings}>
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
@ -60,7 +60,7 @@ export default class ShowUserComponent extends React.Component {
|
|||||||
this.possibleLocales.map(i => (
|
this.possibleLocales.map(i => (
|
||||||
<MenuItem key={i.value} onClick={() => this.setLocale(i)}>
|
<MenuItem key={i.value} onClick={() => this.setLocale(i)}>
|
||||||
<div className={styles.showLocale}>
|
<div className={styles.showLocale}>
|
||||||
<img src={`public/${i.image}.png`} title={i.value} alt={i.value} />
|
<img src={`${i.image}.png`} title={i.value} alt={i.value} />
|
||||||
<Typography variant="p">{i.value}</Typography>
|
<Typography variant="p">{i.value}</Typography>
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -18,10 +18,11 @@ import App from './component/app';
|
|||||||
import ScrollToTop from './component/scroll-to-top';
|
import ScrollToTop from './component/scroll-to-top';
|
||||||
import { writeWarning } from './security-logger';
|
import { writeWarning } from './security-logger';
|
||||||
|
|
||||||
|
|
||||||
let composeEnhancers;
|
let composeEnhancers;
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
if (process.env.NODE_ENV !== 'production' && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
||||||
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||||
} else {
|
} else {
|
||||||
composeEnhancers = compose;
|
composeEnhancers = compose;
|
||||||
writeWarning();
|
writeWarning();
|
@ -12,7 +12,7 @@ function ApiHowTo() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Read the{' '}
|
Read the{' '}
|
||||||
<a href="https://www.unleash-hosted.com/docs" target="_blank">
|
<a href="https://www.unleash-hosted.com/docs" target="_blank" rel="noreferrer">
|
||||||
Getting started guide
|
Getting started guide
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
to learn how to connect to the Unleash API form your application or programmatically. <br /> <br />
|
to learn how to connect to the Unleash API form your application or programmatically. <br /> <br />
|
||||||
|
@ -20,6 +20,7 @@ function ApiKeyList({ location, fetchApiKeys, removeKey, addKey, keys, hasPermis
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchApiKeys();
|
fetchApiKeys();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Icon } from '@material-ui/core';
|
import { Icon, IconButton } from '@material-ui/core';
|
||||||
|
|
||||||
function Secret({ value }) {
|
function Secret({ value }) {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
@ -17,9 +17,9 @@ function Secret({ value }) {
|
|||||||
<span>***************************</span>
|
<span>***************************</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<a href="" onClick={toggle} title="Show token">
|
<IconButton aria-label="Show token" onClick={toggle} title="Show token">
|
||||||
<Icon style={{ marginLeft: '5px', fontSize: '1.2em' }}>visibility</Icon>
|
<Icon style={{ marginLeft: '5px', fontSize: '1.2em' }}>visibility</Icon>
|
||||||
</a>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ function GoogleAuth({ config, getGoogleConfig, updateGoogleConfig, hasPermission
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getGoogleConfig();
|
getGoogleConfig();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -59,7 +60,7 @@ function GoogleAuth({ config, getGoogleConfig, updateGoogleConfig, hasPermission
|
|||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
Please read the{' '}
|
Please read the{' '}
|
||||||
<a href="https://www.unleash-hosted.com/docs/enterprise-authentication/google" target="_blank">
|
<a href="https://www.unleash-hosted.com/docs/enterprise-authentication/google" target="_blank" rel="noreferrer">
|
||||||
documentation
|
documentation
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
to learn how to integrate with Google OAuth 2.0. <br />
|
to learn how to integrate with Google OAuth 2.0. <br />
|
||||||
|
@ -15,12 +15,14 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, hasPermission }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getSamlConfig();
|
getSamlConfig();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (config.entityId) {
|
if (config.entityId) {
|
||||||
setData(config);
|
setData(config);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
if (!hasPermission('ADMIN')) {
|
if (!hasPermission('ADMIN')) {
|
||||||
@ -59,7 +61,7 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, hasPermission }) {
|
|||||||
<Grid item md={12}>
|
<Grid item md={12}>
|
||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
Please read the{' '}
|
Please read the{' '}
|
||||||
<a href="https://www.unleash-hosted.com/docs/enterprise-authentication" target="_blank">
|
<a href="https://www.unleash-hosted.com/docs/enterprise-authentication" target="_blank" rel="noreferrer">
|
||||||
documentation
|
documentation
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
to learn how to integrate with specific SAML 2.0 providers (Okta, Keycloak, etc). <br />
|
to learn how to integrate with specific SAML 2.0 providers (Okta, Keycloak, etc). <br />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable no-alert */
|
/* eslint-disable no-alert */
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, Icon, Table, TableBody, TableCell, TableHead, TableRow } from '@material-ui/core';
|
import { Button, Icon, IconButton, Table, TableBody, TableCell, TableHead, TableRow } from '@material-ui/core';
|
||||||
import { formatFullDateTimeWithLocale } from '../../../../component/common/util';
|
import { formatFullDateTimeWithLocale } from '../../../../component/common/util';
|
||||||
import AddUser from '../add-user-component';
|
import AddUser from '../add-user-component';
|
||||||
import ChangePassword from '../change-password-component';
|
import ChangePassword from '../change-password-component';
|
||||||
@ -65,6 +65,7 @@ function UsersList({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -92,22 +93,22 @@ function UsersList({
|
|||||||
condition={hasPermission('ADMIN')}
|
condition={hasPermission('ADMIN')}
|
||||||
show={
|
show={
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<a href="" title="Edit" onClick={openUpdateDialog(item)}>
|
<IconButton aria-label="Edit" title="Edit" onClick={openUpdateDialog(item)}>
|
||||||
<Icon>edit</Icon>
|
<Icon>edit</Icon>
|
||||||
</a>
|
</IconButton>
|
||||||
<a href="" title="Change password" onClick={openPwDialog(item)}>
|
<IconButton aria-label="Change password" title="Change password" onClick={openPwDialog(item)}>
|
||||||
<Icon>lock</Icon>
|
<Icon>lock</Icon>
|
||||||
</a>
|
</IconButton>
|
||||||
<a href="" title="Remove user" onClick={openDelDialog(item)}>
|
<IconButton aria-label="Remove user" title="Remove user" onClick={openDelDialog(item)}>
|
||||||
<Icon>delete</Icon>
|
<Icon>delete</Icon>
|
||||||
</a>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<a href="" title="Change password" onClick={openPwDialog(item)}>
|
<IconButton aria-label="Change password" title="Change password" onClick={openPwDialog(item)}>
|
||||||
<Icon>lock</Icon>
|
<Icon>lock</Icon>
|
||||||
</a>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -13,12 +13,13 @@ import {
|
|||||||
import { showPermissions, modalStyles } from './util';
|
import { showPermissions, modalStyles } from './util';
|
||||||
|
|
||||||
function AddUser({ user, showDialog, closeDialog, updateUser }) {
|
function AddUser({ user, showDialog, closeDialog, updateUser }) {
|
||||||
|
const [data, setData] = useState(user);
|
||||||
|
const [error, setError] = useState({});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [data, setData] = useState(user);
|
|
||||||
const [error, setError] = useState({});
|
|
||||||
|
|
||||||
const updateField = e => {
|
const updateField = e => {
|
||||||
setData({
|
setData({
|
||||||
|
1
frontend/src/react-app-env.d.ts
vendored
Normal file
1
frontend/src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="react-scripts" />
|
@ -1,5 +1,6 @@
|
|||||||
|
import '@testing-library/jest-dom'
|
||||||
import { configure } from 'enzyme';
|
import { configure } from 'enzyme';
|
||||||
import Adapter from 'enzyme-adapter-react-16';
|
import Adapter from 'enzyme-adapter-react-16';
|
||||||
|
|
||||||
configure({ adapter: new Adapter() });
|
|
||||||
process.env.TZ = 'UTC';
|
process.env.TZ = 'UTC';
|
||||||
|
configure({ adapter: new Adapter() });
|
@ -1,6 +1,6 @@
|
|||||||
import reducer from '../index';
|
import reducer from '../index';
|
||||||
import { RECEIVE_ADDON_CONFIG, ADD_ADDON_CONFIG, REMOVE_ADDON_CONFIG, UPDATE_ADDON_CONFIG } from '../actions';
|
import { RECEIVE_ADDON_CONFIG, ADD_ADDON_CONFIG, REMOVE_ADDON_CONFIG, UPDATE_ADDON_CONFIG } from '../actions';
|
||||||
import { addonSimple, addonsWithConfig, addonConfig } from './data';
|
import { addonSimple, addonsWithConfig, addonConfig } from '../__testdata__/data';
|
||||||
import { USER_LOGOUT } from '../../user/actions';
|
import { USER_LOGOUT } from '../../user/actions';
|
||||||
|
|
||||||
test('should be default state', () => {
|
test('should be default state', () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_ADDON_CONFIG = 'RECEIVE_ADDON_CONFIG';
|
export const RECEIVE_ADDON_CONFIG = 'RECEIVE_ADDON_CONFIG';
|
||||||
export const ERROR_RECEIVE_ADDON_CONFIG = 'ERROR_RECEIVE_ADDON_CONFIG';
|
export const ERROR_RECEIVE_ADDON_CONFIG = 'ERROR_RECEIVE_ADDON_CONFIG';
|
||||||
@ -22,7 +22,7 @@ export function fetchAddons() {
|
|||||||
api
|
api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(success(dispatch, RECEIVE_ADDON_CONFIG))
|
.then(success(dispatch, RECEIVE_ADDON_CONFIG))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ADDON_CONFIG));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_ADDON_CONFIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeAddon(addon) {
|
export function removeAddon(addon) {
|
||||||
@ -30,7 +30,7 @@ export function removeAddon(addon) {
|
|||||||
api
|
api
|
||||||
.remove(addon)
|
.remove(addon)
|
||||||
.then(() => dispatch(removeAddonconfig(addon)))
|
.then(() => dispatch(removeAddonconfig(addon)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_ADDON_CONFIG));
|
.catch(dispatchError(dispatch, ERROR_REMOVING_ADDON_CONFIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAddon(addon) {
|
export function createAddon(addon) {
|
||||||
@ -39,7 +39,7 @@ export function createAddon(addon) {
|
|||||||
.create(addon)
|
.create(addon)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(value => dispatch(addAddonConfig(value)))
|
.then(value => dispatch(addAddonConfig(value)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_ADDON_CONFIG));
|
.catch(dispatchError(dispatch, ERROR_ADD_ADDON_CONFIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateAddon(addon) {
|
export function updateAddon(addon) {
|
||||||
@ -47,5 +47,5 @@ export function updateAddon(addon) {
|
|||||||
api
|
api
|
||||||
.update(addon)
|
.update(addon)
|
||||||
.then(() => dispatch(updateAdddonConfig(addon)))
|
.then(() => dispatch(updateAdddonConfig(addon)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_ADDON_CONFIG));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_ADDON_CONFIG));
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,10 @@ function remove(addonConfig) {
|
|||||||
}).then(throwIfNotSuccess);
|
}).then(throwIfNotSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
const api = {
|
||||||
fetchAll,
|
fetchAll,
|
||||||
create,
|
create,
|
||||||
update,
|
update,
|
||||||
remove,
|
remove,
|
||||||
};
|
};
|
||||||
|
export default api;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
import { MUTE_ERROR } from '../error/actions';
|
import { MUTE_ERROR } from '../error/actions';
|
||||||
|
|
||||||
export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS';
|
export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS';
|
||||||
@ -26,7 +26,7 @@ export function fetchAll() {
|
|||||||
api
|
api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(recieveAllApplications(json)))
|
.then(json => dispatch(recieveAllApplications(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function storeApplicationMetaData(appName, key, value) {
|
export function storeApplicationMetaData(appName, key, value) {
|
||||||
@ -38,7 +38,7 @@ export function storeApplicationMetaData(appName, key, value) {
|
|||||||
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
||||||
dispatch({ type: UPDATE_APPLICATION_FIELD, appName, key, value, info });
|
dispatch({ type: UPDATE_APPLICATION_FIELD, appName, key, value, info });
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATING_APPLICATION_DATA));
|
.catch(dispatchError(dispatch, ERROR_UPDATING_APPLICATION_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchApplication(appName) {
|
export function fetchApplication(appName) {
|
||||||
@ -46,7 +46,7 @@ export function fetchApplication(appName) {
|
|||||||
api
|
api
|
||||||
.fetchApplication(appName)
|
.fetchApplication(appName)
|
||||||
.then(json => dispatch(recieveApplication(json)))
|
.then(json => dispatch(recieveApplication(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteApplication(appName) {
|
export function deleteApplication(appName) {
|
||||||
@ -54,5 +54,5 @@ export function deleteApplication(appName) {
|
|||||||
api
|
api
|
||||||
.deleteApplication(appName)
|
.deleteApplication(appName)
|
||||||
.then(() => dispatch({ type: DELETE_APPLICATION, appName }))
|
.then(() => dispatch({ type: DELETE_APPLICATION, appName }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_DELETE_APPLICATION));
|
.catch(dispatchError(dispatch, ERROR_DELETE_APPLICATION));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const REVIVE_TOGGLE = 'REVIVE_TOGGLE';
|
export const REVIVE_TOGGLE = 'REVIVE_TOGGLE';
|
||||||
export const RECEIVE_ARCHIVE = 'RECEIVE_ARCHIVE';
|
export const RECEIVE_ARCHIVE = 'RECEIVE_ARCHIVE';
|
||||||
@ -20,7 +20,7 @@ export function revive(featureToggle) {
|
|||||||
api
|
api
|
||||||
.revive(featureToggle)
|
.revive(featureToggle)
|
||||||
.then(() => dispatch(reviveToggle(featureToggle)))
|
.then(() => dispatch(reviveToggle(featureToggle)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ARCHIVE));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_ARCHIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchArchive() {
|
export function fetchArchive() {
|
||||||
@ -28,5 +28,5 @@ export function fetchArchive() {
|
|||||||
api
|
api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(receiveArchive(json)))
|
.then(json => dispatch(receiveArchive(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ARCHIVE));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_ARCHIVE));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_CONTEXT = 'RECEIVE_CONTEXT';
|
export const RECEIVE_CONTEXT = 'RECEIVE_CONTEXT';
|
||||||
export const ERROR_RECEIVE_CONTEXT = 'ERROR_RECEIVE_CONTEXT';
|
export const ERROR_RECEIVE_CONTEXT = 'ERROR_RECEIVE_CONTEXT';
|
||||||
@ -23,7 +23,7 @@ export function fetchContext() {
|
|||||||
json.sort((a, b) => a.sortOrder - b.sortOrder);
|
json.sort((a, b) => a.sortOrder - b.sortOrder);
|
||||||
dispatch(receiveContext(json));
|
dispatch(receiveContext(json));
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_CONTEXT));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeContextField(context) {
|
export function removeContextField(context) {
|
||||||
@ -31,7 +31,7 @@ export function removeContextField(context) {
|
|||||||
api
|
api
|
||||||
.remove(context)
|
.remove(context)
|
||||||
.then(() => dispatch(createRemoveContext(context)))
|
.then(() => dispatch(createRemoveContext(context)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_CONTEXT));
|
.catch(dispatchError(dispatch, ERROR_REMOVING_CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createContextField(context) {
|
export function createContextField(context) {
|
||||||
@ -39,7 +39,7 @@ export function createContextField(context) {
|
|||||||
api
|
api
|
||||||
.create(context)
|
.create(context)
|
||||||
.then(() => dispatch(addContextField(context)))
|
.then(() => dispatch(addContextField(context)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_CONTEXT_FIELD));
|
.catch(dispatchError(dispatch, ERROR_ADD_CONTEXT_FIELD));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateContextField(context) {
|
export function updateContextField(context) {
|
||||||
@ -47,7 +47,7 @@ export function updateContextField(context) {
|
|||||||
api
|
api
|
||||||
.update(context)
|
.update(context)
|
||||||
.then(() => dispatch(upContextField(context)))
|
.then(() => dispatch(upContextField(context)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_CONTEXT_FIELD));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_CONTEXT_FIELD));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateName(name) {
|
export function validateName(name) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
export const RECIEVE_GOOGLE_CONFIG = 'RECIEVE_GOOGLE_CONFIG';
|
export const RECIEVE_GOOGLE_CONFIG = 'RECIEVE_GOOGLE_CONFIG';
|
||||||
export const RECIEVE_GOOGLE_CONFIG_ERROR = 'RECIEVE_GOOGLE_CONFIG_ERROR';
|
export const RECIEVE_GOOGLE_CONFIG_ERROR = 'RECIEVE_GOOGLE_CONFIG_ERROR';
|
||||||
export const UPDATE_GOOGLE_AUTH = 'UPDATE_GOOGLE_AUTH';
|
export const UPDATE_GOOGLE_AUTH = 'UPDATE_GOOGLE_AUTH';
|
||||||
@ -22,7 +22,7 @@ export function getGoogleConfig() {
|
|||||||
config,
|
config,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch(dispatchAndThrow(dispatch, RECIEVE_GOOGLE_CONFIG_ERROR));
|
.catch(dispatchError(dispatch, RECIEVE_GOOGLE_CONFIG_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateGoogleConfig(data) {
|
export function updateGoogleConfig(data) {
|
||||||
@ -30,7 +30,7 @@ export function updateGoogleConfig(data) {
|
|||||||
api
|
api
|
||||||
.updateGoogleConfig(data)
|
.updateGoogleConfig(data)
|
||||||
.then(config => dispatch({ type: UPDATE_GOOGLE_AUTH, config }))
|
.then(config => dispatch({ type: UPDATE_GOOGLE_AUTH, config }))
|
||||||
.catch(dispatchAndThrow(dispatch, UPDATE_GOOGLE_AUTH_ERROR));
|
.catch(dispatchError(dispatch, UPDATE_GOOGLE_AUTH_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSamlConfig() {
|
export function getSamlConfig() {
|
||||||
@ -44,7 +44,7 @@ export function getSamlConfig() {
|
|||||||
config,
|
config,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch(dispatchAndThrow(dispatch, RECIEVE_SAML_CONFIG_ERROR));
|
.catch(dispatchError(dispatch, RECIEVE_SAML_CONFIG_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateSamlConfig(data) {
|
export function updateSamlConfig(data) {
|
||||||
@ -52,5 +52,5 @@ export function updateSamlConfig(data) {
|
|||||||
api
|
api
|
||||||
.updateSamlConfig(data)
|
.updateSamlConfig(data)
|
||||||
.then(config => dispatch({ type: UPDATE_SAML_AUTH, config }))
|
.then(config => dispatch({ type: UPDATE_SAML_AUTH, config }))
|
||||||
.catch(dispatchAndThrow(dispatch, UPDATE_SAML_AUTH_ERROR));
|
.catch(dispatchError(dispatch, UPDATE_SAML_AUTH_ERROR));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
export const RECIEVE_KEYS = 'RECIEVE_KEYS';
|
export const RECIEVE_KEYS = 'RECIEVE_KEYS';
|
||||||
export const ERROR_FETCH_KEYS = 'ERROR_FETCH_KEYS';
|
export const ERROR_FETCH_KEYS = 'ERROR_FETCH_KEYS';
|
||||||
export const REMOVE_KEY = 'REMOVE_KEY';
|
export const REMOVE_KEY = 'REMOVE_KEY';
|
||||||
@ -20,7 +20,7 @@ export function fetchApiKeys() {
|
|||||||
tokens: value.tokens,
|
tokens: value.tokens,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_KEYS));
|
.catch(dispatchError(dispatch, ERROR_FETCH_KEYS));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeKey(secret) {
|
export function removeKey(secret) {
|
||||||
@ -28,7 +28,7 @@ export function removeKey(secret) {
|
|||||||
api
|
api
|
||||||
.remove(secret)
|
.remove(secret)
|
||||||
.then(() => dispatch({ type: REMOVE_KEY, secret }))
|
.then(() => dispatch({ type: REMOVE_KEY, secret }))
|
||||||
.catch(dispatchAndThrow(dispatch, REMOVE_KEY));
|
.catch(dispatchError(dispatch, REMOVE_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addKey(data) {
|
export function addKey(data) {
|
||||||
@ -36,5 +36,5 @@ export function addKey(data) {
|
|||||||
api
|
api
|
||||||
.create(data)
|
.create(data)
|
||||||
.then(newToken => dispatch({ type: ADD_KEY, token: newToken }))
|
.then(newToken => dispatch({ type: ADD_KEY, token: newToken }))
|
||||||
.catch(dispatchAndThrow(dispatch, ADD_KEY_ERROR));
|
.catch(dispatchError(dispatch, ADD_KEY_ERROR));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
export const START_FETCH_USERS = 'START_FETCH_USERS';
|
export const START_FETCH_USERS = 'START_FETCH_USERS';
|
||||||
export const RECIEVE_USERS = 'RECIEVE_USERS';
|
export const RECIEVE_USERS = 'RECIEVE_USERS';
|
||||||
export const ERROR_FETCH_USERS = 'ERROR_FETCH_USERS';
|
export const ERROR_FETCH_USERS = 'ERROR_FETCH_USERS';
|
||||||
@ -27,7 +27,7 @@ export function fetchUsers() {
|
|||||||
return api
|
return api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(gotUsers(json)))
|
.then(json => dispatch(gotUsers(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_USERS));
|
.catch(dispatchError(dispatch, ERROR_FETCH_USERS));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export function removeUser(user) {
|
|||||||
api
|
api
|
||||||
.remove(user)
|
.remove(user)
|
||||||
.then(() => dispatch({ type: REMOVE_USER, user }))
|
.then(() => dispatch({ type: REMOVE_USER, user }))
|
||||||
.catch(dispatchAndThrow(dispatch, REMOVE_USER_ERROR));
|
.catch(dispatchError(dispatch, REMOVE_USER_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addUser(user) {
|
export function addUser(user) {
|
||||||
@ -44,7 +44,7 @@ export function addUser(user) {
|
|||||||
api
|
api
|
||||||
.create(user)
|
.create(user)
|
||||||
.then(newUser => dispatch({ type: ADD_USER, user: newUser }))
|
.then(newUser => dispatch({ type: ADD_USER, user: newUser }))
|
||||||
.catch(dispatchAndThrow(dispatch, ADD_USER_ERROR));
|
.catch(dispatchError(dispatch, ADD_USER_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUser(user) {
|
export function updateUser(user) {
|
||||||
@ -52,13 +52,13 @@ export function updateUser(user) {
|
|||||||
api
|
api
|
||||||
.update(user)
|
.update(user)
|
||||||
.then(newUser => dispatch({ type: UPDATE_USER, user: newUser }))
|
.then(newUser => dispatch({ type: UPDATE_USER, user: newUser }))
|
||||||
.catch(dispatchAndThrow(dispatch, UPDATE_USER_ERROR));
|
.catch(dispatchError(dispatch, UPDATE_USER_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changePassword(user, newPassword) {
|
export function changePassword(user, newPassword) {
|
||||||
return dispatch => api.changePassword(user, newPassword).catch(dispatchAndThrow(dispatch, CHANGE_PASSWORD_ERROR));
|
return dispatch => api.changePassword(user, newPassword).catch(dispatchError(dispatch, CHANGE_PASSWORD_ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validatePassword(password) {
|
export function validatePassword(password) {
|
||||||
return dispatch => api.validatePassword(password).catch(dispatchAndThrow(dispatch, VALIDATE_PASSWORD_ERROR));
|
return dispatch => api.validatePassword(password).catch(dispatchError(dispatch, VALIDATE_PASSWORD_ERROR));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const TAG_FEATURE_TOGGLE = 'TAG_FEATURE_TOGGLE';
|
export const TAG_FEATURE_TOGGLE = 'TAG_FEATURE_TOGGLE';
|
||||||
export const UNTAG_FEATURE_TOGGLE = 'UNTAG_FEATURE_TOGGLE';
|
export const UNTAG_FEATURE_TOGGLE = 'UNTAG_FEATURE_TOGGLE';
|
||||||
@ -25,7 +25,7 @@ export function tagFeature(featureToggle, tag) {
|
|||||||
return api
|
return api
|
||||||
.tagFeature(featureToggle, tag)
|
.tagFeature(featureToggle, tag)
|
||||||
.then(json => dispatch({ type: TAG_FEATURE_TOGGLE, featureToggle, tag: json }))
|
.then(json => dispatch({ type: TAG_FEATURE_TOGGLE, featureToggle, tag: json }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_TAG_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_TAG_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export function untagFeature(featureToggle, tag) {
|
|||||||
return api
|
return api
|
||||||
.untagFeature(featureToggle, tag)
|
.untagFeature(featureToggle, tag)
|
||||||
.then(() => dispatch({ type: UNTAG_FEATURE_TOGGLE, featureToggle, tag }))
|
.then(() => dispatch({ type: UNTAG_FEATURE_TOGGLE, featureToggle, tag }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UNTAG_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UNTAG_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +45,6 @@ export function fetchTags(featureToggle) {
|
|||||||
return api
|
return api
|
||||||
.fetchFeatureToggleTags(featureToggle)
|
.fetchFeatureToggleTags(featureToggle)
|
||||||
.then(json => dispatch(receiveFeatureToggleTags(json)))
|
.then(json => dispatch(receiveFeatureToggleTags(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLE_TAGS));
|
.catch(dispatchError(dispatch, ERROR_FETCH_FEATURE_TOGGLE_TAGS));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
const debug = require('debug')('unleash:feature-actions');
|
import { dispatchError } from '../util';
|
||||||
import { dispatchAndThrow } from '../util';
|
|
||||||
import { MUTE_ERROR } from '../error/actions';
|
import { MUTE_ERROR } from '../error/actions';
|
||||||
|
const debug = require('debug')('unleash:feature-actions');
|
||||||
|
|
||||||
export const ADD_FEATURE_TOGGLE = 'ADD_FEATURE_TOGGLE';
|
export const ADD_FEATURE_TOGGLE = 'ADD_FEATURE_TOGGLE';
|
||||||
export const COPY_FEATURE_TOGGLE = 'COPY_FEATURE_TOGGLE';
|
export const COPY_FEATURE_TOGGLE = 'COPY_FEATURE_TOGGLE';
|
||||||
@ -77,7 +77,7 @@ export function fetchFeatureToggles() {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
dispatch({ type: FETCH_FEATURE_TOGGLE_ERROR });
|
dispatch({ type: FETCH_FEATURE_TOGGLE_ERROR });
|
||||||
dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLES);
|
dispatchError(dispatch, ERROR_FETCH_FEATURE_TOGGLES);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ export function fetchFeatureToggle(name) {
|
|||||||
return api
|
return api
|
||||||
.fetchFeatureToggle(name)
|
.fetchFeatureToggle(name)
|
||||||
.then(json => dispatch(receiveFeatureToggle(json)))
|
.then(json => dispatch(receiveFeatureToggle(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_FETCH_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ export function createFeatureToggles(featureToggle) {
|
|||||||
featureToggle: createdFeature,
|
featureToggle: createdFeature,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_CREATING_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_CREATING_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ export function requestToggleFeatureToggle(enable, name) {
|
|||||||
return api
|
return api
|
||||||
.toggle(enable, name)
|
.toggle(enable, name)
|
||||||
.then(() => dispatch({ type: TOGGLE_FEATURE_TOGGLE, name }))
|
.then(() => dispatch({ type: TOGGLE_FEATURE_TOGGLE, name }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ export function requestSetStaleFeatureToggle(stale, name) {
|
|||||||
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
||||||
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
|
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ export function requestUpdateFeatureToggle(featureToggle) {
|
|||||||
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
||||||
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
|
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info });
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ export function requestUpdateFeatureToggleStrategies(featureToggle, newStrategie
|
|||||||
info,
|
info,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ export function requestUpdateFeatureToggleVariants(featureToggle, newVariants) {
|
|||||||
info,
|
info,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ export function removeFeatureToggle(featureToggleName) {
|
|||||||
return api
|
return api
|
||||||
.remove(featureToggleName)
|
.remove(featureToggleName)
|
||||||
.then(() => dispatch({ type: REMOVE_FEATURE_TOGGLE, featureToggleName }))
|
.then(() => dispatch({ type: REMOVE_FEATURE_TOGGLE, featureToggleName }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVE_FEATURE_TOGGLE));
|
.catch(dispatchError(dispatch, ERROR_REMOVE_FEATURE_TOGGLE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { List, Map as $Map } from 'immutable';
|
import { List, Map as $Map } from 'immutable';
|
||||||
const debug = require('debug')('unleash:feature-store');
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ADD_FEATURE_TOGGLE,
|
ADD_FEATURE_TOGGLE,
|
||||||
RECEIVE_FEATURE_TOGGLES,
|
RECEIVE_FEATURE_TOGGLES,
|
||||||
@ -13,6 +11,8 @@ import {
|
|||||||
|
|
||||||
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
|
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
|
||||||
|
|
||||||
|
const debug = require('debug')('unleash:feature-store');
|
||||||
|
|
||||||
const features = (state = new List([]), action) => {
|
const features = (state = new List([]), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADD_FEATURE_TOGGLE:
|
case ADD_FEATURE_TOGGLE:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_FEATURE_TYPES = 'RECEIVE_FEATURE_TYPES';
|
export const RECEIVE_FEATURE_TYPES = 'RECEIVE_FEATURE_TYPES';
|
||||||
export const ERROR_RECEIVE_FEATURE_TYPES = 'ERROR_RECEIVE_FEATURE_TYPES';
|
export const ERROR_RECEIVE_FEATURE_TYPES = 'ERROR_RECEIVE_FEATURE_TYPES';
|
||||||
@ -11,5 +11,5 @@ export function fetchFeatureTypes() {
|
|||||||
api
|
api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(receiveFeatureTypes(json)))
|
.then(json => dispatch(receiveFeatureTypes(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_FEATURE_TYPES));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_FEATURE_TYPES));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
||||||
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
||||||
@ -21,7 +21,7 @@ export function fetchHistory() {
|
|||||||
api
|
api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(receiveHistory(json)))
|
.then(json => dispatch(receiveHistory(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_HISTORY));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_HISTORY));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchHistoryForToggle(toggleName) {
|
export function fetchHistoryForToggle(toggleName) {
|
||||||
@ -29,5 +29,5 @@ export function fetchHistoryForToggle(toggleName) {
|
|||||||
api
|
api
|
||||||
.fetchHistoryForToggle(toggleName)
|
.fetchHistoryForToggle(toggleName)
|
||||||
.then(json => dispatch(receiveHistoryforToggle(json)))
|
.then(json => dispatch(receiveHistoryforToggle(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_HISTORY));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_HISTORY));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_PROJECT = 'RECEIVE_PROJECT';
|
export const RECEIVE_PROJECT = 'RECEIVE_PROJECT';
|
||||||
export const ERROR_RECEIVE_PROJECT = 'ERROR_RECEIVE_PROJECT';
|
export const ERROR_RECEIVE_PROJECT = 'ERROR_RECEIVE_PROJECT';
|
||||||
@ -22,7 +22,7 @@ export function fetchProjects() {
|
|||||||
.then(json => {
|
.then(json => {
|
||||||
dispatch(receiveProjects(json.projects));
|
dispatch(receiveProjects(json.projects));
|
||||||
})
|
})
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_PROJECT));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_PROJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeProject(project) {
|
export function removeProject(project) {
|
||||||
@ -30,7 +30,7 @@ export function removeProject(project) {
|
|||||||
api
|
api
|
||||||
.remove(project)
|
.remove(project)
|
||||||
.then(() => dispatch(delProject(project)))
|
.then(() => dispatch(delProject(project)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_PROJECT));
|
.catch(dispatchError(dispatch, ERROR_REMOVING_PROJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createProject(project) {
|
export function createProject(project) {
|
||||||
@ -38,7 +38,7 @@ export function createProject(project) {
|
|||||||
api
|
api
|
||||||
.create(project)
|
.create(project)
|
||||||
.then(() => dispatch(addProject(project)))
|
.then(() => dispatch(addProject(project)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_PROJECT));
|
.catch(dispatchError(dispatch, ERROR_ADD_PROJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProject(project) {
|
export function updateProject(project) {
|
||||||
@ -46,7 +46,7 @@ export function updateProject(project) {
|
|||||||
api
|
api
|
||||||
.update(project)
|
.update(project)
|
||||||
.then(() => dispatch(upProject(project)))
|
.then(() => dispatch(upProject(project)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_PROJECT));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_PROJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateId(id) {
|
export function validateId(id) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import applicationApi from '../application/api';
|
import applicationApi from '../application/api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const ADD_STRATEGY = 'ADD_STRATEGY';
|
export const ADD_STRATEGY = 'ADD_STRATEGY';
|
||||||
export const UPDATE_STRATEGY = 'UPDATE_STRATEGY';
|
export const UPDATE_STRATEGY = 'UPDATE_STRATEGY';
|
||||||
@ -44,7 +44,7 @@ export function fetchStrategies() {
|
|||||||
return api
|
return api
|
||||||
.fetchAll()
|
.fetchAll()
|
||||||
.then(json => dispatch(receiveStrategies(json)))
|
.then(json => dispatch(receiveStrategies(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_STRATEGIES));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_STRATEGIES));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ export function createStrategy(strategy) {
|
|||||||
return api
|
return api
|
||||||
.create(strategy)
|
.create(strategy)
|
||||||
.then(() => dispatch(addStrategy(strategy)))
|
.then(() => dispatch(addStrategy(strategy)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_CREATING_STRATEGY));
|
.catch(dispatchError(dispatch, ERROR_CREATING_STRATEGY));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ export function updateStrategy(strategy) {
|
|||||||
return api
|
return api
|
||||||
.update(strategy)
|
.update(strategy)
|
||||||
.then(() => dispatch(updatedStrategy(strategy)))
|
.then(() => dispatch(updatedStrategy(strategy)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATING_STRATEGY));
|
.catch(dispatchError(dispatch, ERROR_UPDATING_STRATEGY));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ export function removeStrategy(strategy) {
|
|||||||
api
|
api
|
||||||
.remove(strategy)
|
.remove(strategy)
|
||||||
.then(() => dispatch(createRemoveStrategy(strategy)))
|
.then(() => dispatch(createRemoveStrategy(strategy)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_STRATEGY));
|
.catch(dispatchError(dispatch, ERROR_REMOVING_STRATEGY));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getApplicationsWithStrategy(strategyName) {
|
export function getApplicationsWithStrategy(strategyName) {
|
||||||
@ -87,7 +87,7 @@ export function deprecateStrategy(strategy) {
|
|||||||
dispatch(startDeprecate());
|
dispatch(startDeprecate());
|
||||||
api.deprecate(strategy)
|
api.deprecate(strategy)
|
||||||
.then(() => dispatch(deprecateStrategyEvent(strategy)))
|
.then(() => dispatch(deprecateStrategyEvent(strategy)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_DEPRECATING_STRATEGY));
|
.catch(dispatchError(dispatch, ERROR_DEPRECATING_STRATEGY));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +96,6 @@ export function reactivateStrategy(strategy) {
|
|||||||
dispatch(startReactivate());
|
dispatch(startReactivate());
|
||||||
api.reactivate(strategy)
|
api.reactivate(strategy)
|
||||||
.then(() => dispatch(reactivateStrategyEvent(strategy)))
|
.then(() => dispatch(reactivateStrategyEvent(strategy)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_REACTIVATING_STRATEGY));
|
.catch(dispatchError(dispatch, ERROR_REACTIVATING_STRATEGY));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const START_FETCH_TAG_TYPES = 'START_FETCH_TAG_TYPES';
|
export const START_FETCH_TAG_TYPES = 'START_FETCH_TAG_TYPES';
|
||||||
export const RECEIVE_TAG_TYPES = 'RECEIVE_TAG_TYPES';
|
export const RECEIVE_TAG_TYPES = 'RECEIVE_TAG_TYPES';
|
||||||
@ -28,7 +28,7 @@ export function fetchTagTypes() {
|
|||||||
return api
|
return api
|
||||||
.fetchTagTypes()
|
.fetchTagTypes()
|
||||||
.then(json => dispatch(receiveTagTypes(json)))
|
.then(json => dispatch(receiveTagTypes(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_TAG_TYPES));
|
.catch(dispatchError(dispatch, ERROR_FETCH_TAG_TYPES));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export function createTagType({ name, description, icon }) {
|
|||||||
return api
|
return api
|
||||||
.create({ name, description, icon })
|
.create({ name, description, icon })
|
||||||
.then(() => dispatch({ type: ADD_TAG_TYPE, tagType: { name, description, icon } }))
|
.then(() => dispatch({ type: ADD_TAG_TYPE, tagType: { name, description, icon } }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_CREATE_TAG_TYPE));
|
.catch(dispatchError(dispatch, ERROR_CREATE_TAG_TYPE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ export function updateTagType({ name, description, icon }) {
|
|||||||
return api
|
return api
|
||||||
.update({ name, description, icon })
|
.update({ name, description, icon })
|
||||||
.then(() => dispatch({ type: UPDATE_TAG_TYPE, tagType: { name, description, icon } }))
|
.then(() => dispatch({ type: UPDATE_TAG_TYPE, tagType: { name, description, icon } }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_TAG_TYPE));
|
.catch(dispatchError(dispatch, ERROR_UPDATE_TAG_TYPE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export function removeTagType(name) {
|
|||||||
return api
|
return api
|
||||||
.deleteTagType(name)
|
.deleteTagType(name)
|
||||||
.then(() => dispatch({ type: DELETE_TAG_TYPE, tagType: { name } }))
|
.then(() => dispatch({ type: DELETE_TAG_TYPE, tagType: { name } }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_DELETE_TAG_TYPE));
|
.catch(dispatchError(dispatch, ERROR_DELETE_TAG_TYPE));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +47,11 @@ function deleteTagType(tagTypeName) {
|
|||||||
}).then(throwIfNotSuccess);
|
}).then(throwIfNotSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
const api = {
|
||||||
fetchTagTypes,
|
fetchTagTypes,
|
||||||
create,
|
create,
|
||||||
update,
|
update,
|
||||||
deleteTagType,
|
deleteTagType,
|
||||||
validateTagType,
|
validateTagType,
|
||||||
};
|
}
|
||||||
|
export default api;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { List, Map as $Map } from 'immutable';
|
import { List, Map as $Map } from 'immutable';
|
||||||
const debug = require('debug')('unleash:tag-type-store');
|
|
||||||
|
|
||||||
import { RECEIVE_TAG_TYPES, ADD_TAG_TYPE, DELETE_TAG_TYPE, UPDATE_TAG_TYPE, ERROR_FETCH_TAG_TYPES } from './actions';
|
import { RECEIVE_TAG_TYPES, ADD_TAG_TYPE, DELETE_TAG_TYPE, UPDATE_TAG_TYPE, ERROR_FETCH_TAG_TYPES } from './actions';
|
||||||
|
|
||||||
|
const debug = require('debug')('unleash:tag-type-store');
|
||||||
|
|
||||||
const tagTypes = (state = new List([]), action) => {
|
const tagTypes = (state = new List([]), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADD_TAG_TYPE:
|
case ADD_TAG_TYPE:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const START_FETCH_TAGS = 'START_FETCH_TAGS';
|
export const START_FETCH_TAGS = 'START_FETCH_TAGS';
|
||||||
export const RECEIVE_TAGS = 'RECEIVE_TAGS';
|
export const RECEIVE_TAGS = 'RECEIVE_TAGS';
|
||||||
@ -25,7 +25,7 @@ export function fetchTags() {
|
|||||||
return api
|
return api
|
||||||
.fetchTags()
|
.fetchTags()
|
||||||
.then(json => dispatch(receiveTags(json)))
|
.then(json => dispatch(receiveTags(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_TAGS));
|
.catch(dispatchError(dispatch, ERROR_FETCH_TAGS));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export function create({ type, value }) {
|
|||||||
return api
|
return api
|
||||||
.create({ type, value })
|
.create({ type, value })
|
||||||
.then(() => dispatch({ type: ADD_TAG, tag: { type, value } }))
|
.then(() => dispatch({ type: ADD_TAG, tag: { type, value } }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_CREATE_TAG));
|
.catch(dispatchError(dispatch, ERROR_CREATE_TAG));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +45,6 @@ export function removeTag(tag) {
|
|||||||
return api
|
return api
|
||||||
.deleteTag(tag)
|
.deleteTag(tag)
|
||||||
.then(() => dispatch({ type: DELETE_TAG, tag }))
|
.then(() => dispatch({ type: DELETE_TAG, tag }))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_DELETE_TAG));
|
.catch(dispatchError(dispatch, ERROR_DELETE_TAG));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from '../util';
|
||||||
|
|
||||||
export const RECEIVE_CONFIG = 'RECEIVE_CONFIG';
|
export const RECEIVE_CONFIG = 'RECEIVE_CONFIG';
|
||||||
export const ERROR_RECEIVE_CONFIG = 'ERROR_RECEIVE_CONFIG';
|
export const ERROR_RECEIVE_CONFIG = 'ERROR_RECEIVE_CONFIG';
|
||||||
@ -14,5 +14,5 @@ export function fetchUIConfig() {
|
|||||||
api
|
api
|
||||||
.fetchConfig()
|
.fetchConfig()
|
||||||
.then(json => dispatch(receiveConfig(json)))
|
.then(json => dispatch(receiveConfig(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_CONFIG));
|
.catch(dispatchError(dispatch, ERROR_RECEIVE_CONFIG));
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import api from './api';
|
import api from "./api";
|
||||||
import { dispatchAndThrow } from '../util';
|
import { dispatchError } from "../util";
|
||||||
export const USER_CHANGE_CURRENT = 'USER_CHANGE_CURRENT';
|
export const USER_CHANGE_CURRENT = "USER_CHANGE_CURRENT";
|
||||||
export const USER_LOGOUT = 'USER_LOGOUT';
|
export const USER_LOGOUT = "USER_LOGOUT";
|
||||||
export const USER_LOGIN = 'USER_LOGIN';
|
export const USER_LOGIN = "USER_LOGIN";
|
||||||
export const START_FETCH_USER = 'START_FETCH_USER';
|
export const START_FETCH_USER = "START_FETCH_USER";
|
||||||
export const ERROR_FETCH_USER = 'ERROR_FETCH_USER';
|
export const ERROR_FETCH_USER = "ERROR_FETCH_USER";
|
||||||
const debug = require('debug')('unleash:user-actions');
|
const debug = require("debug")("unleash:user-actions");
|
||||||
|
|
||||||
const updateUser = value => ({
|
const updateUser = (value) => ({
|
||||||
type: USER_CHANGE_CURRENT,
|
type: USER_CHANGE_CURRENT,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
@ -18,41 +18,44 @@ function handleError(error) {
|
|||||||
|
|
||||||
export function fetchUser() {
|
export function fetchUser() {
|
||||||
debug('Start fetching user');
|
debug('Start fetching user');
|
||||||
return dispatch => {
|
return (dispatch) => {
|
||||||
dispatch({ type: START_FETCH_USER });
|
dispatch({ type: START_FETCH_USER });
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.fetchUser()
|
.fetchUser()
|
||||||
.then(json => dispatch(updateUser(json)))
|
.then((json) => dispatch(updateUser(json)))
|
||||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_USER));
|
.catch(dispatchError(dispatch, ERROR_FETCH_USER));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insecureLogin(path, user) {
|
export function insecureLogin(path, user) {
|
||||||
return dispatch => {
|
return (dispatch) => {
|
||||||
dispatch({ type: START_FETCH_USER });
|
dispatch({ type: START_FETCH_USER });
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.insecureLogin(path, user)
|
.insecureLogin(path, user)
|
||||||
.then(json => dispatch(updateUser(json)))
|
.then((json) => dispatch(updateUser(json)))
|
||||||
.catch(handleError);
|
.catch(handleError);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function passwordLogin(path, user) {
|
export function passwordLogin(path, user) {
|
||||||
return dispatch => {
|
return (dispatch) => {
|
||||||
dispatch({ type: START_FETCH_USER });
|
dispatch({ type: START_FETCH_USER });
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.passwordLogin(path, user)
|
.passwordLogin(path, user)
|
||||||
.then(json => dispatch(updateUser(json)))
|
.then((json) => dispatch(updateUser(json)))
|
||||||
.then(() => dispatch({ type: USER_LOGIN }));
|
.then(() => dispatch({ type: USER_LOGIN }));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logoutUser() {
|
export function logoutUser() {
|
||||||
return dispatch => {
|
return (dispatch) => {
|
||||||
dispatch({ type: USER_LOGOUT });
|
return api
|
||||||
window.location = 'logout';
|
.logoutUser()
|
||||||
|
.then(() => dispatch({ type: USER_LOGOUT }))
|
||||||
|
.then(() => window.location = "/")
|
||||||
|
.catch(handleError);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,47 @@
|
|||||||
import { throwIfNotSuccess, headers } from '../api-helper';
|
import { throwIfNotSuccess, headers } from "../api-helper";
|
||||||
|
|
||||||
const URI = 'api/admin/user';
|
const URI = "api/admin/user";
|
||||||
|
|
||||||
function logoutUser() {
|
function logoutUser() {
|
||||||
return fetch(`${URI}/logout`, { method: 'GET', credentials: 'include' })
|
return fetch(`logout`, {
|
||||||
.then(throwIfNotSuccess)
|
method: "GET",
|
||||||
.then(response => response.json());
|
credentials: "include",
|
||||||
|
}).then(throwIfNotSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchUser() {
|
function fetchUser() {
|
||||||
return fetch(URI, { credentials: 'include' })
|
return fetch(URI, { credentials: "include" })
|
||||||
.then(throwIfNotSuccess)
|
.then(throwIfNotSuccess)
|
||||||
.then(response => response.json());
|
.then((response) => response.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
function insecureLogin(path, user) {
|
function insecureLogin(path, user) {
|
||||||
return fetch(path, { method: 'POST', credentials: 'include', headers, body: JSON.stringify(user) })
|
return fetch(path, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(user),
|
||||||
|
})
|
||||||
.then(throwIfNotSuccess)
|
.then(throwIfNotSuccess)
|
||||||
.then(response => response.json());
|
.then((response) => response.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
function passwordLogin(path, data) {
|
function passwordLogin(path, data) {
|
||||||
return fetch(path, {
|
return fetch(path, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
credentials: 'include',
|
credentials: "include",
|
||||||
headers,
|
headers,
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
})
|
})
|
||||||
.then(throwIfNotSuccess)
|
.then(throwIfNotSuccess)
|
||||||
.then(response => response.json());
|
.then((response) => response.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
const api = {
|
||||||
fetchUser,
|
fetchUser,
|
||||||
insecureLogin,
|
insecureLogin,
|
||||||
logoutUser,
|
logoutUser,
|
||||||
passwordLogin,
|
passwordLogin,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
|
@ -14,6 +14,7 @@ const userStore = (state = new $Map(), action) => {
|
|||||||
state = state.set('authDetails', action.error.body).set('showDialog', true);
|
state = state.set('authDetails', action.error.body).set('showDialog', true);
|
||||||
return state;
|
return state;
|
||||||
case USER_LOGOUT:
|
case USER_LOGOUT:
|
||||||
|
console.log("Resetting state due to logout");
|
||||||
return new $Map();
|
return new $Map();
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export const AUTH_REQUIRED = 'AUTH_REQUIRED';
|
export const AUTH_REQUIRED = 'AUTH_REQUIRED';
|
||||||
export const FORBIDDEN = 'FORBIDDEN';
|
export const FORBIDDEN = 'FORBIDDEN';
|
||||||
|
|
||||||
export function dispatchAndThrow(dispatch, type) {
|
export function dispatchError(dispatch, type) {
|
||||||
return error => {
|
return error => {
|
||||||
switch (error.statusCode) {
|
switch (error.statusCode) {
|
||||||
case 401:
|
case 401:
|
||||||
@ -14,7 +14,6 @@ export function dispatchAndThrow(dispatch, type) {
|
|||||||
dispatch({ type, error, receivedAt: Date.now() });
|
dispatch({ type, error, receivedAt: Date.now() });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
throw error;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
frontend/tsconfig.json
Normal file
26
frontend/tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
@ -1,136 +0,0 @@
|
|||||||
// docs: http://webpack.github.io/docs/configuration.html
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
|
||||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
|
||||||
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
||||||
const devMode = process.env.NODE_ENV !== 'production';
|
|
||||||
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
|
||||||
const entry = ['whatwg-fetch', './src/index'];
|
|
||||||
const plugins = [
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
// Options similar to the same options in webpackOptions.output
|
|
||||||
// both options are optional
|
|
||||||
filename: 'bundle.css',
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
|
||||||
new CleanWebpackPlugin(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (devMode) {
|
|
||||||
entry.push('webpack-dev-server/client?http://localhost:3000');
|
|
||||||
entry.push('webpack/hot/only-dev-server');
|
|
||||||
plugins.push(new webpack.HotModuleReplacementPlugin());
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode,
|
|
||||||
entry,
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.scss', '.css', '.js', '.jsx', '.json'],
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, 'dist/public'),
|
|
||||||
filename: 'bundle.js',
|
|
||||||
publicPath: '/static/',
|
|
||||||
},
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
minimizer: [
|
|
||||||
new UglifyJsPlugin({
|
|
||||||
uglifyOptions: {
|
|
||||||
output: {
|
|
||||||
comments: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new OptimizeCssAssetsPlugin({
|
|
||||||
cssProcessor: require('cssnano'),
|
|
||||||
cssProcessorOptions: { discardComments: { removeAll: true } },
|
|
||||||
canPrint: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
include: path.join(__dirname, 'src'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /(\.scss)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
modules: true,
|
|
||||||
importLoaders: 1,
|
|
||||||
localIdentName: '[name]__[local]___[hash:base64:5]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
// data: '@import "theme/_config.scss";',
|
|
||||||
includePaths: [path.resolve(__dirname, './src')],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /(\.css)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
|
|
||||||
},
|
|
||||||
{ loader: 'css-loader' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins,
|
|
||||||
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
proxy: {
|
|
||||||
'/api': {
|
|
||||||
target: process.env.UNLEASH_API || 'http://localhost:4242',
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
},
|
|
||||||
'/logout': {
|
|
||||||
target: process.env.UNLEASH_API || 'http://localhost:4242',
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
},
|
|
||||||
'/auth': {
|
|
||||||
target: process.env.UNLEASH_API || 'http://localhost:4242',
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
port: process.env.PORT || 3000,
|
|
||||||
host: '0.0.0.0',
|
|
||||||
disableHostCheck: true,
|
|
||||||
},
|
|
||||||
};
|
|
8352
frontend/yarn.lock
8352
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user