mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01: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:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- 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
|
||||
dist
|
||||
build
|
||||
|
||||
# IDE
|
||||
.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');
|
||||
|
||||
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",
|
||||
"description": "unleash your features",
|
||||
"version": "4.0.0-alpha.1",
|
||||
"version": "3.15.1",
|
||||
"keywords": [
|
||||
"unleash",
|
||||
"feature toggle",
|
||||
@ -10,7 +10,7 @@
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"dist/"
|
||||
"build/"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -20,106 +20,93 @@
|
||||
"url": "https://github.com/Unleash/unleash-frontend"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "npm run build:assets && npm run build:html && npm run build:img && npm run build:ico",
|
||||
"build:assets": "NODE_ENV=production webpack -p --display-optimization-bailout",
|
||||
"build:html": "cp public/*.html dist/.",
|
||||
"build:ico": "cp public/*.ico dist/.",
|
||||
"build:img": "cp public/*.png dist/public/. && cp public/*.svg dist/public/.",
|
||||
"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"
|
||||
"build": "react-scripts build",
|
||||
"start": "react-scripts start",
|
||||
"start:heroku": "UNLEASH_API=https://unleash.herokuapp.com yarn run start",
|
||||
"test": "react-scripts test",
|
||||
"prepublish": "yarn run build"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/styles": "^4.11.3",
|
||||
"array-move": "^2.2.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^25.3.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"css-loader": "^2.1.1",
|
||||
"date-fns": "^2.17.0",
|
||||
"debounce": "^1.2.0",
|
||||
"debug": "^4.1.1",
|
||||
"enzyme": "^3.9.0",
|
||||
"enzyme-adapter-react-16": "^1.11.0",
|
||||
"enzyme-to-json": "^3.3.5",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-finn": "^3.0.1",
|
||||
"eslint-config-finn-prettier": "^3.0.2",
|
||||
"eslint-config-finn-react": "^2.0.2",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"@types/enzyme": "^3.10.8",
|
||||
"@types/enzyme-adapter-react-16": "^1.0.6",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"array-move": "^3.0.1",
|
||||
"classnames": "^2.3.1",
|
||||
"css-loader": "^5.2.0",
|
||||
"date-fns": "^2.19.0",
|
||||
"debounce": "^1.2.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.6",
|
||||
"fetch-mock": "^9.11.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"immutable": "^3.8.1",
|
||||
"jest": "^26.6.3",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.flow": "^3.5.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-sass": "^4.5.3",
|
||||
"normalize.css": "^8.0.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.0",
|
||||
"prettier": "^1.18.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.14.0",
|
||||
"react-dnd": "^11.1.3",
|
||||
"react-dnd-html5-backend": "^11.1.3",
|
||||
"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",
|
||||
"react": "^17.0.2",
|
||||
"react-dnd": "^14.0.2",
|
||||
"react-dnd-html5-backend": "^14.0.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-redux": "^7.2.3",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-timeago": "^5.2.0",
|
||||
"redux": "^4.0.5",
|
||||
"redux-devtools": "^3.7.0",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"sass-loader": "^7.0.1",
|
||||
"style-loader": "^1.0.0",
|
||||
"toolbox-loader": "0.0.3",
|
||||
"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"
|
||||
"sass": "^1.32.8",
|
||||
"typescript": "^4.2.3",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"jest": {
|
||||
"moduleNameMapper": {
|
||||
"\\.(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"
|
||||
},
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/src/setupTests.js"
|
||||
],
|
||||
"setupFiles": [
|
||||
"<rootDir>/jest-setup.js"
|
||||
],
|
||||
"snapshotSerializers": [
|
||||
"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">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="unleash">
|
||||
|
||||
<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/css?family=Roboto:300,400,500,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id='app'></div>
|
||||
<script src="public/bundle.js"></script>
|
||||
</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(() => {
|
||||
fetchFeatureToggles();
|
||||
setSelectedProject(projects[0].id);
|
||||
}, []);
|
||||
}, [fetchFeatureToggles, projects]);
|
||||
|
||||
useEffect(() => {
|
||||
setProjectOptions(formatProjectOptions(projects));
|
||||
@ -43,7 +43,7 @@ const Reporting = ({ fetchFeatureToggles, projects }) => {
|
||||
options={projectOptions}
|
||||
value={selectedProject}
|
||||
onChange={onChange}
|
||||
inputProps={{ ['data-test']: REPORTING_SELECT_ID }}
|
||||
inputProps={{ ['data-testid']: REPORTING_SELECT_ID }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -3,7 +3,8 @@ import { Provider } from 'react-redux';
|
||||
import { HashRouter } from 'react-router-dom';
|
||||
|
||||
import { createStore } from 'redux';
|
||||
import { mount } from 'enzyme/build';
|
||||
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
|
||||
import Reporting from '../Reporting';
|
||||
import { REPORTING_SELECT_ID } from '../../../testIds';
|
||||
@ -16,8 +17,8 @@ const mockStore = {
|
||||
};
|
||||
const mockReducer = state => state;
|
||||
|
||||
test('changing projects renders only toggles from that project', () => {
|
||||
const wrapper = mount(
|
||||
test('changing projects renders only toggles from that project', async () => {
|
||||
render(
|
||||
<HashRouter>
|
||||
<Provider store={createStore(mockReducer, mockStore)}>
|
||||
<Reporting projects={testProjects} features={testFeatures} fetchFeatureToggles={() => {}} />
|
||||
@ -25,14 +26,9 @@ test('changing projects renders only toggles from that project', () => {
|
||||
</HashRouter>
|
||||
);
|
||||
|
||||
const select = wrapper.find(`input[data-test="${REPORTING_SELECT_ID}"][value="default"]`).first();
|
||||
|
||||
let list = wrapper.find('tr');
|
||||
const table = await screen.findByRole("table");
|
||||
/* Length of projects belonging to project (3) + header row (1) */
|
||||
expect(list.length).toBe(4);
|
||||
|
||||
select.simulate('change', { target: { value: 'myProject' } });
|
||||
list = wrapper.find('tr');
|
||||
|
||||
expect(list.length).toBe(3);
|
||||
expect(table.rows).toHaveLength(4);
|
||||
fireEvent.change(await screen.findByTestId(REPORTING_SELECT_ID), { target: { value: 'myProject'}});
|
||||
expect(table.rows).toHaveLength(3);
|
||||
});
|
||||
|
@ -15,11 +15,11 @@ const style = {
|
||||
const getIcon = name => {
|
||||
switch (name) {
|
||||
case 'slack':
|
||||
return <img style={style} src="public/slack.svg" />;
|
||||
return <img style={style} alt="Slack Logo" src="slack.svg" />;
|
||||
case 'jira-comment':
|
||||
return <img style={style} src="public/jira.svg" />;
|
||||
return <img style={style} alt="JIRA Logo" src="jira.svg" />;
|
||||
case 'webhook':
|
||||
return <img style={style} src="public/webhooks.svg" />;
|
||||
return <img style={style} alt="Generic Webhook logo" src="webhooks.svg" />;
|
||||
default:
|
||||
return (
|
||||
<Avatar>
|
||||
@ -34,7 +34,8 @@ const AddonList = ({ addons, providers, fetchAddons, removeAddon, toggleAddon, h
|
||||
if (addons.length === 0) {
|
||||
fetchAddons();
|
||||
}
|
||||
}, []);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [addons.length]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -22,17 +22,17 @@ const AddonFormComponent = ({ editMode, provider, addon, fetch, cancel, submit }
|
||||
if (!provider) {
|
||||
fetch();
|
||||
}
|
||||
}, []); // empty array => fetch only first time
|
||||
}, [fetch, provider]); // empty array => fetch only first time
|
||||
|
||||
useEffect(() => {
|
||||
setConfig({ ...addon });
|
||||
}, [addon.id]);
|
||||
}, [addon]);
|
||||
|
||||
useEffect(() => {
|
||||
if (provider && !config.provider) {
|
||||
setConfig({ ...addon, provider: provider.name });
|
||||
}
|
||||
}, [provider]);
|
||||
}, [provider, addon, config.provider]);
|
||||
|
||||
const setFieldValue = field => evt => {
|
||||
evt.preventDefault();
|
||||
@ -104,7 +104,7 @@ const AddonFormComponent = ({ editMode, provider, addon, fetch, cancel, submit }
|
||||
<PageContent headerContent={`Configure ${name} addon`}>
|
||||
<section className={styles.formSection}>
|
||||
{description}
|
||||
<a href={documentationUrl} target="_blank">
|
||||
<a href={documentationUrl} target="_blank" rel="noreferrer">
|
||||
Read more
|
||||
</a>
|
||||
<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 React, { useRef } from 'react';
|
||||
|
||||
const RNDContext = createDndContext(HTML5Backend);
|
||||
import React from 'react';
|
||||
|
||||
function useDNDProviderElement(props) {
|
||||
const manager = useRef(RNDContext);
|
||||
|
||||
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) {
|
||||
|
@ -108,7 +108,7 @@ export function getIcon(type) {
|
||||
}
|
||||
|
||||
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>
|
||||
</a>
|
||||
);
|
||||
|
@ -188,6 +188,7 @@ class AddContextComponent extends Component {
|
||||
<a
|
||||
href="https://unleash.github.io/docs/activation_strategy#flexiblerollout"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
|
@ -5,6 +5,8 @@ import { MenuItem } from '@material-ui/core';
|
||||
import { MenuItemWithIcon } from '../../../common';
|
||||
import DropdownMenu from '../../../common/dropdown-menu';
|
||||
import ProjectSelect from '../../../common/ProjectSelect';
|
||||
import { useStyles } from './styles';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const sortingOptions = [
|
||||
{ type: 'name', displayName: 'Name' },
|
||||
@ -17,8 +19,6 @@ const sortingOptions = [
|
||||
{ type: 'metrics', displayName: 'Metrics' },
|
||||
];
|
||||
|
||||
import { useStyles } from './styles';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const FeatureToggleListActions = ({ settings, setSort, toggleMetrics, updateSetting, loading }) => {
|
||||
const styles = useStyles();
|
||||
|
@ -52,6 +52,7 @@ const FeatureView = ({
|
||||
useEffect(() => {
|
||||
scrollToTop();
|
||||
fetchTags(featureToggleName);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@ -62,6 +63,7 @@ const FeatureView = ({
|
||||
fetchArchive();
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [features]);
|
||||
|
||||
const getTabComponent = key => {
|
||||
@ -91,6 +93,8 @@ const FeatureView = ({
|
||||
);
|
||||
case 'log':
|
||||
return <HistoryComponent toggleName={featureToggleName} />;
|
||||
default:
|
||||
return null
|
||||
}
|
||||
};
|
||||
const getTabData = () => [
|
||||
|
@ -103,7 +103,6 @@ class CopyFeatureComponent extends Component {
|
||||
label="Feature toggle name"
|
||||
name="name"
|
||||
value={newToggleName}
|
||||
error={nameError}
|
||||
onBlur={this.onValidateName}
|
||||
onChange={this.setValue}
|
||||
error={nameError !== undefined}
|
||||
|
@ -20,11 +20,11 @@ function FeatureTagComponent({ tags, tagTypes, featureToggleName, untagFeature }
|
||||
if (tagType && tagType.icon) {
|
||||
switch (tagType.name) {
|
||||
case 'slack':
|
||||
return <img style={style} alt="slack" src="public/slack.svg" />;
|
||||
return <img style={style} alt="slack" src="slack.svg" />;
|
||||
case 'jira':
|
||||
return <img style={style} alt="jira" src="public/jira.svg" />;
|
||||
return <img style={style} alt="jira" src="jira.svg" />;
|
||||
case 'webhook':
|
||||
return <img style={style} alt="webhook" src="public/webhooks.svg" />;
|
||||
return <img style={style} alt="webhook" src="webhooks.svg" />;
|
||||
default:
|
||||
return <Icon>label</Icon>;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export default function GeneralStrategyInput({ parameters, strategyDefinition, u
|
||||
maxLabel="on"
|
||||
/>
|
||||
{description && (
|
||||
<p className={styles.helpText} className={styles.helperText}>
|
||||
<p className={styles.helpText}>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
@ -67,6 +67,8 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
||||
show={<StrategyCardField title={paramDefinition.name} value={param} />}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,7 @@ const StrategiesList = props => {
|
||||
if (!editStrategyIndex) {
|
||||
updateEditableStrategies(cloneDeep(props.configuredStrategies));
|
||||
}
|
||||
}, [props.configuredStrategies]);
|
||||
}, [props.configuredStrategies, editStrategyIndex]);
|
||||
|
||||
const updateStrategy = index => strategy => {
|
||||
const newStrategy = { ...strategy };
|
||||
|
@ -499,6 +499,7 @@ exports[`renders correctly with with variants 1`] = `
|
||||
|
||||
<a
|
||||
href="https://unleash.github.io/docs/toggle_variants"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Read more
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
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 MySelect from '../../common/select';
|
||||
import { trim, modalStyles } from '../../common/util';
|
||||
import { modalStyles, trim } from '../../common/util';
|
||||
import { weightTypes } from './enums';
|
||||
import OverrideConfig from './e-override-config';
|
||||
|
||||
@ -46,6 +46,7 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
|
||||
|
||||
useEffect(() => {
|
||||
clear();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [editVariant]);
|
||||
|
||||
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
|
||||
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
|
||||
</a>
|
||||
</small>
|
||||
|
@ -33,7 +33,7 @@ export const Footer = () => (
|
||||
<ListItem key="github_link" className={styles.listItem}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<a href="https://github.com/Unleash/unleash/" target="_blank">
|
||||
<a href="https://github.com/Unleash/unleash/" target="_blank" rel="noreferrer">
|
||||
GitHub
|
||||
</a>
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ const Header = ({ uiConfig, init }) => {
|
||||
|
||||
useEffect(() => {
|
||||
init(uiConfig.flags);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { loadInitialData } from '../../../store/loader';
|
||||
|
||||
const mapStateToProps = state => ({ uiConfig: state.uiConfig.toJS() });
|
||||
|
||||
import Header from './Header';
|
||||
|
||||
const mapStateToProps = state => ({ uiConfig: state.uiConfig.toJS() });
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
init: loadInitialData,
|
||||
})(Header);
|
||||
|
@ -43,7 +43,7 @@ function renderLink(link, toggleDrawer) {
|
||||
key={link.href}
|
||||
target="_blank"
|
||||
className={[styles.navigationLink].join(' ')}
|
||||
title={link.title}
|
||||
title={link.title} rel="noreferrer"
|
||||
>
|
||||
{getIcon(link.icon)} {link.value}
|
||||
</a>
|
||||
@ -56,7 +56,7 @@ export const DrawerMenu = ({ links = [], title = 'Unleash', flags = {}, open = f
|
||||
<div className={styles.drawerContainer}>
|
||||
<div className={styles.drawerTitleContainer}>
|
||||
<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>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@ const ProjectList = ({ projects, fetchProjects, removeProject, history, hasPermi
|
||||
const styles = useStyles();
|
||||
useEffect(() => {
|
||||
fetchProjects();
|
||||
}, []);
|
||||
}, [fetchProjects]);
|
||||
|
||||
const addProjectButton = () => (
|
||||
<ConditionallyRender
|
||||
|
@ -1,24 +1,24 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
CardHeader,
|
||||
Avatar,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
ListItemAvatar,
|
||||
Select,
|
||||
MenuItem,
|
||||
Icon,
|
||||
IconButton,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogTitle,
|
||||
DialogContentText,
|
||||
DialogContent,
|
||||
Button,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Icon,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Select,
|
||||
} from '@material-ui/core';
|
||||
|
||||
import AddUserComponent from './access-add-user';
|
||||
@ -38,6 +38,7 @@ function AccessComponent({ projectId, project }) {
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccess();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [projectId]);
|
||||
|
||||
if (!project) {
|
||||
|
@ -27,6 +27,7 @@ const StrategiesList = ({
|
||||
|
||||
useEffect(() => {
|
||||
fetchStrategies();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const headerButton = () => (
|
||||
|
@ -29,6 +29,7 @@ const TagTypeList = ({ tagTypes, fetchTagTypes, removeTagType, hasPermission })
|
||||
|
||||
useEffect(() => {
|
||||
fetchTagTypes();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
let header = (
|
||||
|
@ -18,6 +18,7 @@ const TagList = ({ tags, fetchTags, removeTag, hasPermission }) => {
|
||||
|
||||
useEffect(() => {
|
||||
fetchTags();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const remove = (tag, evt) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
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 { useHistory } from 'react-router';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
@ -121,9 +121,9 @@ const PasswordAuth = ({ authDetails, passwordLogin, loadInitialData }) => {
|
||||
condition={showFields}
|
||||
show={renderLoginForm()}
|
||||
elseShow={
|
||||
<a href="" onClick={onShowOptions}>
|
||||
<IconButton> onClick={onShowOptions}>
|
||||
Show more options
|
||||
</a>
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
@ -29,7 +29,7 @@ const SimpleAuth = ({ insecureLogin, loadInitialData, history, authDetails }) =>
|
||||
<p>
|
||||
This instance of Unleash is not set up with a secure authentication provider. You can read more
|
||||
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
|
||||
</a>
|
||||
</p>
|
||||
|
@ -1,25 +1,24 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, CardContent, CardHeader } from '@material-ui/core';
|
||||
import { styles as commonStyles } from '../common';
|
||||
|
||||
export default class FeatureListComponent extends React.Component {
|
||||
static propTypes = {
|
||||
logoutUser: PropTypes.func.isRequired,
|
||||
};
|
||||
const LogoutComponent = ({logoutUser}) => {
|
||||
useEffect(() => {
|
||||
logoutUser();
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
this.props.logoutUser();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card shadow={0} className={commonStyles.fullwidth}>
|
||||
<CardHeader>Logged out</CardHeader>
|
||||
<CardContent>
|
||||
You have now been successfully logged out of Unleash. Thank you for using Unleash.{' '}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
return (<Card shadow={0} className={commonStyles.fullwidth}>
|
||||
<CardHeader>Logged out</CardHeader>
|
||||
<CardContent>
|
||||
You have now been successfully logged out of Unleash. Thank you for using Unleash.{' '}
|
||||
</CardContent>
|
||||
</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 locale = this.getLocale();
|
||||
let foundLocale = this.possibleLocales.find(l => l.value === locale);
|
||||
const imageUrl = email ? this.props.profile.imageUrl : 'public/unknown-user.png';
|
||||
const imageLocale = foundLocale ? `public/${foundLocale.image}.png` : `public/unknown-locale.png`;
|
||||
const imageUrl = email ? this.props.profile.imageUrl : 'unknown-user.png';
|
||||
const imageLocale = foundLocale ? `${foundLocale.image}.png` : `unknown-locale.png`;
|
||||
return (
|
||||
<div className={styles.showUserSettings}>
|
||||
<DropdownMenu
|
||||
@ -60,7 +60,7 @@ export default class ShowUserComponent extends React.Component {
|
||||
this.possibleLocales.map(i => (
|
||||
<MenuItem key={i.value} onClick={() => this.setLocale(i)}>
|
||||
<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>
|
||||
</div>
|
||||
</MenuItem>
|
||||
|
@ -18,10 +18,11 @@ import App from './component/app';
|
||||
import ScrollToTop from './component/scroll-to-top';
|
||||
import { writeWarning } from './security-logger';
|
||||
|
||||
|
||||
let composeEnhancers;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
||||
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||
if (process.env.NODE_ENV !== 'production' && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
||||
composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||
} else {
|
||||
composeEnhancers = compose;
|
||||
writeWarning();
|
@ -12,7 +12,7 @@ function ApiHowTo() {
|
||||
}}
|
||||
>
|
||||
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
|
||||
</a>{' '}
|
||||
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(() => {
|
||||
fetchApiKeys();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon } from '@material-ui/core';
|
||||
import { Icon, IconButton } from '@material-ui/core';
|
||||
|
||||
function Secret({ value }) {
|
||||
const [show, setShow] = useState(false);
|
||||
@ -17,9 +17,9 @@ function Secret({ value }) {
|
||||
<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>
|
||||
</a>
|
||||
</IconButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ function GoogleAuth({ config, getGoogleConfig, updateGoogleConfig, hasPermission
|
||||
|
||||
useEffect(() => {
|
||||
getGoogleConfig();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@ -59,7 +60,7 @@ function GoogleAuth({ config, getGoogleConfig, updateGoogleConfig, hasPermission
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1">
|
||||
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
|
||||
</a>{' '}
|
||||
to learn how to integrate with Google OAuth 2.0. <br />
|
||||
|
@ -15,12 +15,14 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, hasPermission }) {
|
||||
|
||||
useEffect(() => {
|
||||
getSamlConfig();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (config.entityId) {
|
||||
setData(config);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [config]);
|
||||
|
||||
if (!hasPermission('ADMIN')) {
|
||||
@ -59,7 +61,7 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, hasPermission }) {
|
||||
<Grid item md={12}>
|
||||
<Typography variant="subtitle1">
|
||||
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
|
||||
</a>{' '}
|
||||
to learn how to integrate with specific SAML 2.0 providers (Okta, Keycloak, etc). <br />
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-alert */
|
||||
import React, { useEffect, useState } from 'react';
|
||||
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 AddUser from '../add-user-component';
|
||||
import ChangePassword from '../change-password-component';
|
||||
@ -65,6 +65,7 @@ function UsersList({
|
||||
|
||||
useEffect(() => {
|
||||
fetchUsers();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -92,22 +93,22 @@ function UsersList({
|
||||
condition={hasPermission('ADMIN')}
|
||||
show={
|
||||
<TableCell>
|
||||
<a href="" title="Edit" onClick={openUpdateDialog(item)}>
|
||||
<IconButton aria-label="Edit" title="Edit" onClick={openUpdateDialog(item)}>
|
||||
<Icon>edit</Icon>
|
||||
</a>
|
||||
<a href="" title="Change password" onClick={openPwDialog(item)}>
|
||||
</IconButton>
|
||||
<IconButton aria-label="Change password" title="Change password" onClick={openPwDialog(item)}>
|
||||
<Icon>lock</Icon>
|
||||
</a>
|
||||
<a href="" title="Remove user" onClick={openDelDialog(item)}>
|
||||
</IconButton>
|
||||
<IconButton aria-label="Remove user" title="Remove user" onClick={openDelDialog(item)}>
|
||||
<Icon>delete</Icon>
|
||||
</a>
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
}
|
||||
elseShow={
|
||||
<TableCell>
|
||||
<a href="" title="Change password" onClick={openPwDialog(item)}>
|
||||
<IconButton aria-label="Change password" title="Change password" onClick={openPwDialog(item)}>
|
||||
<Icon>lock</Icon>
|
||||
</a>
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
}
|
||||
/>
|
||||
|
@ -13,12 +13,13 @@ import {
|
||||
import { showPermissions, modalStyles } from './util';
|
||||
|
||||
function AddUser({ user, showDialog, closeDialog, updateUser }) {
|
||||
const [data, setData] = useState(user);
|
||||
const [error, setError] = useState({});
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [data, setData] = useState(user);
|
||||
const [error, setError] = useState({});
|
||||
|
||||
const updateField = e => {
|
||||
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 Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
process.env.TZ = 'UTC';
|
||||
configure({ adapter: new Adapter() });
|
@ -1,6 +1,6 @@
|
||||
import reducer from '../index';
|
||||
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';
|
||||
|
||||
test('should be default state', () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import api from './api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_ADDON_CONFIG = 'RECEIVE_ADDON_CONFIG';
|
||||
export const ERROR_RECEIVE_ADDON_CONFIG = 'ERROR_RECEIVE_ADDON_CONFIG';
|
||||
@ -22,7 +22,7 @@ export function fetchAddons() {
|
||||
api
|
||||
.fetchAll()
|
||||
.then(success(dispatch, RECEIVE_ADDON_CONFIG))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ADDON_CONFIG));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_ADDON_CONFIG));
|
||||
}
|
||||
|
||||
export function removeAddon(addon) {
|
||||
@ -30,7 +30,7 @@ export function removeAddon(addon) {
|
||||
api
|
||||
.remove(addon)
|
||||
.then(() => dispatch(removeAddonconfig(addon)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_ADDON_CONFIG));
|
||||
.catch(dispatchError(dispatch, ERROR_REMOVING_ADDON_CONFIG));
|
||||
}
|
||||
|
||||
export function createAddon(addon) {
|
||||
@ -39,7 +39,7 @@ export function createAddon(addon) {
|
||||
.create(addon)
|
||||
.then(res => res.json())
|
||||
.then(value => dispatch(addAddonConfig(value)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_ADDON_CONFIG));
|
||||
.catch(dispatchError(dispatch, ERROR_ADD_ADDON_CONFIG));
|
||||
}
|
||||
|
||||
export function updateAddon(addon) {
|
||||
@ -47,5 +47,5 @@ export function updateAddon(addon) {
|
||||
api
|
||||
.update(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);
|
||||
}
|
||||
|
||||
export default {
|
||||
const api = {
|
||||
fetchAll,
|
||||
create,
|
||||
update,
|
||||
remove,
|
||||
};
|
||||
export default api;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import api from './api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
import { MUTE_ERROR } from '../error/actions';
|
||||
|
||||
export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS';
|
||||
@ -26,7 +26,7 @@ export function fetchAll() {
|
||||
api
|
||||
.fetchAll()
|
||||
.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) {
|
||||
@ -38,7 +38,7 @@ export function storeApplicationMetaData(appName, key, value) {
|
||||
setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
|
||||
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) {
|
||||
@ -46,7 +46,7 @@ export function fetchApplication(appName) {
|
||||
api
|
||||
.fetchApplication(appName)
|
||||
.then(json => dispatch(recieveApplication(json)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
|
||||
}
|
||||
|
||||
export function deleteApplication(appName) {
|
||||
@ -54,5 +54,5 @@ export function deleteApplication(appName) {
|
||||
api
|
||||
.deleteApplication(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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const REVIVE_TOGGLE = 'REVIVE_TOGGLE';
|
||||
export const RECEIVE_ARCHIVE = 'RECEIVE_ARCHIVE';
|
||||
@ -20,7 +20,7 @@ export function revive(featureToggle) {
|
||||
api
|
||||
.revive(featureToggle)
|
||||
.then(() => dispatch(reviveToggle(featureToggle)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ARCHIVE));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_ARCHIVE));
|
||||
}
|
||||
|
||||
export function fetchArchive() {
|
||||
@ -28,5 +28,5 @@ export function fetchArchive() {
|
||||
api
|
||||
.fetchAll()
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_CONTEXT = '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);
|
||||
dispatch(receiveContext(json));
|
||||
})
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_CONTEXT));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_CONTEXT));
|
||||
}
|
||||
|
||||
export function removeContextField(context) {
|
||||
@ -31,7 +31,7 @@ export function removeContextField(context) {
|
||||
api
|
||||
.remove(context)
|
||||
.then(() => dispatch(createRemoveContext(context)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_CONTEXT));
|
||||
.catch(dispatchError(dispatch, ERROR_REMOVING_CONTEXT));
|
||||
}
|
||||
|
||||
export function createContextField(context) {
|
||||
@ -39,7 +39,7 @@ export function createContextField(context) {
|
||||
api
|
||||
.create(context)
|
||||
.then(() => dispatch(addContextField(context)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_CONTEXT_FIELD));
|
||||
.catch(dispatchError(dispatch, ERROR_ADD_CONTEXT_FIELD));
|
||||
}
|
||||
|
||||
export function updateContextField(context) {
|
||||
@ -47,7 +47,7 @@ export function updateContextField(context) {
|
||||
api
|
||||
.update(context)
|
||||
.then(() => dispatch(upContextField(context)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_CONTEXT_FIELD));
|
||||
.catch(dispatchError(dispatch, ERROR_UPDATE_CONTEXT_FIELD));
|
||||
}
|
||||
|
||||
export function validateName(name) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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_ERROR = 'RECIEVE_GOOGLE_CONFIG_ERROR';
|
||||
export const UPDATE_GOOGLE_AUTH = 'UPDATE_GOOGLE_AUTH';
|
||||
@ -22,7 +22,7 @@ export function getGoogleConfig() {
|
||||
config,
|
||||
})
|
||||
)
|
||||
.catch(dispatchAndThrow(dispatch, RECIEVE_GOOGLE_CONFIG_ERROR));
|
||||
.catch(dispatchError(dispatch, RECIEVE_GOOGLE_CONFIG_ERROR));
|
||||
}
|
||||
|
||||
export function updateGoogleConfig(data) {
|
||||
@ -30,7 +30,7 @@ export function updateGoogleConfig(data) {
|
||||
api
|
||||
.updateGoogleConfig(data)
|
||||
.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() {
|
||||
@ -44,7 +44,7 @@ export function getSamlConfig() {
|
||||
config,
|
||||
})
|
||||
)
|
||||
.catch(dispatchAndThrow(dispatch, RECIEVE_SAML_CONFIG_ERROR));
|
||||
.catch(dispatchError(dispatch, RECIEVE_SAML_CONFIG_ERROR));
|
||||
}
|
||||
|
||||
export function updateSamlConfig(data) {
|
||||
@ -52,5 +52,5 @@ export function updateSamlConfig(data) {
|
||||
api
|
||||
.updateSamlConfig(data)
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
export const RECIEVE_KEYS = 'RECIEVE_KEYS';
|
||||
export const ERROR_FETCH_KEYS = 'ERROR_FETCH_KEYS';
|
||||
export const REMOVE_KEY = 'REMOVE_KEY';
|
||||
@ -20,7 +20,7 @@ export function fetchApiKeys() {
|
||||
tokens: value.tokens,
|
||||
})
|
||||
)
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_KEYS));
|
||||
.catch(dispatchError(dispatch, ERROR_FETCH_KEYS));
|
||||
}
|
||||
|
||||
export function removeKey(secret) {
|
||||
@ -28,7 +28,7 @@ export function removeKey(secret) {
|
||||
api
|
||||
.remove(secret)
|
||||
.then(() => dispatch({ type: REMOVE_KEY, secret }))
|
||||
.catch(dispatchAndThrow(dispatch, REMOVE_KEY));
|
||||
.catch(dispatchError(dispatch, REMOVE_KEY));
|
||||
}
|
||||
|
||||
export function addKey(data) {
|
||||
@ -36,5 +36,5 @@ export function addKey(data) {
|
||||
api
|
||||
.create(data)
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
export const START_FETCH_USERS = 'START_FETCH_USERS';
|
||||
export const RECIEVE_USERS = 'RECIEVE_USERS';
|
||||
export const ERROR_FETCH_USERS = 'ERROR_FETCH_USERS';
|
||||
@ -27,7 +27,7 @@ export function fetchUsers() {
|
||||
return api
|
||||
.fetchAll()
|
||||
.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
|
||||
.remove(user)
|
||||
.then(() => dispatch({ type: REMOVE_USER, user }))
|
||||
.catch(dispatchAndThrow(dispatch, REMOVE_USER_ERROR));
|
||||
.catch(dispatchError(dispatch, REMOVE_USER_ERROR));
|
||||
}
|
||||
|
||||
export function addUser(user) {
|
||||
@ -44,7 +44,7 @@ export function addUser(user) {
|
||||
api
|
||||
.create(user)
|
||||
.then(newUser => dispatch({ type: ADD_USER, user: newUser }))
|
||||
.catch(dispatchAndThrow(dispatch, ADD_USER_ERROR));
|
||||
.catch(dispatchError(dispatch, ADD_USER_ERROR));
|
||||
}
|
||||
|
||||
export function updateUser(user) {
|
||||
@ -52,13 +52,13 @@ export function updateUser(user) {
|
||||
api
|
||||
.update(user)
|
||||
.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) {
|
||||
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) {
|
||||
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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const TAG_FEATURE_TOGGLE = 'TAG_FEATURE_TOGGLE';
|
||||
export const UNTAG_FEATURE_TOGGLE = 'UNTAG_FEATURE_TOGGLE';
|
||||
@ -25,7 +25,7 @@ export function tagFeature(featureToggle, tag) {
|
||||
return api
|
||||
.tagFeature(featureToggle, tag)
|
||||
.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
|
||||
.untagFeature(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
|
||||
.fetchFeatureToggleTags(featureToggle)
|
||||
.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';
|
||||
const debug = require('debug')('unleash:feature-actions');
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
import { MUTE_ERROR } from '../error/actions';
|
||||
const debug = require('debug')('unleash:feature-actions');
|
||||
|
||||
export const ADD_FEATURE_TOGGLE = 'ADD_FEATURE_TOGGLE';
|
||||
export const COPY_FEATURE_TOGGLE = 'COPY_FEATURE_TOGGLE';
|
||||
@ -77,7 +77,7 @@ export function fetchFeatureToggles() {
|
||||
})
|
||||
.catch(() => {
|
||||
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
|
||||
.fetchFeatureToggle(name)
|
||||
.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,
|
||||
});
|
||||
})
|
||||
.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
|
||||
.toggle(enable, 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);
|
||||
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);
|
||||
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,
|
||||
});
|
||||
})
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||
.catch(dispatchError(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
|
||||
};
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ export function requestUpdateFeatureToggleVariants(featureToggle, newVariants) {
|
||||
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
|
||||
.remove(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';
|
||||
const debug = require('debug')('unleash:feature-store');
|
||||
|
||||
import {
|
||||
ADD_FEATURE_TOGGLE,
|
||||
RECEIVE_FEATURE_TOGGLES,
|
||||
@ -13,6 +11,8 @@ import {
|
||||
|
||||
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
|
||||
|
||||
const debug = require('debug')('unleash:feature-store');
|
||||
|
||||
const features = (state = new List([]), action) => {
|
||||
switch (action.type) {
|
||||
case ADD_FEATURE_TOGGLE:
|
||||
|
@ -1,5 +1,5 @@
|
||||
import api from './api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_FEATURE_TYPES = 'RECEIVE_FEATURE_TYPES';
|
||||
export const ERROR_RECEIVE_FEATURE_TYPES = 'ERROR_RECEIVE_FEATURE_TYPES';
|
||||
@ -11,5 +11,5 @@ export function fetchFeatureTypes() {
|
||||
api
|
||||
.fetchAll()
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
||||
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
||||
@ -21,7 +21,7 @@ export function fetchHistory() {
|
||||
api
|
||||
.fetchAll()
|
||||
.then(json => dispatch(receiveHistory(json)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_HISTORY));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_HISTORY));
|
||||
}
|
||||
|
||||
export function fetchHistoryForToggle(toggleName) {
|
||||
@ -29,5 +29,5 @@ export function fetchHistoryForToggle(toggleName) {
|
||||
api
|
||||
.fetchHistoryForToggle(toggleName)
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_PROJECT = 'RECEIVE_PROJECT';
|
||||
export const ERROR_RECEIVE_PROJECT = 'ERROR_RECEIVE_PROJECT';
|
||||
@ -22,7 +22,7 @@ export function fetchProjects() {
|
||||
.then(json => {
|
||||
dispatch(receiveProjects(json.projects));
|
||||
})
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_PROJECT));
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_PROJECT));
|
||||
}
|
||||
|
||||
export function removeProject(project) {
|
||||
@ -30,7 +30,7 @@ export function removeProject(project) {
|
||||
api
|
||||
.remove(project)
|
||||
.then(() => dispatch(delProject(project)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_PROJECT));
|
||||
.catch(dispatchError(dispatch, ERROR_REMOVING_PROJECT));
|
||||
}
|
||||
|
||||
export function createProject(project) {
|
||||
@ -38,7 +38,7 @@ export function createProject(project) {
|
||||
api
|
||||
.create(project)
|
||||
.then(() => dispatch(addProject(project)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_ADD_PROJECT));
|
||||
.catch(dispatchError(dispatch, ERROR_ADD_PROJECT));
|
||||
}
|
||||
|
||||
export function updateProject(project) {
|
||||
@ -46,7 +46,7 @@ export function updateProject(project) {
|
||||
api
|
||||
.update(project)
|
||||
.then(() => dispatch(upProject(project)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_PROJECT));
|
||||
.catch(dispatchError(dispatch, ERROR_UPDATE_PROJECT));
|
||||
}
|
||||
|
||||
export function validateId(id) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import api from './api';
|
||||
import applicationApi from '../application/api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const ADD_STRATEGY = 'ADD_STRATEGY';
|
||||
export const UPDATE_STRATEGY = 'UPDATE_STRATEGY';
|
||||
@ -44,7 +44,7 @@ export function fetchStrategies() {
|
||||
return api
|
||||
.fetchAll()
|
||||
.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
|
||||
.create(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
|
||||
.update(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
|
||||
.remove(strategy)
|
||||
.then(() => dispatch(createRemoveStrategy(strategy)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_REMOVING_STRATEGY));
|
||||
.catch(dispatchError(dispatch, ERROR_REMOVING_STRATEGY));
|
||||
}
|
||||
|
||||
export function getApplicationsWithStrategy(strategyName) {
|
||||
@ -87,7 +87,7 @@ export function deprecateStrategy(strategy) {
|
||||
dispatch(startDeprecate());
|
||||
api.deprecate(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());
|
||||
api.reactivate(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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const START_FETCH_TAG_TYPES = 'START_FETCH_TAG_TYPES';
|
||||
export const RECEIVE_TAG_TYPES = 'RECEIVE_TAG_TYPES';
|
||||
@ -28,7 +28,7 @@ export function fetchTagTypes() {
|
||||
return api
|
||||
.fetchTagTypes()
|
||||
.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
|
||||
.create({ 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
|
||||
.update({ 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
|
||||
.deleteTagType(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);
|
||||
}
|
||||
|
||||
export default {
|
||||
const api = {
|
||||
fetchTagTypes,
|
||||
create,
|
||||
update,
|
||||
deleteTagType,
|
||||
validateTagType,
|
||||
};
|
||||
}
|
||||
export default api;
|
||||
|
@ -1,8 +1,8 @@
|
||||
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';
|
||||
|
||||
const debug = require('debug')('unleash:tag-type-store');
|
||||
|
||||
const tagTypes = (state = new List([]), action) => {
|
||||
switch (action.type) {
|
||||
case ADD_TAG_TYPE:
|
||||
|
@ -1,5 +1,5 @@
|
||||
import api from './api';
|
||||
import { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const START_FETCH_TAGS = 'START_FETCH_TAGS';
|
||||
export const RECEIVE_TAGS = 'RECEIVE_TAGS';
|
||||
@ -25,7 +25,7 @@ export function fetchTags() {
|
||||
return api
|
||||
.fetchTags()
|
||||
.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
|
||||
.create({ 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
|
||||
.deleteTag(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 { dispatchAndThrow } from '../util';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_CONFIG = 'RECEIVE_CONFIG';
|
||||
export const ERROR_RECEIVE_CONFIG = 'ERROR_RECEIVE_CONFIG';
|
||||
@ -14,5 +14,5 @@ export function fetchUIConfig() {
|
||||
api
|
||||
.fetchConfig()
|
||||
.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 { dispatchAndThrow } from '../util';
|
||||
export const USER_CHANGE_CURRENT = 'USER_CHANGE_CURRENT';
|
||||
export const USER_LOGOUT = 'USER_LOGOUT';
|
||||
export const USER_LOGIN = 'USER_LOGIN';
|
||||
export const START_FETCH_USER = 'START_FETCH_USER';
|
||||
export const ERROR_FETCH_USER = 'ERROR_FETCH_USER';
|
||||
const debug = require('debug')('unleash:user-actions');
|
||||
import api from "./api";
|
||||
import { dispatchError } from "../util";
|
||||
export const USER_CHANGE_CURRENT = "USER_CHANGE_CURRENT";
|
||||
export const USER_LOGOUT = "USER_LOGOUT";
|
||||
export const USER_LOGIN = "USER_LOGIN";
|
||||
export const START_FETCH_USER = "START_FETCH_USER";
|
||||
export const ERROR_FETCH_USER = "ERROR_FETCH_USER";
|
||||
const debug = require("debug")("unleash:user-actions");
|
||||
|
||||
const updateUser = value => ({
|
||||
const updateUser = (value) => ({
|
||||
type: USER_CHANGE_CURRENT,
|
||||
value,
|
||||
});
|
||||
@ -18,41 +18,44 @@ function handleError(error) {
|
||||
|
||||
export function fetchUser() {
|
||||
debug('Start fetching user');
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: START_FETCH_USER });
|
||||
|
||||
return api
|
||||
.fetchUser()
|
||||
.then(json => dispatch(updateUser(json)))
|
||||
.catch(dispatchAndThrow(dispatch, ERROR_FETCH_USER));
|
||||
.then((json) => dispatch(updateUser(json)))
|
||||
.catch(dispatchError(dispatch, ERROR_FETCH_USER));
|
||||
};
|
||||
}
|
||||
|
||||
export function insecureLogin(path, user) {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: START_FETCH_USER });
|
||||
|
||||
return api
|
||||
.insecureLogin(path, user)
|
||||
.then(json => dispatch(updateUser(json)))
|
||||
.then((json) => dispatch(updateUser(json)))
|
||||
.catch(handleError);
|
||||
};
|
||||
}
|
||||
|
||||
export function passwordLogin(path, user) {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: START_FETCH_USER });
|
||||
|
||||
return api
|
||||
.passwordLogin(path, user)
|
||||
.then(json => dispatch(updateUser(json)))
|
||||
.then((json) => dispatch(updateUser(json)))
|
||||
.then(() => dispatch({ type: USER_LOGIN }));
|
||||
};
|
||||
}
|
||||
|
||||
export function logoutUser() {
|
||||
return dispatch => {
|
||||
dispatch({ type: USER_LOGOUT });
|
||||
window.location = 'logout';
|
||||
return (dispatch) => {
|
||||
return api
|
||||
.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() {
|
||||
return fetch(`${URI}/logout`, { method: 'GET', credentials: 'include' })
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
return fetch(`logout`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
}).then(throwIfNotSuccess);
|
||||
}
|
||||
|
||||
function fetchUser() {
|
||||
return fetch(URI, { credentials: 'include' })
|
||||
return fetch(URI, { credentials: "include" })
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
.then((response) => response.json());
|
||||
}
|
||||
|
||||
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(response => response.json());
|
||||
.then((response) => response.json());
|
||||
}
|
||||
|
||||
function passwordLogin(path, data) {
|
||||
return fetch(path, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers,
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
.then((response) => response.json());
|
||||
}
|
||||
|
||||
export default {
|
||||
const api = {
|
||||
fetchUser,
|
||||
insecureLogin,
|
||||
logoutUser,
|
||||
passwordLogin,
|
||||
};
|
||||
|
||||
export default api;
|
||||
|
@ -14,6 +14,7 @@ const userStore = (state = new $Map(), action) => {
|
||||
state = state.set('authDetails', action.error.body).set('showDialog', true);
|
||||
return state;
|
||||
case USER_LOGOUT:
|
||||
console.log("Resetting state due to logout");
|
||||
return new $Map();
|
||||
default:
|
||||
return state;
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const AUTH_REQUIRED = 'AUTH_REQUIRED';
|
||||
export const FORBIDDEN = 'FORBIDDEN';
|
||||
|
||||
export function dispatchAndThrow(dispatch, type) {
|
||||
export function dispatchError(dispatch, type) {
|
||||
return error => {
|
||||
switch (error.statusCode) {
|
||||
case 401:
|
||||
@ -14,7 +14,6 @@ export function dispatchAndThrow(dispatch, type) {
|
||||
dispatch({ type, error, receivedAt: Date.now() });
|
||||
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