@scm-manager/ui-api 2.27.4 → 2.27.5-20211122-133854
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/branches.test.ts +22 -20
- package/src/branches.ts +106 -13
- package/src/changesets.test.ts +19 -18
- package/src/config.test.ts +1 -0
- package/src/contentType.ts +6 -0
- package/src/import.ts +9 -9
- package/src/index.ts +2 -0
- package/src/loginInfo.ts +43 -0
- package/src/repositories.test.ts +54 -57
- package/src/urls.ts +7 -2
- package/src/usePluginCenterAuthInfo.ts +78 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scm-manager/ui-api",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.5-20211122-133854",
|
|
4
4
|
"description": "React hook api for the SCM-Manager backend",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"files": [
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"react-test-renderer": "^17.0.1"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@scm-manager/ui-types": "^2.27.
|
|
28
|
+
"@scm-manager/ui-types": "^2.27.5-20211122-133854",
|
|
29
29
|
"fetch-mock-jest": "^1.5.1",
|
|
30
30
|
"gitdiff-parser": "^0.1.2",
|
|
31
|
-
"query-string": "
|
|
31
|
+
"query-string": "6.14.1",
|
|
32
32
|
"react": "^17.0.1",
|
|
33
33
|
"react-query": "^3.25.1"
|
|
34
34
|
},
|
package/src/branches.test.ts
CHANGED
|
@@ -36,36 +36,38 @@ describe("Test branches hooks", () => {
|
|
|
36
36
|
type: "hg",
|
|
37
37
|
_links: {
|
|
38
38
|
branches: {
|
|
39
|
-
href: "/hog/branches"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
39
|
+
href: "/hog/branches"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const develop: Branch = {
|
|
45
45
|
name: "develop",
|
|
46
46
|
revision: "42",
|
|
47
|
+
lastCommitter: { name: "trillian" },
|
|
47
48
|
_links: {
|
|
48
49
|
delete: {
|
|
49
|
-
href: "/hog/branches/develop"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
50
|
+
href: "/hog/branches/develop"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
52
53
|
};
|
|
53
54
|
|
|
54
55
|
const feature: Branch = {
|
|
55
56
|
name: "feature/something-special",
|
|
56
57
|
revision: "42",
|
|
58
|
+
lastCommitter: { name: "trillian" },
|
|
57
59
|
_links: {
|
|
58
60
|
delete: {
|
|
59
|
-
href: "/hog/branches/feature%2Fsomething-special"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
61
|
+
href: "/hog/branches/feature%2Fsomething-special"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
62
64
|
};
|
|
63
65
|
|
|
64
66
|
const branches: BranchCollection = {
|
|
65
67
|
_embedded: {
|
|
66
|
-
branches: [develop]
|
|
68
|
+
branches: [develop]
|
|
67
69
|
},
|
|
68
|
-
_links: {}
|
|
70
|
+
_links: {}
|
|
69
71
|
};
|
|
70
72
|
|
|
71
73
|
const queryClient = createInfiniteCachingClient();
|
|
@@ -83,7 +85,7 @@ describe("Test branches hooks", () => {
|
|
|
83
85
|
fetchMock.getOnce("/api/v2/hog/branches", branches);
|
|
84
86
|
|
|
85
87
|
const { result, waitFor } = renderHook(() => useBranches(repository), {
|
|
86
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
88
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
87
89
|
});
|
|
88
90
|
await waitFor(() => {
|
|
89
91
|
return !!result.current.data;
|
|
@@ -104,7 +106,7 @@ describe("Test branches hooks", () => {
|
|
|
104
106
|
"repository",
|
|
105
107
|
"hitchhiker",
|
|
106
108
|
"heart-of-gold",
|
|
107
|
-
"branches"
|
|
109
|
+
"branches"
|
|
108
110
|
]);
|
|
109
111
|
expect(data).toEqual(branches);
|
|
110
112
|
});
|
|
@@ -115,7 +117,7 @@ describe("Test branches hooks", () => {
|
|
|
115
117
|
fetchMock.getOnce("/api/v2/hog/branches/" + encodeURIComponent(name), branch);
|
|
116
118
|
|
|
117
119
|
const { result, waitFor } = renderHook(() => useBranch(repository, name), {
|
|
118
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
120
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
119
121
|
});
|
|
120
122
|
|
|
121
123
|
expect(result.error).toBeUndefined();
|
|
@@ -143,14 +145,14 @@ describe("Test branches hooks", () => {
|
|
|
143
145
|
fetchMock.postOnce("/api/v2/hog/branches", {
|
|
144
146
|
status: 201,
|
|
145
147
|
headers: {
|
|
146
|
-
Location: "/hog/branches/develop"
|
|
147
|
-
}
|
|
148
|
+
Location: "/hog/branches/develop"
|
|
149
|
+
}
|
|
148
150
|
});
|
|
149
151
|
|
|
150
152
|
fetchMock.getOnce("/api/v2/hog/branches/develop", develop);
|
|
151
153
|
|
|
152
154
|
const { result, waitForNextUpdate } = renderHook(() => useCreateBranch(repository), {
|
|
153
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
155
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
154
156
|
});
|
|
155
157
|
|
|
156
158
|
await act(() => {
|
|
@@ -175,7 +177,7 @@ describe("Test branches hooks", () => {
|
|
|
175
177
|
"hitchhiker",
|
|
176
178
|
"heart-of-gold",
|
|
177
179
|
"branch",
|
|
178
|
-
"develop"
|
|
180
|
+
"develop"
|
|
179
181
|
]);
|
|
180
182
|
expect(branch).toEqual(develop);
|
|
181
183
|
});
|
|
@@ -192,11 +194,11 @@ describe("Test branches hooks", () => {
|
|
|
192
194
|
describe("useDeleteBranch tests", () => {
|
|
193
195
|
const deleteBranch = async () => {
|
|
194
196
|
fetchMock.deleteOnce("/api/v2/hog/branches/develop", {
|
|
195
|
-
status: 204
|
|
197
|
+
status: 204
|
|
196
198
|
});
|
|
197
199
|
|
|
198
200
|
const { result, waitForNextUpdate } = renderHook(() => useDeleteBranch(repository), {
|
|
199
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
201
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
200
202
|
});
|
|
201
203
|
|
|
202
204
|
await act(() => {
|
package/src/branches.ts
CHANGED
|
@@ -21,19 +21,35 @@
|
|
|
21
21
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
Branch,
|
|
26
|
+
BranchCollection,
|
|
27
|
+
BranchCreation,
|
|
28
|
+
BranchDetails,
|
|
29
|
+
BranchDetailsCollection,
|
|
30
|
+
Link,
|
|
31
|
+
NamespaceAndName,
|
|
32
|
+
Repository
|
|
33
|
+
} from "@scm-manager/ui-types";
|
|
25
34
|
import { requiredLink } from "./links";
|
|
26
|
-
import { useMutation, useQuery, useQueryClient } from "react-query";
|
|
35
|
+
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "react-query";
|
|
27
36
|
import { ApiResult, ApiResultWithFetching } from "./base";
|
|
28
37
|
import { branchQueryKey, repoQueryKey } from "./keys";
|
|
29
38
|
import { apiClient } from "./apiclient";
|
|
30
39
|
import { concat } from "./urls";
|
|
40
|
+
import { useEffect } from "react";
|
|
31
41
|
|
|
32
42
|
export const useBranches = (repository: Repository): ApiResult<BranchCollection> => {
|
|
43
|
+
const queryClient = useQueryClient();
|
|
33
44
|
const link = requiredLink(repository, "branches");
|
|
34
45
|
return useQuery<BranchCollection, Error>(
|
|
35
46
|
repoQueryKey(repository, "branches"),
|
|
36
|
-
() => apiClient.get(link).then(
|
|
47
|
+
() => apiClient.get(link).then(response => response.json()),
|
|
48
|
+
{
|
|
49
|
+
onSuccess: () => {
|
|
50
|
+
return queryClient.invalidateQueries(branchQueryKey(repository, "details"));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
37
53
|
// we do not populate the cache for a single branch,
|
|
38
54
|
// because we have no pagination for branches and if we have a lot of them
|
|
39
55
|
// the population slows us down
|
|
@@ -43,22 +59,99 @@ export const useBranches = (repository: Repository): ApiResult<BranchCollection>
|
|
|
43
59
|
export const useBranch = (repository: Repository, name: string): ApiResultWithFetching<Branch> => {
|
|
44
60
|
const link = requiredLink(repository, "branches");
|
|
45
61
|
return useQuery<Branch, Error>(branchQueryKey(repository, name), () =>
|
|
46
|
-
apiClient.get(concat(link, encodeURIComponent(name))).then(
|
|
62
|
+
apiClient.get(concat(link, encodeURIComponent(name))).then(response => response.json())
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function chunkBranches(branches: Branch[]) {
|
|
67
|
+
const chunks: Branch[][] = [];
|
|
68
|
+
const chunkSize = 5;
|
|
69
|
+
let chunkIndex = 0;
|
|
70
|
+
for (const branch of branches) {
|
|
71
|
+
if (!chunks[chunkIndex]) {
|
|
72
|
+
chunks[chunkIndex] = [];
|
|
73
|
+
}
|
|
74
|
+
chunks[chunkIndex].push(branch);
|
|
75
|
+
if (chunks[chunkIndex].length >= chunkSize) {
|
|
76
|
+
chunkIndex = chunkIndex + 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return chunks;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const branchDetailsQueryKey = (
|
|
83
|
+
repository: NamespaceAndName,
|
|
84
|
+
branch: string | undefined = undefined
|
|
85
|
+
) => {
|
|
86
|
+
let branchName;
|
|
87
|
+
if (!branch) {
|
|
88
|
+
branchName = "_";
|
|
89
|
+
} else {
|
|
90
|
+
branchName = branch;
|
|
91
|
+
}
|
|
92
|
+
return [...repoQueryKey(repository), "branch-details", branchName];
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const useBranchDetailsCollection = (repository: Repository, branches: Branch[]) => {
|
|
96
|
+
const link = requiredLink(repository, "branchDetailsCollection");
|
|
97
|
+
const chunks = chunkBranches(branches);
|
|
98
|
+
const queryClient = useQueryClient();
|
|
99
|
+
|
|
100
|
+
const { data, isLoading, error, fetchNextPage } = useInfiniteQuery<
|
|
101
|
+
BranchDetailsCollection,
|
|
102
|
+
Error,
|
|
103
|
+
BranchDetailsCollection
|
|
104
|
+
>(
|
|
105
|
+
branchDetailsQueryKey(repository),
|
|
106
|
+
({ pageParam = 0 }) => {
|
|
107
|
+
const encodedBranches = chunks[pageParam]?.map(b => encodeURIComponent(b.name)).join("&branches=");
|
|
108
|
+
return apiClient.get(concat(link, `?branches=${encodedBranches}`)).then(response => response.json());
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
112
|
+
if (allPages.length >= chunks.length) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return allPages.length;
|
|
116
|
+
},
|
|
117
|
+
onSuccess: newData => {
|
|
118
|
+
newData.pages
|
|
119
|
+
.flatMap(d => d._embedded?.branchDetails)
|
|
120
|
+
.filter(d => !!d)
|
|
121
|
+
.forEach(d => queryClient.setQueryData(branchDetailsQueryKey(repository, d!.branchName), () => d));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
47
124
|
);
|
|
125
|
+
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
fetchNextPage();
|
|
128
|
+
}, [data, fetchNextPage]);
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
data: data?.pages?.map(d => d._embedded?.branchDetails).flat(1),
|
|
132
|
+
isLoading,
|
|
133
|
+
error
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const useBranchDetails = (repository: Repository, branch: Branch) => {
|
|
138
|
+
const link = (branch._links.details as Link).href;
|
|
139
|
+
const queryKey = branchDetailsQueryKey(repository, branch.name);
|
|
140
|
+
return useQuery<BranchDetails, Error>(queryKey, () => apiClient.get(link).then(response => response.json()));
|
|
48
141
|
};
|
|
49
142
|
|
|
50
143
|
const createBranch = (link: string) => {
|
|
51
144
|
return (branch: BranchCreation) => {
|
|
52
145
|
return apiClient
|
|
53
146
|
.post(link, branch, "application/vnd.scmm-branchRequest+json;v=2")
|
|
54
|
-
.then(
|
|
147
|
+
.then(response => {
|
|
55
148
|
const location = response.headers.get("Location");
|
|
56
149
|
if (!location) {
|
|
57
150
|
throw new Error("Server does not return required Location header");
|
|
58
151
|
}
|
|
59
152
|
return apiClient.get(location);
|
|
60
153
|
})
|
|
61
|
-
.then(
|
|
154
|
+
.then(response => response.json());
|
|
62
155
|
};
|
|
63
156
|
};
|
|
64
157
|
|
|
@@ -66,23 +159,23 @@ export const useCreateBranch = (repository: Repository) => {
|
|
|
66
159
|
const queryClient = useQueryClient();
|
|
67
160
|
const link = requiredLink(repository, "branches");
|
|
68
161
|
const { mutate, isLoading, error, data } = useMutation<Branch, Error, BranchCreation>(createBranch(link), {
|
|
69
|
-
onSuccess: async
|
|
162
|
+
onSuccess: async branch => {
|
|
70
163
|
queryClient.setQueryData(branchQueryKey(repository, branch), branch);
|
|
71
164
|
await queryClient.invalidateQueries(repoQueryKey(repository, "branches"));
|
|
72
|
-
}
|
|
165
|
+
}
|
|
73
166
|
});
|
|
74
167
|
return {
|
|
75
168
|
create: (branch: BranchCreation) => mutate(branch),
|
|
76
169
|
isLoading,
|
|
77
170
|
error,
|
|
78
|
-
branch: data
|
|
171
|
+
branch: data
|
|
79
172
|
};
|
|
80
173
|
};
|
|
81
174
|
|
|
82
175
|
export const useDeleteBranch = (repository: Repository) => {
|
|
83
176
|
const queryClient = useQueryClient();
|
|
84
177
|
const { mutate, isLoading, error, data } = useMutation<unknown, Error, Branch>(
|
|
85
|
-
|
|
178
|
+
branch => {
|
|
86
179
|
const deleteUrl = (branch._links.delete as Link).href;
|
|
87
180
|
return apiClient.delete(deleteUrl);
|
|
88
181
|
},
|
|
@@ -90,14 +183,14 @@ export const useDeleteBranch = (repository: Repository) => {
|
|
|
90
183
|
onSuccess: async (_, branch) => {
|
|
91
184
|
queryClient.removeQueries(branchQueryKey(repository, branch));
|
|
92
185
|
await queryClient.invalidateQueries(repoQueryKey(repository, "branches"));
|
|
93
|
-
}
|
|
186
|
+
}
|
|
94
187
|
}
|
|
95
188
|
);
|
|
96
189
|
return {
|
|
97
190
|
remove: (branch: Branch) => mutate(branch),
|
|
98
191
|
isLoading,
|
|
99
192
|
error,
|
|
100
|
-
isDeleted: !!data
|
|
193
|
+
isDeleted: !!data
|
|
101
194
|
};
|
|
102
195
|
};
|
|
103
196
|
|
|
@@ -106,6 +199,6 @@ type DefaultBranch = { defaultBranch: string };
|
|
|
106
199
|
export const useDefaultBranch = (repository: Repository): ApiResult<DefaultBranch> => {
|
|
107
200
|
const link = requiredLink(repository, "defaultBranch");
|
|
108
201
|
return useQuery<DefaultBranch, Error>(branchQueryKey(repository, "__default-branch"), () =>
|
|
109
|
-
apiClient.get(link).then(
|
|
202
|
+
apiClient.get(link).then(response => response.json())
|
|
110
203
|
);
|
|
111
204
|
};
|
package/src/changesets.test.ts
CHANGED
|
@@ -35,19 +35,20 @@ describe("Test changeset hooks", () => {
|
|
|
35
35
|
type: "hg",
|
|
36
36
|
_links: {
|
|
37
37
|
changesets: {
|
|
38
|
-
href: "/r/c"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
38
|
+
href: "/r/c"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
const develop: Branch = {
|
|
44
44
|
name: "develop",
|
|
45
45
|
revision: "42",
|
|
46
|
+
lastCommitter: { name: "trillian" },
|
|
46
47
|
_links: {
|
|
47
48
|
history: {
|
|
48
|
-
href: "/r/b/c"
|
|
49
|
-
}
|
|
50
|
-
}
|
|
49
|
+
href: "/r/b/c"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
const changeset: Changeset = {
|
|
@@ -55,19 +56,19 @@ describe("Test changeset hooks", () => {
|
|
|
55
56
|
description: "Awesome change",
|
|
56
57
|
date: new Date(),
|
|
57
58
|
author: {
|
|
58
|
-
name: "Arthur Dent"
|
|
59
|
+
name: "Arthur Dent"
|
|
59
60
|
},
|
|
60
61
|
_embedded: {},
|
|
61
|
-
_links: {}
|
|
62
|
+
_links: {}
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
const changesets: ChangesetCollection = {
|
|
65
66
|
page: 1,
|
|
66
67
|
pageTotal: 1,
|
|
67
68
|
_embedded: {
|
|
68
|
-
changesets: [changeset]
|
|
69
|
+
changesets: [changeset]
|
|
69
70
|
},
|
|
70
|
-
_links: {}
|
|
71
|
+
_links: {}
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
const expectChangesetCollection = (result?: ChangesetCollection) => {
|
|
@@ -85,7 +86,7 @@ describe("Test changeset hooks", () => {
|
|
|
85
86
|
const queryClient = createInfiniteCachingClient();
|
|
86
87
|
|
|
87
88
|
const { result, waitFor } = renderHook(() => useChangesets(repository), {
|
|
88
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
89
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
89
90
|
});
|
|
90
91
|
|
|
91
92
|
await waitFor(() => {
|
|
@@ -98,14 +99,14 @@ describe("Test changeset hooks", () => {
|
|
|
98
99
|
it("should return changesets for page", async () => {
|
|
99
100
|
fetchMock.getOnce("/api/v2/r/c", changesets, {
|
|
100
101
|
query: {
|
|
101
|
-
page: 42
|
|
102
|
-
}
|
|
102
|
+
page: 42
|
|
103
|
+
}
|
|
103
104
|
});
|
|
104
105
|
|
|
105
106
|
const queryClient = createInfiniteCachingClient();
|
|
106
107
|
|
|
107
108
|
const { result, waitFor } = renderHook(() => useChangesets(repository, { page: 42 }), {
|
|
108
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
109
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
109
110
|
});
|
|
110
111
|
|
|
111
112
|
await waitFor(() => {
|
|
@@ -121,7 +122,7 @@ describe("Test changeset hooks", () => {
|
|
|
121
122
|
const queryClient = createInfiniteCachingClient();
|
|
122
123
|
|
|
123
124
|
const { result, waitFor } = renderHook(() => useChangesets(repository, { branch: develop }), {
|
|
124
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
125
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
125
126
|
});
|
|
126
127
|
|
|
127
128
|
await waitFor(() => {
|
|
@@ -137,7 +138,7 @@ describe("Test changeset hooks", () => {
|
|
|
137
138
|
const queryClient = createInfiniteCachingClient();
|
|
138
139
|
|
|
139
140
|
const { result, waitFor } = renderHook(() => useChangesets(repository), {
|
|
140
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
141
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
141
142
|
});
|
|
142
143
|
|
|
143
144
|
await waitFor(() => {
|
|
@@ -149,7 +150,7 @@ describe("Test changeset hooks", () => {
|
|
|
149
150
|
"hitchhiker",
|
|
150
151
|
"heart-of-gold",
|
|
151
152
|
"changeset",
|
|
152
|
-
"42"
|
|
153
|
+
"42"
|
|
153
154
|
]);
|
|
154
155
|
|
|
155
156
|
expect(changeset?.id).toBe("42");
|
|
@@ -163,7 +164,7 @@ describe("Test changeset hooks", () => {
|
|
|
163
164
|
const queryClient = createInfiniteCachingClient();
|
|
164
165
|
|
|
165
166
|
const { result, waitFor } = renderHook(() => useChangeset(repository, "42"), {
|
|
166
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
167
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
167
168
|
});
|
|
168
169
|
|
|
169
170
|
await waitFor(() => {
|
package/src/config.test.ts
CHANGED
package/src/contentType.ts
CHANGED
|
@@ -28,6 +28,9 @@ import { ApiResultWithFetching } from "./base";
|
|
|
28
28
|
export type ContentType = {
|
|
29
29
|
type: string;
|
|
30
30
|
language?: string;
|
|
31
|
+
aceMode?: string;
|
|
32
|
+
codemirrorMode?: string;
|
|
33
|
+
prismMode?: string;
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
function getContentType(url: string): Promise<ContentType> {
|
|
@@ -35,6 +38,9 @@ function getContentType(url: string): Promise<ContentType> {
|
|
|
35
38
|
return {
|
|
36
39
|
type: response.headers.get("Content-Type") || "application/octet-stream",
|
|
37
40
|
language: response.headers.get("X-Programming-Language") || undefined,
|
|
41
|
+
aceMode: response.headers.get("X-Syntax-Mode-Ace") || undefined,
|
|
42
|
+
codemirrorMode: response.headers.get("X-Syntax-Mode-Codemirror") || undefined,
|
|
43
|
+
prismMode: response.headers.get("X-Syntax-Mode-Prism") || undefined,
|
|
38
44
|
};
|
|
39
45
|
});
|
|
40
46
|
}
|
package/src/import.ts
CHANGED
|
@@ -30,12 +30,12 @@ import { requiredLink } from "./links";
|
|
|
30
30
|
|
|
31
31
|
export const useImportLog = (logId: string): ApiResult<string> => {
|
|
32
32
|
const link = useRequiredIndexLink("importLog").replace("{logId}", logId);
|
|
33
|
-
return useQuery<string, Error>(["importLog", logId], () => apiClient.get(link).then(
|
|
33
|
+
return useQuery<string, Error>(["importLog", logId], () => apiClient.get(link).then(response => response.text()));
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export const useImportRepositoryFromUrl = (repositoryType: RepositoryType) => {
|
|
37
37
|
const url = requiredLink(repositoryType, "import", "url");
|
|
38
|
-
const { isLoading, error, data, mutate } = useMutation<Repository, Error, RepositoryUrlImport>(
|
|
38
|
+
const { isLoading, error, data, mutate } = useMutation<Repository, Error, RepositoryUrlImport>(repo =>
|
|
39
39
|
apiClient
|
|
40
40
|
.post(url, repo, "application/vnd.scmm-repository+json;v=2")
|
|
41
41
|
.then(fetchResourceFromLocationHeader)
|
|
@@ -46,14 +46,14 @@ export const useImportRepositoryFromUrl = (repositoryType: RepositoryType) => {
|
|
|
46
46
|
isLoading,
|
|
47
47
|
error,
|
|
48
48
|
importRepositoryFromUrl: (repository: RepositoryUrlImport) => mutate(repository),
|
|
49
|
-
importedRepository: data
|
|
49
|
+
importedRepository: data
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
const importRepository = (url: string, repository: RepositoryCreation, file: File, password?: string) => {
|
|
54
54
|
return apiClient
|
|
55
|
-
.postBinary(url,
|
|
56
|
-
formData.append("bundle", file, file
|
|
55
|
+
.postBinary(url, formData => {
|
|
56
|
+
formData.append("bundle", file, file.name);
|
|
57
57
|
formData.append("repository", JSON.stringify({ ...repository, password }));
|
|
58
58
|
})
|
|
59
59
|
.then(fetchResourceFromLocationHeader)
|
|
@@ -82,9 +82,9 @@ export const useImportRepositoryFromBundle = (repositoryType: RepositoryType) =>
|
|
|
82
82
|
repository,
|
|
83
83
|
file,
|
|
84
84
|
compressed,
|
|
85
|
-
password
|
|
85
|
+
password
|
|
86
86
|
}),
|
|
87
|
-
importedRepository: data
|
|
87
|
+
importedRepository: data
|
|
88
88
|
};
|
|
89
89
|
};
|
|
90
90
|
|
|
@@ -107,8 +107,8 @@ export const useImportFullRepository = (repositoryType: RepositoryType) => {
|
|
|
107
107
|
mutate({
|
|
108
108
|
repository,
|
|
109
109
|
file,
|
|
110
|
-
password
|
|
110
|
+
password
|
|
111
111
|
}),
|
|
112
|
-
importedRepository: data
|
|
112
|
+
importedRepository: data
|
|
113
113
|
};
|
|
114
114
|
};
|
package/src/index.ts
CHANGED
|
@@ -58,6 +58,8 @@ export * from "./history";
|
|
|
58
58
|
export * from "./contentType";
|
|
59
59
|
export * from "./annotations";
|
|
60
60
|
export * from "./search";
|
|
61
|
+
export * from "./loginInfo";
|
|
62
|
+
export * from "./usePluginCenterAuthInfo";
|
|
61
63
|
|
|
62
64
|
export { default as ApiProvider } from "./ApiProvider";
|
|
63
65
|
export * from "./ApiProvider";
|
package/src/loginInfo.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
import { ApiResult, useIndexLink } from "./base";
|
|
25
|
+
import { useQuery } from "react-query";
|
|
26
|
+
import { LoginInfo } from "@scm-manager/ui-types";
|
|
27
|
+
|
|
28
|
+
export const useLoginInfo = (disabled = false): ApiResult<LoginInfo> => {
|
|
29
|
+
const loginInfoLink = useIndexLink("loginInfo");
|
|
30
|
+
const { error, isLoading, data } = useQuery<LoginInfo, Error>(
|
|
31
|
+
["loginInfo"],
|
|
32
|
+
() => fetch(loginInfoLink!).then(response => response.json()),
|
|
33
|
+
{
|
|
34
|
+
enabled: !disabled && !!loginInfoLink,
|
|
35
|
+
refetchOnWindowFocus: false
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
return {
|
|
39
|
+
data,
|
|
40
|
+
error,
|
|
41
|
+
isLoading
|
|
42
|
+
};
|
|
43
|
+
};
|
package/src/repositories.test.ts
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
useRepository,
|
|
38
38
|
useRepositoryTypes,
|
|
39
39
|
useUnarchiveRepository,
|
|
40
|
-
useUpdateRepository
|
|
40
|
+
useUpdateRepository
|
|
41
41
|
} from "./repositories";
|
|
42
42
|
import { Repository } from "@scm-manager/ui-types";
|
|
43
43
|
import { QueryClient } from "react-query";
|
|
@@ -50,25 +50,25 @@ describe("Test repository hooks", () => {
|
|
|
50
50
|
type: "git",
|
|
51
51
|
_links: {
|
|
52
52
|
delete: {
|
|
53
|
-
href: "/r/spaceships/heartOfGold"
|
|
53
|
+
href: "/r/spaceships/heartOfGold"
|
|
54
54
|
},
|
|
55
55
|
update: {
|
|
56
|
-
href: "/r/spaceships/heartOfGold"
|
|
56
|
+
href: "/r/spaceships/heartOfGold"
|
|
57
57
|
},
|
|
58
58
|
archive: {
|
|
59
|
-
href: "/r/spaceships/heartOfGold/archive"
|
|
59
|
+
href: "/r/spaceships/heartOfGold/archive"
|
|
60
60
|
},
|
|
61
61
|
unarchive: {
|
|
62
|
-
href: "/r/spaceships/heartOfGold/unarchive"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
62
|
+
href: "/r/spaceships/heartOfGold/unarchive"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
const repositoryCollection = {
|
|
68
68
|
_embedded: {
|
|
69
|
-
repositories: [heartOfGold]
|
|
69
|
+
repositories: [heartOfGold]
|
|
70
70
|
},
|
|
71
|
-
_links: {}
|
|
71
|
+
_links: {}
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
afterEach(() => {
|
|
@@ -78,7 +78,7 @@ describe("Test repository hooks", () => {
|
|
|
78
78
|
describe("useRepositories tests", () => {
|
|
79
79
|
const expectCollection = async (queryClient: QueryClient, request?: UseRepositoriesRequest) => {
|
|
80
80
|
const { result, waitFor } = renderHook(() => useRepositories(request), {
|
|
81
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
81
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
82
82
|
});
|
|
83
83
|
await waitFor(() => {
|
|
84
84
|
return !!result.current.data;
|
|
@@ -91,8 +91,8 @@ describe("Test repository hooks", () => {
|
|
|
91
91
|
setIndexLink(queryClient, "repositories", "/repos");
|
|
92
92
|
fetchMock.get("/api/v2/repos", repositoryCollection, {
|
|
93
93
|
query: {
|
|
94
|
-
sortBy: "namespaceAndName"
|
|
95
|
-
}
|
|
94
|
+
sortBy: "namespaceAndName"
|
|
95
|
+
}
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
await expectCollection(queryClient);
|
|
@@ -104,12 +104,12 @@ describe("Test repository hooks", () => {
|
|
|
104
104
|
fetchMock.get("/api/v2/repos", repositoryCollection, {
|
|
105
105
|
query: {
|
|
106
106
|
sortBy: "namespaceAndName",
|
|
107
|
-
page: "42"
|
|
108
|
-
}
|
|
107
|
+
page: "42"
|
|
108
|
+
}
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
await expectCollection(queryClient, {
|
|
112
|
-
page: 42
|
|
112
|
+
page: 42
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
|
|
@@ -118,8 +118,8 @@ describe("Test repository hooks", () => {
|
|
|
118
118
|
setIndexLink(queryClient, "repositories", "/repos");
|
|
119
119
|
fetchMock.get("/api/v2/spaceships", repositoryCollection, {
|
|
120
120
|
query: {
|
|
121
|
-
sortBy: "namespaceAndName"
|
|
122
|
-
}
|
|
121
|
+
sortBy: "namespaceAndName"
|
|
122
|
+
}
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
await expectCollection(queryClient, {
|
|
@@ -127,10 +127,10 @@ describe("Test repository hooks", () => {
|
|
|
127
127
|
namespace: "spaceships",
|
|
128
128
|
_links: {
|
|
129
129
|
repositories: {
|
|
130
|
-
href: "/spaceships"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
130
|
+
href: "/spaceships"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
136
|
|
|
@@ -140,12 +140,12 @@ describe("Test repository hooks", () => {
|
|
|
140
140
|
fetchMock.get("/api/v2/repos", repositoryCollection, {
|
|
141
141
|
query: {
|
|
142
142
|
sortBy: "namespaceAndName",
|
|
143
|
-
q: "heart"
|
|
144
|
-
}
|
|
143
|
+
q: "heart"
|
|
144
|
+
}
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
await expectCollection(queryClient, {
|
|
148
|
-
search: "heart"
|
|
148
|
+
search: "heart"
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
|
|
@@ -154,8 +154,8 @@ describe("Test repository hooks", () => {
|
|
|
154
154
|
setIndexLink(queryClient, "repositories", "/repos");
|
|
155
155
|
fetchMock.get("/api/v2/repos", repositoryCollection, {
|
|
156
156
|
query: {
|
|
157
|
-
sortBy: "namespaceAndName"
|
|
158
|
-
}
|
|
157
|
+
sortBy: "namespaceAndName"
|
|
158
|
+
}
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
await expectCollection(queryClient);
|
|
@@ -168,7 +168,7 @@ describe("Test repository hooks", () => {
|
|
|
168
168
|
const queryClient = createInfiniteCachingClient();
|
|
169
169
|
setIndexLink(queryClient, "repositories", "/repos");
|
|
170
170
|
const { result } = renderHook(() => useRepositories({ disabled: true }), {
|
|
171
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
171
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -185,19 +185,18 @@ describe("Test repository hooks", () => {
|
|
|
185
185
|
fetchMock.postOnce("/api/v2/r", {
|
|
186
186
|
status: 201,
|
|
187
187
|
headers: {
|
|
188
|
-
Location: "/r/spaceships/heartOfGold"
|
|
189
|
-
}
|
|
188
|
+
Location: "/r/spaceships/heartOfGold"
|
|
189
|
+
}
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
fetchMock.getOnce("/api/v2/r/spaceships/heartOfGold", heartOfGold);
|
|
193
193
|
|
|
194
194
|
const { result, waitForNextUpdate } = renderHook(() => useCreateRepository(), {
|
|
195
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
195
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
const repository = {
|
|
199
|
-
...heartOfGold
|
|
200
|
-
contextEntries: [],
|
|
199
|
+
...heartOfGold
|
|
201
200
|
};
|
|
202
201
|
|
|
203
202
|
await act(() => {
|
|
@@ -216,19 +215,18 @@ describe("Test repository hooks", () => {
|
|
|
216
215
|
fetchMock.postOnce("/api/v2/r?initialize=true", {
|
|
217
216
|
status: 201,
|
|
218
217
|
headers: {
|
|
219
|
-
Location: "/r/spaceships/heartOfGold"
|
|
220
|
-
}
|
|
218
|
+
Location: "/r/spaceships/heartOfGold"
|
|
219
|
+
}
|
|
221
220
|
});
|
|
222
221
|
|
|
223
222
|
fetchMock.getOnce("/api/v2/r/spaceships/heartOfGold", heartOfGold);
|
|
224
223
|
|
|
225
224
|
const { result, waitForNextUpdate } = renderHook(() => useCreateRepository(), {
|
|
226
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
225
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
227
226
|
});
|
|
228
227
|
|
|
229
228
|
const repository = {
|
|
230
|
-
...heartOfGold
|
|
231
|
-
contextEntries: [],
|
|
229
|
+
...heartOfGold
|
|
232
230
|
};
|
|
233
231
|
|
|
234
232
|
await act(() => {
|
|
@@ -245,16 +243,15 @@ describe("Test repository hooks", () => {
|
|
|
245
243
|
setIndexLink(queryClient, "repositories", "/r");
|
|
246
244
|
|
|
247
245
|
fetchMock.postOnce("/api/v2/r", {
|
|
248
|
-
status: 201
|
|
246
|
+
status: 201
|
|
249
247
|
});
|
|
250
248
|
|
|
251
249
|
const { result, waitForNextUpdate } = renderHook(() => useCreateRepository(), {
|
|
252
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
250
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
253
251
|
});
|
|
254
252
|
|
|
255
253
|
const repository = {
|
|
256
|
-
...heartOfGold
|
|
257
|
-
contextEntries: [],
|
|
254
|
+
...heartOfGold
|
|
258
255
|
};
|
|
259
256
|
|
|
260
257
|
await act(() => {
|
|
@@ -274,7 +271,7 @@ describe("Test repository hooks", () => {
|
|
|
274
271
|
fetchMock.get("/api/v2/r/spaceships/heartOfGold", heartOfGold);
|
|
275
272
|
|
|
276
273
|
const { result, waitFor } = renderHook(() => useRepository("spaceships", "heartOfGold"), {
|
|
277
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
274
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
278
275
|
});
|
|
279
276
|
await waitFor(() => {
|
|
280
277
|
return !!result.current.data;
|
|
@@ -293,15 +290,15 @@ describe("Test repository hooks", () => {
|
|
|
293
290
|
{
|
|
294
291
|
name: "git",
|
|
295
292
|
displayName: "Git",
|
|
296
|
-
_links: {}
|
|
297
|
-
}
|
|
298
|
-
]
|
|
293
|
+
_links: {}
|
|
294
|
+
}
|
|
295
|
+
]
|
|
299
296
|
},
|
|
300
|
-
_links: {}
|
|
297
|
+
_links: {}
|
|
301
298
|
});
|
|
302
299
|
|
|
303
300
|
const { result, waitFor } = renderHook(() => useRepositoryTypes(), {
|
|
304
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
301
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
305
302
|
});
|
|
306
303
|
await waitFor(() => {
|
|
307
304
|
return !!result.current.data;
|
|
@@ -322,11 +319,11 @@ describe("Test repository hooks", () => {
|
|
|
322
319
|
|
|
323
320
|
const deleteRepository = async (options?: UseDeleteRepositoryOptions) => {
|
|
324
321
|
fetchMock.deleteOnce("/api/v2/r/spaceships/heartOfGold", {
|
|
325
|
-
status: 204
|
|
322
|
+
status: 204
|
|
326
323
|
});
|
|
327
324
|
|
|
328
325
|
const { result, waitForNextUpdate } = renderHook(() => useDeleteRepository(options), {
|
|
329
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
326
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
330
327
|
});
|
|
331
328
|
|
|
332
329
|
await act(() => {
|
|
@@ -371,9 +368,9 @@ describe("Test repository hooks", () => {
|
|
|
371
368
|
it("should call onSuccess callback", async () => {
|
|
372
369
|
let repo;
|
|
373
370
|
await deleteRepository({
|
|
374
|
-
onSuccess:
|
|
371
|
+
onSuccess: repository => {
|
|
375
372
|
repo = repository;
|
|
376
|
-
}
|
|
373
|
+
}
|
|
377
374
|
});
|
|
378
375
|
expect(repo).toEqual(heartOfGold);
|
|
379
376
|
});
|
|
@@ -388,11 +385,11 @@ describe("Test repository hooks", () => {
|
|
|
388
385
|
|
|
389
386
|
const updateRepository = async () => {
|
|
390
387
|
fetchMock.putOnce("/api/v2/r/spaceships/heartOfGold", {
|
|
391
|
-
status: 204
|
|
388
|
+
status: 204
|
|
392
389
|
});
|
|
393
390
|
|
|
394
391
|
const { result, waitForNextUpdate } = renderHook(() => useUpdateRepository(), {
|
|
395
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
392
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
396
393
|
});
|
|
397
394
|
|
|
398
395
|
await act(() => {
|
|
@@ -436,11 +433,11 @@ describe("Test repository hooks", () => {
|
|
|
436
433
|
|
|
437
434
|
const archiveRepository = async () => {
|
|
438
435
|
fetchMock.postOnce("/api/v2/r/spaceships/heartOfGold/archive", {
|
|
439
|
-
status: 204
|
|
436
|
+
status: 204
|
|
440
437
|
});
|
|
441
438
|
|
|
442
439
|
const { result, waitForNextUpdate } = renderHook(() => useArchiveRepository(), {
|
|
443
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
440
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
444
441
|
});
|
|
445
442
|
|
|
446
443
|
await act(() => {
|
|
@@ -484,11 +481,11 @@ describe("Test repository hooks", () => {
|
|
|
484
481
|
|
|
485
482
|
const unarchiveRepository = async () => {
|
|
486
483
|
fetchMock.postOnce("/api/v2/r/spaceships/heartOfGold/unarchive", {
|
|
487
|
-
status: 204
|
|
484
|
+
status: 204
|
|
488
485
|
});
|
|
489
486
|
|
|
490
487
|
const { result, waitForNextUpdate } = renderHook(() => useUnarchiveRepository(), {
|
|
491
|
-
wrapper: createWrapper(undefined, queryClient)
|
|
488
|
+
wrapper: createWrapper(undefined, queryClient)
|
|
492
489
|
});
|
|
493
490
|
|
|
494
491
|
await act(() => {
|
package/src/urls.ts
CHANGED
|
@@ -84,8 +84,13 @@ function parsePageNumber(pageAsString: string) {
|
|
|
84
84
|
return page;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export function getQueryStringFromLocation(location:
|
|
88
|
-
|
|
87
|
+
export function getQueryStringFromLocation(location: { search?: string }): string | undefined {
|
|
88
|
+
if (location.search) {
|
|
89
|
+
const query = queryString.parse(location.search).q;
|
|
90
|
+
if (query && !Array.isArray(query)) {
|
|
91
|
+
return query;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
export function stripEndingSlash(url: string) {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { ApiResult, useIndexLink } from "./base";
|
|
26
|
+
import { Link, PluginCenterAuthenticationInfo } from "@scm-manager/ui-types";
|
|
27
|
+
import { useMutation, useQuery, useQueryClient } from "react-query";
|
|
28
|
+
import { apiClient } from "./apiclient";
|
|
29
|
+
import { useLocation } from "react-router-dom";
|
|
30
|
+
|
|
31
|
+
export const usePluginCenterAuthInfo = (): ApiResult<PluginCenterAuthenticationInfo> => {
|
|
32
|
+
const link = useIndexLink("pluginCenterAuth");
|
|
33
|
+
const location = useLocation();
|
|
34
|
+
return useQuery<PluginCenterAuthenticationInfo, Error>(
|
|
35
|
+
["pluginCenterAuth"],
|
|
36
|
+
() => {
|
|
37
|
+
if (!link) {
|
|
38
|
+
throw new Error("no such plugin center auth link");
|
|
39
|
+
}
|
|
40
|
+
return apiClient
|
|
41
|
+
.get(link)
|
|
42
|
+
.then(response => response.json())
|
|
43
|
+
.then((result: PluginCenterAuthenticationInfo) => {
|
|
44
|
+
if (result._links?.login) {
|
|
45
|
+
(result._links.login as Link).href += `?source=${location.pathname}`;
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
enabled: !!link
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const usePluginCenterLogout = (authenticationInfo: PluginCenterAuthenticationInfo) => {
|
|
57
|
+
const queryClient = useQueryClient();
|
|
58
|
+
const { mutate, isLoading, error } = useMutation<unknown, Error>(
|
|
59
|
+
() => {
|
|
60
|
+
if (!authenticationInfo._links.logout) {
|
|
61
|
+
throw new Error("authenticationInfo has no logout link");
|
|
62
|
+
}
|
|
63
|
+
const logout = authenticationInfo._links.logout as Link;
|
|
64
|
+
return apiClient.delete(logout.href);
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
onSuccess: () => queryClient.invalidateQueries("pluginCenterAuth")
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
logout: () => {
|
|
73
|
+
mutate();
|
|
74
|
+
},
|
|
75
|
+
isLoading,
|
|
76
|
+
error
|
|
77
|
+
};
|
|
78
|
+
};
|