mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 06:25:45 +01:00
adds combobox to select namespace strategy
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Links } from "./hal";
|
||||||
|
|
||||||
|
export type NamespaceStrategies = {
|
||||||
|
current: string,
|
||||||
|
available: string[],
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
@@ -26,3 +26,5 @@ export type { SubRepository, File } from "./Sources";
|
|||||||
export type { SelectValue, AutocompleteObject } from "./Autocomplete";
|
export type { SelectValue, AutocompleteObject } from "./Autocomplete";
|
||||||
|
|
||||||
export type { AvailableRepositoryPermissions, RepositoryRole } from "./AvailableRepositoryPermissions";
|
export type { AvailableRepositoryPermissions, RepositoryRole } from "./AvailableRepositoryPermissions";
|
||||||
|
|
||||||
|
export type { NamespaceStrategies } from "./NamespaceStrategies";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { SubmitButton, Notification } from "@scm-manager/ui-components";
|
import { SubmitButton, Notification } from "@scm-manager/ui-components";
|
||||||
|
import type { NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
import type { Config } from "@scm-manager/ui-types";
|
import type { Config } from "@scm-manager/ui-types";
|
||||||
import ProxySettings from "./ProxySettings";
|
import ProxySettings from "./ProxySettings";
|
||||||
import GeneralSettings from "./GeneralSettings";
|
import GeneralSettings from "./GeneralSettings";
|
||||||
@@ -13,9 +14,11 @@ type Props = {
|
|||||||
submitForm: Config => void,
|
submitForm: Config => void,
|
||||||
config?: Config,
|
config?: Config,
|
||||||
loading?: boolean,
|
loading?: boolean,
|
||||||
t: string => string,
|
|
||||||
configReadPermission: boolean,
|
configReadPermission: boolean,
|
||||||
configUpdatePermission: boolean
|
configUpdatePermission: boolean,
|
||||||
|
namespaceStrategies?: NamespaceStrategies,
|
||||||
|
// context props
|
||||||
|
t: string => string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -88,6 +91,7 @@ class ConfigForm extends React.Component<Props, State> {
|
|||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
t,
|
t,
|
||||||
|
namespaceStrategies,
|
||||||
configReadPermission,
|
configReadPermission,
|
||||||
configUpdatePermission
|
configUpdatePermission
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -118,6 +122,7 @@ class ConfigForm extends React.Component<Props, State> {
|
|||||||
<form onSubmit={this.submit}>
|
<form onSubmit={this.submit}>
|
||||||
{noPermissionNotification}
|
{noPermissionNotification}
|
||||||
<GeneralSettings
|
<GeneralSettings
|
||||||
|
namespaceStrategies={namespaceStrategies}
|
||||||
realmDescription={config.realmDescription}
|
realmDescription={config.realmDescription}
|
||||||
enableRepositoryArchive={config.enableRepositoryArchive}
|
enableRepositoryArchive={config.enableRepositoryArchive}
|
||||||
disableGroupingGrid={config.disableGroupingGrid}
|
disableGroupingGrid={config.disableGroupingGrid}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Checkbox, InputField } from "@scm-manager/ui-components";
|
import { Checkbox, InputField, Select } from "@scm-manager/ui-components";
|
||||||
|
import type { NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
|
import NamespaceStrategySelect from "./NamespaceStrategySelect";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
realmDescription: string,
|
realmDescription: string,
|
||||||
@@ -13,12 +15,15 @@ type Props = {
|
|||||||
pluginUrl: string,
|
pluginUrl: string,
|
||||||
enabledXsrfProtection: boolean,
|
enabledXsrfProtection: boolean,
|
||||||
defaultNamespaceStrategy: string,
|
defaultNamespaceStrategy: string,
|
||||||
t: string => string,
|
namespaceStrategies?: NamespaceStrategies,
|
||||||
onChange: (boolean, any, string) => void,
|
onChange: (boolean, any, string) => void,
|
||||||
hasUpdatePermission: boolean
|
hasUpdatePermission: boolean,
|
||||||
|
// context props
|
||||||
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
class GeneralSettings extends React.Component<Props> {
|
class GeneralSettings extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
t,
|
t,
|
||||||
@@ -31,7 +36,8 @@ class GeneralSettings extends React.Component<Props> {
|
|||||||
pluginUrl,
|
pluginUrl,
|
||||||
enabledXsrfProtection,
|
enabledXsrfProtection,
|
||||||
defaultNamespaceStrategy,
|
defaultNamespaceStrategy,
|
||||||
hasUpdatePermission
|
hasUpdatePermission,
|
||||||
|
namespaceStrategies
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -67,13 +73,14 @@ class GeneralSettings extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column is-half">
|
<div className="column is-half">
|
||||||
<InputField
|
<NamespaceStrategySelect
|
||||||
label={t("general-settings.default-namespace-strategy")}
|
label={t("general-settings.default-namespace-strategy")}
|
||||||
onChange={this.handleDefaultNamespaceStrategyChange}
|
onChange={this.handleDefaultNamespaceStrategyChange}
|
||||||
value={defaultNamespaceStrategy}
|
value={defaultNamespaceStrategy}
|
||||||
disabled={!hasUpdatePermission}
|
disabled={!hasUpdatePermission}
|
||||||
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
namespaceStrategies={namespaceStrategies}
|
||||||
/>
|
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
|
|||||||
55
scm-ui/src/config/components/form/NamespaceStrategySelect.js
Normal file
55
scm-ui/src/config/components/form/NamespaceStrategySelect.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate, type TFunction } from "react-i18next";
|
||||||
|
import { Select } from "@scm-manager/ui-components";
|
||||||
|
import type { NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
namespaceStrategies: NamespaceStrategies,
|
||||||
|
label: string,
|
||||||
|
value?: string,
|
||||||
|
disabled?: boolean,
|
||||||
|
helpText?: string,
|
||||||
|
onChange: (value: string, name?: string) => void,
|
||||||
|
// context props
|
||||||
|
t: TFunction
|
||||||
|
};
|
||||||
|
|
||||||
|
class NamespaceStrategySelect extends React.Component<Props> {
|
||||||
|
createNamespaceOptions = () => {
|
||||||
|
const { namespaceStrategies, t } = this.props;
|
||||||
|
let available = [];
|
||||||
|
if (namespaceStrategies && namespaceStrategies.available) {
|
||||||
|
available = namespaceStrategies.available;
|
||||||
|
}
|
||||||
|
|
||||||
|
return available.map(ns => {
|
||||||
|
const key = "namespaceStrategies." + ns;
|
||||||
|
let label = t("namespaceStrategies." + ns);
|
||||||
|
if (label === key) {
|
||||||
|
label = ns;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value: ns,
|
||||||
|
label: label
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { label, value, helpText, disabled, onChange } = this.props;
|
||||||
|
const nsOptions = this.createNamespaceOptions();
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label={label}
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
disabled={disabled}
|
||||||
|
options={nsOptions}
|
||||||
|
helpText={helpText}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("plugins")(NamespaceStrategySelect);
|
||||||
@@ -14,9 +14,15 @@ import {
|
|||||||
modifyConfigReset
|
modifyConfigReset
|
||||||
} from "../modules/config";
|
} from "../modules/config";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import type { Config } from "@scm-manager/ui-types";
|
import type { Config, NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
import ConfigForm from "../components/form/ConfigForm";
|
import ConfigForm from "../components/form/ConfigForm";
|
||||||
import { getConfigLink } from "../../modules/indexResource";
|
import { getConfigLink } from "../../modules/indexResource";
|
||||||
|
import {
|
||||||
|
fetchNamespaceStrategiesIfNeeded,
|
||||||
|
getFetchNamespaceStrategiesFailure,
|
||||||
|
getNamespaceStrategies,
|
||||||
|
isFetchNamespaceStrategiesPending
|
||||||
|
} from "../modules/namespaceStrategies";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
@@ -24,11 +30,13 @@ type Props = {
|
|||||||
config: Config,
|
config: Config,
|
||||||
configUpdatePermission: boolean,
|
configUpdatePermission: boolean,
|
||||||
configLink: string,
|
configLink: string,
|
||||||
|
namespaceStrategies?: NamespaceStrategies,
|
||||||
|
|
||||||
// dispatch functions
|
// dispatch functions
|
||||||
modifyConfig: (config: Config, callback?: () => void) => void,
|
modifyConfig: (config: Config, callback?: () => void) => void,
|
||||||
fetchConfig: (link: string) => void,
|
fetchConfig: (link: string) => void,
|
||||||
configReset: void => void,
|
configReset: void => void,
|
||||||
|
fetchNamespaceStrategiesIfNeeded: void => void,
|
||||||
|
|
||||||
// context objects
|
// context objects
|
||||||
t: string => string
|
t: string => string
|
||||||
@@ -51,6 +59,7 @@ class GlobalConfig extends React.Component<Props, State> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.configReset();
|
this.props.configReset();
|
||||||
|
this.props.fetchNamespaceStrategiesIfNeeded();
|
||||||
if (this.props.configLink) {
|
if (this.props.configLink) {
|
||||||
this.props.fetchConfig(this.props.configLink);
|
this.props.fetchConfig(this.props.configLink);
|
||||||
} else {
|
} else {
|
||||||
@@ -103,7 +112,7 @@ class GlobalConfig extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderContent = () => {
|
renderContent = () => {
|
||||||
const { error, loading, config, configUpdatePermission } = this.props;
|
const { error, loading, config, configUpdatePermission, namespaceStrategies } = this.props;
|
||||||
const { configReadPermission } = this.state;
|
const { configReadPermission } = this.state;
|
||||||
if (!error) {
|
if (!error) {
|
||||||
return (
|
return (
|
||||||
@@ -113,6 +122,7 @@ class GlobalConfig extends React.Component<Props, State> {
|
|||||||
submitForm={config => this.modifyConfig(config)}
|
submitForm={config => this.modifyConfig(config)}
|
||||||
config={config}
|
config={config}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
namespaceStrategies={namespaceStrategies}
|
||||||
configUpdatePermission={configUpdatePermission}
|
configUpdatePermission={configUpdatePermission}
|
||||||
configReadPermission={configReadPermission}
|
configReadPermission={configReadPermission}
|
||||||
/>
|
/>
|
||||||
@@ -133,23 +143,33 @@ const mapDispatchToProps = dispatch => {
|
|||||||
},
|
},
|
||||||
configReset: () => {
|
configReset: () => {
|
||||||
dispatch(modifyConfigReset());
|
dispatch(modifyConfigReset());
|
||||||
|
},
|
||||||
|
fetchNamespaceStrategiesIfNeeded: () => {
|
||||||
|
dispatch(fetchNamespaceStrategiesIfNeeded());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const loading = isFetchConfigPending(state) || isModifyConfigPending(state);
|
const loading = isFetchConfigPending(state)
|
||||||
const error = getFetchConfigFailure(state) || getModifyConfigFailure(state);
|
|| isModifyConfigPending(state)
|
||||||
|
|| isFetchNamespaceStrategiesPending(state);
|
||||||
|
const error = getFetchConfigFailure(state)
|
||||||
|
|| getModifyConfigFailure(state)
|
||||||
|
|| getFetchNamespaceStrategiesFailure(state);
|
||||||
|
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
const configUpdatePermission = getConfigUpdatePermission(state);
|
const configUpdatePermission = getConfigUpdatePermission(state);
|
||||||
const configLink = getConfigLink(state);
|
const configLink = getConfigLink(state);
|
||||||
|
const namespaceStrategies = getNamespaceStrategies(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
config,
|
config,
|
||||||
configUpdatePermission,
|
configUpdatePermission,
|
||||||
configLink
|
configLink,
|
||||||
|
namespaceStrategies
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
105
scm-ui/src/config/modules/namespaceStrategies.js
Normal file
105
scm-ui/src/config/modules/namespaceStrategies.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as types from "../../modules/types";
|
||||||
|
import type { Action, NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
|
import { apiClient } from "@scm-manager/ui-components";
|
||||||
|
import { isPending } from "../../modules/pending";
|
||||||
|
import { getFailure } from "../../modules/failure";
|
||||||
|
|
||||||
|
export const FETCH_NAMESPACESTRATEGIES_TYPES =
|
||||||
|
"scm/config/FETCH_NAMESPACESTRATEGIES_TYPES";
|
||||||
|
export const FETCH_NAMESPACESTRATEGIES_TYPES_PENDING = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${
|
||||||
|
types.PENDING_SUFFIX
|
||||||
|
}`;
|
||||||
|
export const FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${
|
||||||
|
types.SUCCESS_SUFFIX
|
||||||
|
}`;
|
||||||
|
export const FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${
|
||||||
|
types.FAILURE_SUFFIX
|
||||||
|
}`;
|
||||||
|
|
||||||
|
export function fetchNamespaceStrategiesIfNeeded() {
|
||||||
|
return function(dispatch: any, getState: () => Object) {
|
||||||
|
const state = getState();
|
||||||
|
if (shouldFetchNamespaceStrategies(state)) {
|
||||||
|
return fetchNamespaceStrategies(dispatch, state.indexResources.links.namespaceStrategies.href);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchNamespaceStrategies(dispatch: any, url: string) {
|
||||||
|
dispatch(fetchNamespaceStrategiesPending());
|
||||||
|
return apiClient
|
||||||
|
.get(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(namespaceStrategies => {
|
||||||
|
dispatch(fetchNamespaceStrategiesSuccess(namespaceStrategies));
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
dispatch(fetchNamespaceStrategiesFailure(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldFetchNamespaceStrategies(state: Object) {
|
||||||
|
if (
|
||||||
|
isFetchNamespaceStrategiesPending(state) ||
|
||||||
|
getFetchNamespaceStrategiesFailure(state)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !state.namespaceStrategies || !state.namespaceStrategies.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchNamespaceStrategiesPending(): Action {
|
||||||
|
return {
|
||||||
|
type: FETCH_NAMESPACESTRATEGIES_TYPES_PENDING
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchNamespaceStrategiesSuccess(
|
||||||
|
namespaceStrategies: NamespaceStrategies
|
||||||
|
): Action {
|
||||||
|
return {
|
||||||
|
type: FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS,
|
||||||
|
payload: namespaceStrategies
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchNamespaceStrategiesFailure(error: Error): Action {
|
||||||
|
return {
|
||||||
|
type: FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE,
|
||||||
|
payload: error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// reducers
|
||||||
|
|
||||||
|
export default function reducer(
|
||||||
|
state: NamespaceStrategies = {},
|
||||||
|
action: Action = { type: "UNKNOWN" }
|
||||||
|
): NamespaceStrategies {
|
||||||
|
if (
|
||||||
|
action.type === FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS &&
|
||||||
|
action.payload
|
||||||
|
) {
|
||||||
|
return action.payload;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectors
|
||||||
|
|
||||||
|
export function getNamespaceStrategies(state: Object) {
|
||||||
|
if (state.namespaceStrategies) {
|
||||||
|
return state.namespaceStrategies;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFetchNamespaceStrategiesPending(state: Object) {
|
||||||
|
return isPending(state, FETCH_NAMESPACESTRATEGIES_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFetchNamespaceStrategiesFailure(state: Object) {
|
||||||
|
return getFailure(state, FETCH_NAMESPACESTRATEGIES_TYPES);
|
||||||
|
}
|
||||||
187
scm-ui/src/config/modules/namespaceStrategies.test.js
Normal file
187
scm-ui/src/config/modules/namespaceStrategies.test.js
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
// @flow
|
||||||
|
import fetchMock from "fetch-mock";
|
||||||
|
import configureMockStore from "redux-mock-store";
|
||||||
|
import thunk from "redux-thunk";
|
||||||
|
import {
|
||||||
|
FETCH_NAMESPACESTRATEGIES_TYPES,
|
||||||
|
FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE,
|
||||||
|
FETCH_NAMESPACESTRATEGIES_TYPES_PENDING,
|
||||||
|
FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS,
|
||||||
|
fetchNamespaceStrategiesIfNeeded,
|
||||||
|
fetchNamespaceStrategiesSuccess,
|
||||||
|
shouldFetchNamespaceStrategies,
|
||||||
|
default as reducer,
|
||||||
|
getNamespaceStrategies,
|
||||||
|
isFetchNamespaceStrategiesPending,
|
||||||
|
getFetchNamespaceStrategiesFailure
|
||||||
|
} from "./namespaceStrategies";
|
||||||
|
|
||||||
|
const strategies = {
|
||||||
|
current: "sonia.scm.repository.UsernameNamespaceStrategy",
|
||||||
|
available: [
|
||||||
|
"sonia.scm.repository.UsernameNamespaceStrategy",
|
||||||
|
"sonia.scm.repository.CustomNamespaceStrategy",
|
||||||
|
"sonia.scm.repository.CurrentYearNamespaceStrategy",
|
||||||
|
"sonia.scm.repository.RepositoryTypeNamespaceStrategy"
|
||||||
|
],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: "http://localhost:8081/scm/api/v2/namespaceStrategies"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("namespace strategy caching", () => {
|
||||||
|
it("should fetch strategies, on empty state", () => {
|
||||||
|
expect(shouldFetchNamespaceStrategies({})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fetch strategies, on empty namespaceStrategies node", () => {
|
||||||
|
const state = {
|
||||||
|
namespaceStrategies: {}
|
||||||
|
};
|
||||||
|
expect(shouldFetchNamespaceStrategies(state)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not fetch strategies, on pending state", () => {
|
||||||
|
const state = {
|
||||||
|
pending: {
|
||||||
|
[FETCH_NAMESPACESTRATEGIES_TYPES]: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(shouldFetchNamespaceStrategies(state)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not fetch strategies, on failure state", () => {
|
||||||
|
const state = {
|
||||||
|
failure: {
|
||||||
|
[FETCH_NAMESPACESTRATEGIES_TYPES]: new Error("no...")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(shouldFetchNamespaceStrategies(state)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not fetch strategies, if they are already fetched", () => {
|
||||||
|
const state = {
|
||||||
|
namespaceStrategies: {
|
||||||
|
current: "some"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(shouldFetchNamespaceStrategies(state)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("namespace strategies fetch", () => {
|
||||||
|
const URL = "http://scm.hitchhiker.com/api/v2/namespaceStrategies";
|
||||||
|
const mockStore = configureMockStore([thunk]);
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fetchMock.reset();
|
||||||
|
fetchMock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const createStore = (initialState = {}) => {
|
||||||
|
return mockStore({
|
||||||
|
...initialState,
|
||||||
|
indexResources: {
|
||||||
|
links: {
|
||||||
|
namespaceStrategies: {
|
||||||
|
href: URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should successfully fetch strategies", () => {
|
||||||
|
fetchMock.getOnce(URL, strategies);
|
||||||
|
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: FETCH_NAMESPACESTRATEGIES_TYPES_PENDING },
|
||||||
|
{
|
||||||
|
type: FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS,
|
||||||
|
payload: strategies
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const store = createStore();
|
||||||
|
return store.dispatch(fetchNamespaceStrategiesIfNeeded()).then(() => {
|
||||||
|
expect(store.getActions()).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should dispatch FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE on server error", () => {
|
||||||
|
fetchMock.getOnce(URL, {
|
||||||
|
status: 500
|
||||||
|
});
|
||||||
|
|
||||||
|
const store = createStore();
|
||||||
|
return store.dispatch(fetchNamespaceStrategiesIfNeeded()).then(() => {
|
||||||
|
const actions = store.getActions();
|
||||||
|
expect(actions[0].type).toBe(FETCH_NAMESPACESTRATEGIES_TYPES_PENDING);
|
||||||
|
expect(actions[1].type).toBe(FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE);
|
||||||
|
expect(actions[1].payload).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not dispatch any action, if the strategies are already fetched", () => {
|
||||||
|
const store = createStore({
|
||||||
|
namespaceStrategies: strategies
|
||||||
|
});
|
||||||
|
store.dispatch(fetchNamespaceStrategiesIfNeeded());
|
||||||
|
expect(store.getActions().length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("namespace strategies reducer", () => {
|
||||||
|
it("should return unmodified state on unknown action", () => {
|
||||||
|
const state = [];
|
||||||
|
expect(reducer(state)).toBe(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should store the strategies on success", () => {
|
||||||
|
const newState = reducer([], fetchNamespaceStrategiesSuccess(strategies));
|
||||||
|
expect(newState).toBe(strategies);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("namespace strategy selectors", () => {
|
||||||
|
const error = new Error("The end of the universe");
|
||||||
|
|
||||||
|
it("should return an empty object", () => {
|
||||||
|
expect(getNamespaceStrategies({})).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the namespace strategies", () => {
|
||||||
|
const state = {
|
||||||
|
namespaceStrategies: strategies
|
||||||
|
};
|
||||||
|
expect(getNamespaceStrategies(state)).toBe(strategies);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true, when fetch namespace strategies is pending", () => {
|
||||||
|
const state = {
|
||||||
|
pending: {
|
||||||
|
[FETCH_NAMESPACESTRATEGIES_TYPES]: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(isFetchNamespaceStrategiesPending(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false, when fetch strategies is not pending", () => {
|
||||||
|
expect(isFetchNamespaceStrategiesPending({})).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return error when fetch namespace strategies did fail", () => {
|
||||||
|
const state = {
|
||||||
|
failure: {
|
||||||
|
[FETCH_NAMESPACESTRATEGIES_TYPES]: error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(getFetchNamespaceStrategiesFailure(state)).toEqual(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined when fetch strategies did not fail", () => {
|
||||||
|
expect(getFetchNamespaceStrategiesFailure({})).toBe(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -15,6 +15,7 @@ import pending from "./modules/pending";
|
|||||||
import failure from "./modules/failure";
|
import failure from "./modules/failure";
|
||||||
import permissions from "./repos/permissions/modules/permissions";
|
import permissions from "./repos/permissions/modules/permissions";
|
||||||
import config from "./config/modules/config";
|
import config from "./config/modules/config";
|
||||||
|
import namespaceStrategies from "./config/modules/namespaceStrategies";
|
||||||
import indexResources from "./modules/indexResource";
|
import indexResources from "./modules/indexResource";
|
||||||
|
|
||||||
import type { BrowserHistory } from "history/createBrowserHistory";
|
import type { BrowserHistory } from "history/createBrowserHistory";
|
||||||
@@ -38,7 +39,8 @@ function createReduxStore(history: BrowserHistory) {
|
|||||||
groups,
|
groups,
|
||||||
auth,
|
auth,
|
||||||
config,
|
config,
|
||||||
sources
|
sources,
|
||||||
|
namespaceStrategies
|
||||||
});
|
});
|
||||||
|
|
||||||
return createStore(
|
return createStore(
|
||||||
|
|||||||
Reference in New Issue
Block a user