diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts
index b132b6a208..f7645ab760 100644
--- a/plugins/circleci/src/api/index.ts
+++ b/plugins/circleci/src/api/index.ts
@@ -45,14 +45,21 @@ export class CircleCIApi {
}
async getBuilds(options: CircleCIOptions) {
- return getBuildSummaries(options.token, { vcs: {}, ...options });
+ return getBuildSummaries(options.token, {
+ vcs: {},
+ circleHost: this.apiUrl,
+ ...options,
+ });
}
async getUser(options: CircleCIOptions) {
- return getMe(options.token, options);
+ return getMe(options.token, { circleHost: this.apiUrl, ...options });
}
async getBuild(buildNumber: number, options: CircleCIOptions) {
- return getFullBuild(options.token, buildNumber, options);
+ return getFullBuild(options.token, buildNumber, {
+ circleHost: this.apiUrl,
+ ...options,
+ });
}
}
diff --git a/plugins/circleci/src/components/App.tsx b/plugins/circleci/src/components/App.tsx
index 2dc92ea574..799016130f 100644
--- a/plugins/circleci/src/components/App.tsx
+++ b/plugins/circleci/src/components/App.tsx
@@ -1,17 +1,31 @@
-import { Route } from 'react-router';
+import { Route, Switch } from 'react-router';
import React from 'react';
-// import { BuildsPage } from 'pages/BuildsPage';
+import { BuildsPage } from 'pages/BuildsPage';
// import { DetailedViewPage } from 'pages/DetailedViewPage';
import { SettingsPage } from 'pages/SettingsPage';
-import { Provider } from 'react-redux';
-import store from 'state/store';
+import { Provider, useDispatch } from 'react-redux';
+import store, { Dispatch } from 'state/store';
+
+const RehydrateSettings = () => {
+ const dispatch: Dispatch = useDispatch();
+
+ React.useEffect(() => {
+ dispatch.settings.rehydrate();
+ }, []);
+ return null;
+};
export const App = () => {
return (
- {/*
- */}
-
+ <>
+
+
+
+
+
+ >
+ {/* */}
);
};
diff --git a/plugins/circleci/src/components/CircleCIFetch/CirleCIFetch.tsx b/plugins/circleci/src/components/CircleCIFetch/CirleCIFetch.tsx
index abd4b2c363..68358dccd6 100644
--- a/plugins/circleci/src/components/CircleCIFetch/CirleCIFetch.tsx
+++ b/plugins/circleci/src/components/CircleCIFetch/CirleCIFetch.tsx
@@ -22,9 +22,10 @@ import React, { FC } from 'react';
import { BuildSummary } from 'circleci-api';
import { CITable, CITableBuildInfo } from '../CITable';
-import { circleCIApiRef } from 'api';
+import { useSelector, useDispatch } from 'react-redux';
+import { iRootState, Dispatch } from 'state/store';
import { useApi } from '@backstage/core';
-
+import { circleCIApiRef } from 'api';
// "lifecycle" : "finished", // :queued, :scheduled, :not_run, :not_running, :running or :finished
// "outcome" : "failed", // :canceled, :infrastructure_fail, :timedout, :failed, :no_tests or :success
@@ -47,10 +48,7 @@ const makeReadableStatus = (status: string | undefined) => {
} as Record)[status];
};
-const transform = (
- buildsData: BuildSummary[],
- api: typeof circleCIApiRef.T,
-): CITableBuildInfo[] => {
+const transform = (buildsData: BuildSummary[]): CITableBuildInfo[] => {
return buildsData.map((buildData) => {
const tableBuildInfo: CITableBuildInfo = {
id: String(buildData.build_num),
@@ -58,7 +56,7 @@ const transform = (
? buildData.subject +
(buildData.retry_of ? ` (retry of #${buildData.retry_of})` : '')
: '',
- onRetryClick: () => api.retry(String(buildData.build_num)),
+ onRetryClick: () => {}, //api.retry(String(buildData.build_num)),
source: {
branchName: String(buildData.branch),
commit: {
@@ -81,35 +79,17 @@ const transform = (
};
export const CircleCIFetch: FC<{}> = () => {
- const [authed, setAuthed] = React.useState(false);
- const [builds, setBuilds] = React.useState([]);
+ const dispatch: Dispatch = useDispatch();
const api = useApi(circleCIApiRef);
React.useEffect(() => {
- const intervalId = setInterval(async () => {
- if (!authed) {
- await api.restorePersistedSettings();
- await api
- .validateToken()
- .then(() => {
- setAuthed(true);
- })
- .catch(() => setAuthed(false));
- }
- api.getBuilds().then(setBuilds);
- }, 1500);
- return () => clearInterval(intervalId);
- }, [authed]);
+ dispatch.builds.startPolling(api);
+ return () => {
+ dispatch.builds.stopPolling();
+ };
+ }, []);
+ const { builds } = useSelector((state: iRootState) => state.builds);
+ const transformedBuilds = transform(builds);
- if (!authed) return Not authenticated
;
- const transformedBuilds = transform(builds || [], api);
- return (
- <>
- {!api.authed ? (
- Not authenticated
- ) : (
-
- )}
- >
- );
+ return ;
};
diff --git a/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx b/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx
index 3d9e14f6c6..cd68577d3b 100644
--- a/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx
+++ b/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx
@@ -20,20 +20,20 @@ export const SettingsPage = () => {
token: tokenFromStore,
owner: ownerFromStore,
repo: repoFromStore,
- } = useSelector((state: iRootState): SettingsState => state.settings);
+ } = useSelector(
+ (state: iRootState): SettingsState =>
+ (console.log({ state }) as any) || state.settings,
+ );
- const dispatch: Dispatch = useDispatch();
- // const api = useApi(circleCIApiRef);
// const apiGitInfo = api.options.vcs;
// const [authed] = React.useState(false);
- const [token, setToken] = React.useState('');
- const [owner, setOwner] = React.useState('');
- const [repo, setRepo] = React.useState('');
+ const [token, setToken] = React.useState(() => tokenFromStore);
+ const [owner, setOwner] = React.useState(() => ownerFromStore);
+ const [repo, setRepo] = React.useState(() => repoFromStore);
- React.useEffect(() => {
- dispatch.settings.rehydrate();
- }, []);
+ const dispatch: Dispatch = useDispatch();
+ React.useEffect(() => () => console.log('Settings unmounterd'), []);
React.useEffect(() => {
if (tokenFromStore !== token) {
setToken(tokenFromStore);
@@ -71,7 +71,7 @@ export const SettingsPage = () => {
name="circleci-token"
label="Token"
value={token}
- onChange={e => setToken(e.target.value)}
+ onChange={(e) => setToken(e.target.value)}
/>
@@ -79,7 +79,7 @@ export const SettingsPage = () => {
name="circleci-owner"
label="Owner"
value={owner}
- onChange={e => setOwner(e.target.value)}
+ onChange={(e) => setOwner(e.target.value)}
/>
@@ -87,7 +87,7 @@ export const SettingsPage = () => {
name="circleci-repo"
label="Repo"
value={repo}
- onChange={e => setRepo(e.target.value)}
+ onChange={(e) => setRepo(e.target.value)}
/>
diff --git a/plugins/circleci/src/plugin.ts b/plugins/circleci/src/plugin.ts
index 064cce93fb..77a223a162 100644
--- a/plugins/circleci/src/plugin.ts
+++ b/plugins/circleci/src/plugin.ts
@@ -19,6 +19,6 @@ import { App } from './components/App';
export const plugin = createPlugin({
id: 'circleci',
register({ router }) {
- router.registerRoute('/circleci', App);
+ router.registerRoute('/circleci', App, { exact: false });
},
});
diff --git a/plugins/circleci/src/state/models/builds.ts b/plugins/circleci/src/state/models/builds.ts
new file mode 100644
index 0000000000..71b5c4f4f2
--- /dev/null
+++ b/plugins/circleci/src/state/models/builds.ts
@@ -0,0 +1,67 @@
+import { Dispatch, iRootState } from '../store';
+import { BuildSummary, GitType } from 'circleci-api';
+import { CircleCIApi } from 'api';
+
+export type BuildsState = {
+ builds: BuildSummary[];
+ pollingIntervalId: number | null;
+ pollingState: PollingState;
+};
+
+const INTERVAL_AMOUNT = 1500;
+
+export enum PollingState {
+ Polling,
+ Idle,
+}
+export const builds = {
+ state: {
+ builds: [] as BuildSummary[],
+ pollingIntervalId: null,
+ pollingState: PollingState.Idle,
+ },
+ reducers: {
+ setBuilds(state: BuildsState, payload: BuildSummary[]) {
+ return { ...state, builds: payload };
+ },
+ setPollingIntervalId(state: BuildsState, payload: number | null) {
+ return {
+ ...state,
+ pollingIntervalId: payload,
+ pollingState:
+ payload === null ? PollingState.Idle : PollingState.Polling,
+ };
+ },
+ },
+ effects: (dispatch: Dispatch) => ({
+ async getBuilds(api: CircleCIApi, state: iRootState) {
+ try {
+ const builds = await api.getBuilds({
+ token: state.settings.token,
+ vcs: {
+ owner: state.settings.owner,
+ repo: state.settings.repo,
+ type: GitType.GITHUB,
+ },
+ });
+ dispatch.builds.setBuilds(builds);
+ } catch (e) {
+ console.log(e);
+ }
+ },
+ startPolling(api: CircleCIApi, state: iRootState) {
+ if (state.builds.pollingIntervalId) return;
+
+ const intervalId = (setInterval(
+ () => dispatch.builds.getBuilds(api),
+ INTERVAL_AMOUNT,
+ ) as any) as number;
+ dispatch.builds.setPollingIntervalId(intervalId);
+ },
+ stopPolling(_: any, state: iRootState) {
+ const currentIntervalId = state.builds.pollingIntervalId;
+ if (currentIntervalId) clearInterval(currentIntervalId);
+ dispatch.builds.setPollingIntervalId(null);
+ },
+ }),
+};
diff --git a/plugins/circleci/src/state/models/index.ts b/plugins/circleci/src/state/models/index.ts
index c02f31a6e1..39623b96f9 100644
--- a/plugins/circleci/src/state/models/index.ts
+++ b/plugins/circleci/src/state/models/index.ts
@@ -1,8 +1,13 @@
import { settings } from './settings';
+import { builds } from './builds';
// no need to extend from Models
export interface RootModel {
settings: typeof settings;
+ builds: typeof builds;
}
-export const models: RootModel = { settings };
+export const models = {
+ settings,
+ builds,
+};
diff --git a/plugins/circleci/src/state/store.ts b/plugins/circleci/src/state/store.ts
index c06c44d8e6..43b447bf9c 100644
--- a/plugins/circleci/src/state/store.ts
+++ b/plugins/circleci/src/state/store.ts
@@ -1,12 +1,6 @@
import { init, RematchRootState, RematchDispatch } from '@rematch/core';
import { models, RootModel } from './models';
-const store = init({
- models,
-});
-
-export type Store = typeof store;
export type Dispatch = RematchDispatch;
export type iRootState = RematchRootState;
-
-export default store;
+export default init({ models });