diff --git a/ui/src/Common/Fetch.js b/ui/src/Common/Fetch.js
index 6d4a8f068..a62de42a0 100644
--- a/ui/src/Common/Fetch.js
+++ b/ui/src/Common/Fetch.js
@@ -1,9 +1,28 @@
import merge from "lodash.merge";
-const FetchWithCredentials = async (uri, options) =>
+const CommonOptions = {
+ credentials: "include",
+ redirect: "follow"
+};
+
+const FetchGet = async (uri, options) =>
await fetch(
uri,
- merge({}, { credentials: "include", redirect: "follow" }, options)
+ merge(
+ {},
+ {
+ method: "GET",
+ mode: "no-cors"
+ },
+ CommonOptions,
+ options
+ )
);
-export { FetchWithCredentials };
+const FetchPost = async (uri, options) =>
+ await fetch(uri, merge({}, { method: "POST" }, CommonOptions, options));
+
+const FetchDelete = async (uri, options) =>
+ await fetch(uri, merge({}, { method: "DELETE" }, CommonOptions, options));
+
+export { CommonOptions, FetchGet, FetchPost, FetchDelete };
diff --git a/ui/src/Common/Fetch.test.js b/ui/src/Common/Fetch.test.js
index ed244d32a..7218c76c9 100644
--- a/ui/src/Common/Fetch.test.js
+++ b/ui/src/Common/Fetch.test.js
@@ -1,4 +1,6 @@
-import { FetchWithCredentials } from "./Fetch";
+import { CommonOptions, FetchGet, FetchPost, FetchDelete } from "./Fetch";
+
+import merge from "lodash.merge";
beforeEach(() => {
fetch.resetMocks();
@@ -8,37 +10,53 @@ afterEach(() => {
jest.restoreAllMocks();
});
-describe("FetchWithCredentials", () => {
- it("fetch passes '{credentials: include}' to all requests", async () => {
- const request = FetchWithCredentials("http://example.com", {});
- await expect(request).resolves.toBeUndefined();
- expect(fetch).toHaveBeenCalledWith("http://example.com", {
- credentials: "include",
- redirect: "follow"
- });
- });
+describe("Fetch", () => {
+ const tests = {
+ FetchGet: FetchGet,
+ FetchPost: FetchPost,
+ FetchDelete: FetchDelete
+ };
- it("custom keys are merged with defaults", async () => {
- const request = FetchWithCredentials("http://example.com", {
- foo: "bar"
- });
- await expect(request).resolves.toBeUndefined();
- expect(fetch).toHaveBeenCalledWith("http://example.com", {
- credentials: "include",
- redirect: "follow",
- foo: "bar"
- });
- });
+ const methodOptions = {
+ FetchGet: { method: "GET", mode: "no-cors" },
+ FetchPost: { method: "POST" },
+ FetchDelete: { method: "DELETE" }
+ };
- it("custom credentials are used when passed", async () => {
- const request = FetchWithCredentials("http://example.com", {
- credentials: "none",
- redirect: "follow"
+ for (const [name, func] of Object.entries(tests)) {
+ it(`${name}: passes '{credentials: include}' to all requests`, async () => {
+ const request = func("http://example.com", {});
+ await expect(request).resolves.toBeUndefined();
+ expect(fetch).toHaveBeenCalledWith(
+ "http://example.com",
+ merge({}, CommonOptions, methodOptions[name])
+ );
});
- await expect(request).resolves.toBeUndefined();
- expect(fetch).toHaveBeenCalledWith("http://example.com", {
- credentials: "none",
- redirect: "follow"
+
+ it(`${name}: custom keys are merged with defaults`, async () => {
+ const request = func("http://example.com", {
+ foo: "bar"
+ });
+ await expect(request).resolves.toBeUndefined();
+ expect(fetch).toHaveBeenCalledWith(
+ "http://example.com",
+ merge({}, CommonOptions, methodOptions[name], { foo: "bar" })
+ );
});
- });
+
+ it(`${name}: custom credentials are used when passed`, async () => {
+ const request = func("http://example.com", {
+ credentials: "none",
+ redirect: "follow"
+ });
+ await expect(request).resolves.toBeUndefined();
+ expect(fetch).toHaveBeenCalledWith(
+ "http://example.com",
+ merge({}, CommonOptions, methodOptions[name], {
+ credentials: "none",
+ redirect: "follow"
+ })
+ );
+ });
+ }
});
diff --git a/ui/src/Components/AlertAck/index.js b/ui/src/Components/AlertAck/index.js
index 9f517e7af..a6f41c8ac 100644
--- a/ui/src/Components/AlertAck/index.js
+++ b/ui/src/Components/AlertAck/index.js
@@ -21,7 +21,7 @@ import {
MatchersFromGroup,
GenerateAlertmanagerSilenceData
} from "Stores/SilenceFormStore";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchPost } from "Common/Fetch";
import { TooltipWrapper } from "Components/TooltipWrapper";
const SubmitState = Object.freeze({
@@ -148,19 +148,15 @@ const AlertAck = observer(
? `${am.uri}/api/v2/silences`
: `${am.uri}/api/v1/silences`;
- this.submitState.silencesByCluster[cluster].fetch = FetchWithCredentials(
- uri,
- {
- method: "POST",
- body: JSON.stringify(
- this.submitState.silencesByCluster[cluster].payload
- ),
- headers: {
- "Content-Type": "application/json",
- ...am.headers
- }
+ this.submitState.silencesByCluster[cluster].fetch = FetchPost(uri, {
+ body: JSON.stringify(
+ this.submitState.silencesByCluster[cluster].payload
+ ),
+ headers: {
+ "Content-Type": "application/json",
+ ...am.headers
}
- )
+ })
.then(result => {
if (isOpenAPI) {
if (result.ok) {
diff --git a/ui/src/Components/MainModal/Configuration/SortLabelName.js b/ui/src/Components/MainModal/Configuration/SortLabelName.js
index e6fafa75f..8d68d8238 100644
--- a/ui/src/Components/MainModal/Configuration/SortLabelName.js
+++ b/ui/src/Components/MainModal/Configuration/SortLabelName.js
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
import Creatable from "react-select/creatable";
import { StaticLabels } from "Common/Query";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
import { FormatBackendURI } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { ReactSelectStyles } from "Components/MultiSelect";
@@ -34,7 +34,7 @@ const SortLabelName = observer(
});
populateNameSuggestions = action(() => {
- this.nameSuggestionsFetch = FetchWithCredentials(
+ this.nameSuggestionsFetch = FetchGet(
FormatBackendURI(`labelNames.json`),
{}
)
diff --git a/ui/src/Components/ManagedSilence/DeleteSilence.js b/ui/src/Components/ManagedSilence/DeleteSilence.js
index 829d9e2cc..f26dd0f9f 100644
--- a/ui/src/Components/ManagedSilence/DeleteSilence.js
+++ b/ui/src/Components/ManagedSilence/DeleteSilence.js
@@ -16,7 +16,7 @@ import { APISilence } from "Models/API";
import { AlertStore, FormatBackendURI, FormatAlertsQ } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { FormatQuery, QueryOperators, StaticLabels } from "Common/Query";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet, FetchDelete } from "Common/Fetch";
import { Modal } from "Components/Modal";
import {
LabelSetList,
@@ -144,7 +144,7 @@ const DeleteSilenceModalContent = observer(
FormatQuery(StaticLabels.SilenceID, QueryOperators.Equal, silence.id)
]);
- this.previewState.fetch = FetchWithCredentials(alertsURI, {})
+ this.previewState.fetch = FetchGet(alertsURI, {})
.then(result => result.json())
.then(result => {
this.previewState.groupsToUniqueLabels(Object.values(result.groups));
@@ -175,8 +175,7 @@ const DeleteSilenceModalContent = observer(
? `${alertmanager.uri}/api/v2/silence/${silence.id}`
: `${alertmanager.uri}/api/v1/silence/${silence.id}`;
- this.deleteState.fetch = FetchWithCredentials(uri, {
- method: "DELETE",
+ this.deleteState.fetch = FetchDelete(uri, {
headers: alertmanager.headers
})
.then(result => {
diff --git a/ui/src/Components/NavBar/FilterInput/index.js b/ui/src/Components/NavBar/FilterInput/index.js
index 0dc7b5329..a21cffef5 100644
--- a/ui/src/Components/NavBar/FilterInput/index.js
+++ b/ui/src/Components/NavBar/FilterInput/index.js
@@ -15,7 +15,7 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch";
import { AlertStore, FormatBackendURI } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { IsMobile } from "Common/Device";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
import { FilterInputLabel } from "Components/Labels/FilterInputLabel";
import { AutosuggestTheme } from "./Constants";
import { History } from "./History";
@@ -73,7 +73,7 @@ const FilterInput = observer(
onSuggestionsFetchRequested = debounce(
action(({ value }) => {
if (value !== "") {
- this.inputStore.suggestionsFetch = FetchWithCredentials(
+ this.inputStore.suggestionsFetch = FetchGet(
FormatBackendURI(`autocomplete.json?term=${value}`),
{}
)
diff --git a/ui/src/Components/SilenceModal/Browser/index.js b/ui/src/Components/SilenceModal/Browser/index.js
index a3579cac8..6fdbce575 100644
--- a/ui/src/Components/SilenceModal/Browser/index.js
+++ b/ui/src/Components/SilenceModal/Browser/index.js
@@ -21,7 +21,7 @@ import { faAngleDoubleRight } from "@fortawesome/free-solid-svg-icons/faAngleDou
import { AlertStore, FormatBackendURI } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { Settings } from "Stores/Settings";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
import { MountFade } from "Components/Animations/MountFade";
import { ManagedSilence } from "Components/ManagedSilence";
@@ -102,7 +102,7 @@ const Browser = observer(
}`
);
- this.dataSource.fetch = FetchWithCredentials(uri, {})
+ this.dataSource.fetch = FetchGet(uri, {})
.then(result => {
return result.json();
})
diff --git a/ui/src/Components/SilenceModal/SilenceMatch/LabelNameInput.js b/ui/src/Components/SilenceModal/SilenceMatch/LabelNameInput.js
index 8fc6c6a9e..92434d764 100644
--- a/ui/src/Components/SilenceModal/SilenceMatch/LabelNameInput.js
+++ b/ui/src/Components/SilenceModal/SilenceMatch/LabelNameInput.js
@@ -8,7 +8,7 @@ import { SilenceFormMatcher } from "Models/SilenceForm";
import { MultiSelect } from "Components/MultiSelect";
import { ValidationError } from "Components/MultiSelect/ValidationError";
import { FormatBackendURI } from "Stores/AlertStore";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
const LabelNameInput = observer(
class LabelNameInput extends MultiSelect {
@@ -20,7 +20,7 @@ const LabelNameInput = observer(
populateNameSuggestions = action(() => {
const { matcher } = this.props;
- this.nameSuggestionsFetch = FetchWithCredentials(
+ this.nameSuggestionsFetch = FetchGet(
FormatBackendURI(`labelNames.json`),
{}
)
@@ -45,7 +45,7 @@ const LabelNameInput = observer(
populateValueSuggestions = action(() => {
const { matcher } = this.props;
- this.valueSuggestionsFetch = FetchWithCredentials(
+ this.valueSuggestionsFetch = FetchGet(
FormatBackendURI(`labelValues.json?name=${matcher.name}`),
{}
)
diff --git a/ui/src/Components/SilenceModal/SilenceMatch/MatchCounter.js b/ui/src/Components/SilenceModal/SilenceMatch/MatchCounter.js
index 8f9d19bc5..b867ebf6e 100644
--- a/ui/src/Components/SilenceModal/SilenceMatch/MatchCounter.js
+++ b/ui/src/Components/SilenceModal/SilenceMatch/MatchCounter.js
@@ -14,7 +14,7 @@ import { FormatBackendURI, FormatAlertsQ } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { SilenceFormMatcher } from "Models/SilenceForm";
import { TooltipWrapper } from "Components/TooltipWrapper";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
import { MatcherToFilter, AlertManagersToFilter } from "../Matchers";
const MatchCounter = observer(
@@ -55,7 +55,7 @@ const MatchCounter = observer(
const alertsURI =
FormatBackendURI("alerts.json?") + FormatAlertsQ(filters);
- this.matchedAlerts.fetch = FetchWithCredentials(alertsURI, {})
+ this.matchedAlerts.fetch = FetchGet(alertsURI, {})
.then(result => {
return result.json();
})
diff --git a/ui/src/Components/SilenceModal/SilencePreview/index.js b/ui/src/Components/SilenceModal/SilencePreview/index.js
index ad7a6d769..c061f5578 100644
--- a/ui/src/Components/SilenceModal/SilencePreview/index.js
+++ b/ui/src/Components/SilenceModal/SilencePreview/index.js
@@ -16,7 +16,7 @@ import {
LabelSetList,
GroupListToUniqueLabelsList
} from "Components/LabelSetList";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
import { MatcherToFilter, AlertManagersToFilter } from "../Matchers";
const FetchError = ({ message }) => (
@@ -82,7 +82,7 @@ const SilencePreview = observer(
const alertsURI =
FormatBackendURI("alerts.json?") + FormatAlertsQ(filters);
- this.matchedAlerts.fetch = FetchWithCredentials(alertsURI, {})
+ this.matchedAlerts.fetch = FetchGet(alertsURI, {})
.then(result => {
return result.json();
})
diff --git a/ui/src/Components/SilenceModal/SilencePreview/index.test.js b/ui/src/Components/SilenceModal/SilencePreview/index.test.js
index e4d3ec9ad..66935abc6 100644
--- a/ui/src/Components/SilenceModal/SilencePreview/index.test.js
+++ b/ui/src/Components/SilenceModal/SilencePreview/index.test.js
@@ -85,11 +85,14 @@ describe("", () => {
const tree = MountedSilencePreview();
await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined();
- expect(
- fetch
- ).toHaveBeenCalledWith(
+ expect(fetch).toHaveBeenCalledWith(
"./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28amValue%29%24",
- { credentials: "include", redirect: "follow" }
+ {
+ method: "GET",
+ mode: "no-cors",
+ credentials: "include",
+ redirect: "follow"
+ }
);
});
@@ -101,11 +104,14 @@ describe("", () => {
const tree = MountedSilencePreview();
await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined();
- expect(
- fetch
- ).toHaveBeenCalledWith(
+ expect(fetch).toHaveBeenCalledWith(
"./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28am1%7Cam2%29%24",
- { credentials: "include", redirect: "follow" }
+ {
+ method: "GET",
+ mode: "no-cors",
+ credentials: "include",
+ redirect: "follow"
+ }
);
});
diff --git a/ui/src/Components/SilenceModal/SilenceSubmit/SilenceSubmitProgress.js b/ui/src/Components/SilenceModal/SilenceSubmit/SilenceSubmitProgress.js
index bd19778e9..25354e794 100644
--- a/ui/src/Components/SilenceModal/SilenceSubmit/SilenceSubmitProgress.js
+++ b/ui/src/Components/SilenceModal/SilenceSubmit/SilenceSubmitProgress.js
@@ -13,7 +13,7 @@ import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclama
import { APISilenceMatcher } from "Models/API";
import { AlertStore } from "Stores/AlertStore";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchPost } from "Common/Fetch";
const SubmitState = Object.freeze({
InProgress: "InProgress",
@@ -109,8 +109,7 @@ const SilenceSubmitProgress = observer(
? `${am.uri}/api/v2/silences`
: `${am.uri}/api/v1/silences`;
- this.submitState.fetch = FetchWithCredentials(uri, {
- method: "POST",
+ this.submitState.fetch = FetchPost(uri, {
body: JSON.stringify(payload),
headers: {
"Content-Type": "application/json",
diff --git a/ui/src/Stores/AlertStore.js b/ui/src/Stores/AlertStore.js
index 3ec98f539..4d81acb89 100644
--- a/ui/src/Stores/AlertStore.js
+++ b/ui/src/Stores/AlertStore.js
@@ -8,7 +8,7 @@ import qs from "qs";
import moment from "moment";
-import { FetchWithCredentials } from "Common/Fetch";
+import { FetchGet } from "Common/Fetch";
const QueryStringEncodeOptions = {
encodeValuesOnly: true, // don't encode q[]
@@ -268,7 +268,7 @@ class AlertStore {
`alerts.json?sortOrder=${sortOrder}&sortLabel=${sortLabel}&sortReverse=${sortReverse}&`
) + FormatAPIFilterQuery(this.filters.values.map(f => f.raw));
- return FetchWithCredentials(alertsURI, {})
+ return FetchGet(alertsURI, {})
.then(result => {
this.status.setProcessing();
return result.json();