diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index d98f511f35..f683f79ff9 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -48,8 +48,15 @@ export class CircleCIApi { }); } - async getBuilds(options: CircleCIOptions) { + async getBuilds( + { limit = 10, offset = 0 }: { limit: number; offset: number }, + options: CircleCIOptions, + ) { return getBuildSummaries(options.token, { + options: { + limit, + offset, + }, vcs: {}, circleHost: this.apiUrl, ...options, diff --git a/plugins/circleci/src/components/App.tsx b/plugins/circleci/src/components/App.tsx index 3324753b88..46b70cb500 100644 --- a/plugins/circleci/src/components/App.tsx +++ b/plugins/circleci/src/components/App.tsx @@ -16,20 +16,24 @@ import React from 'react'; import { Switch, Route } from 'react-router'; import { BuildsPage } from '../pages/BuildsPage'; -import { SettingsPage } from '../pages/SettingsPage'; import { DetailedViewPage } from '../pages/BuildWithStepsPage'; import { AppStateProvider } from '../state'; +import { Settings } from './Settings'; -export const App = () => ( - - - - - - - -); +export const App = () => { + return ( + + <> + + + + + + + + ); +}; diff --git a/plugins/circleci/src/components/Layout/Layout.tsx b/plugins/circleci/src/components/Layout/Layout.tsx index eab8ab0e88..2028e1533d 100644 --- a/plugins/circleci/src/components/Layout/Layout.tsx +++ b/plugins/circleci/src/components/Layout/Layout.tsx @@ -19,20 +19,22 @@ import { Header, Page, pageTheme, HeaderLabel } from '@backstage/core'; import logo from '../../assets/circle-logo-badge-white-15.png'; import { Box } from '@material-ui/core'; -export const Layout: React.FC = ({ children }) => ( - -
- Backstage Logo - Circle CI - - } - > - - -
- {children} -
-); +export const Layout: React.FC = ({ children }) => { + return ( + +
+ Backstage Logo + Circle CI + + } + > + + +
+ {children} +
+ ); +}; diff --git a/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx b/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx index 7bd35d0805..4bab4b5921 100644 --- a/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx +++ b/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx @@ -19,9 +19,11 @@ import { ContentHeader, SupportButton } from '@backstage/core'; import { Button, IconButton, Box, Typography } from '@material-ui/core'; import ArrowBack from '@material-ui/icons/ArrowBack'; import SettingsIcon from '@material-ui/icons/Settings'; +import { useSettings } from '../../state'; export type Props = { title?: string }; export const PluginHeader: FC = ({ title = 'Circle CI' }) => { + const [, { showSettings }] = useSettings(); const location = useLocation(); const notRoot = !location.pathname.match(/\/circleci\/?$/); const isSettingsPage = location.pathname.match(/\/circleci\/settings\/?/); @@ -40,11 +42,7 @@ export const PluginHeader: FC = ({ title = 'Circle CI' }) => { )} > {!isSettingsPage && ( - )} diff --git a/plugins/circleci/src/components/Settings/Settings.tsx b/plugins/circleci/src/components/Settings/Settings.tsx new file mode 100644 index 0000000000..b33bf59dd8 --- /dev/null +++ b/plugins/circleci/src/components/Settings/Settings.tsx @@ -0,0 +1,127 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useState } from 'react'; +import { + Button, + TextField, + List, + ListItem, + Snackbar, + Box, + Dialog, + DialogTitle, +} from '@material-ui/core'; +import { Alert } from '@material-ui/lab'; +import { useSettings } from '../../state'; + +const Settings = () => { + const [ + { + repo: repoFromStore, + owner: ownerFromStore, + token: tokenFromStore, + showSettings, + }, + { saveSettings, hideSettings }, + ] = useSettings(); + + const [token, setToken] = React.useState(() => tokenFromStore); + const [owner, setOwner] = React.useState(() => ownerFromStore); + const [repo, setRepo] = React.useState(() => repoFromStore); + + React.useEffect(() => { + if (tokenFromStore !== token) { + setToken(tokenFromStore); + } + if (ownerFromStore !== owner) { + setOwner(ownerFromStore); + } + if (repoFromStore !== repo) { + setRepo(repoFromStore); + } + }, [ownerFromStore, repoFromStore, tokenFromStore]); + + const [saved, setSaved] = useState(false); + + return ( + <> + setSaved(false)} + > + Credentials saved. + + + + Project Credentials + {/* {authed ? : } */} + + + + setToken(e.target.value)} + /> + + + setOwner(e.target.value)} + /> + + + setRepo(e.target.value)} + /> + + + + + + + + + + ); +}; + +export default Settings; diff --git a/plugins/circleci/src/pages/SettingsPage/index.ts b/plugins/circleci/src/components/Settings/index.ts similarity index 91% rename from plugins/circleci/src/pages/SettingsPage/index.ts rename to plugins/circleci/src/components/Settings/index.ts index e0ba8157b2..c04ded6dea 100644 --- a/plugins/circleci/src/pages/SettingsPage/index.ts +++ b/plugins/circleci/src/components/Settings/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default as SettingsPage } from './SettingsPage'; +export { default as Settings } from './Settings'; diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx b/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx index 7dbe5ef393..0a4dfd4050 100644 --- a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx +++ b/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx @@ -15,7 +15,7 @@ */ import React, { FC, useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Content, InfoCard } from '@backstage/core'; +import { Content, InfoCard, Progress } from '@backstage/core'; import { BuildWithSteps, BuildStepAction } from '../../api'; import { Grid, Box, Link, IconButton } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; @@ -26,7 +26,7 @@ import { useBuildWithSteps, useSettings } from '../../state'; import LaunchIcon from '@material-ui/icons/Launch'; const IconLink = IconButton as typeof Link; -const BuildName: FC<{ build: BuildWithSteps | null }> = ({ build }) => ( +const BuildName: FC<{ build?: BuildWithSteps }> = ({ build }) => ( #{build?.build_num} - {build?.subject} @@ -95,7 +95,7 @@ const BuildWithStepsPage: FC<{}> = () => { const { buildId = '' } = useParams(); const classes = useStyles(); const [settings] = useSettings(); - const [build, { startPolling, stopPolling }] = useBuildWithSteps( + const [{ loading, value }, { startPolling, stopPolling }] = useBuildWithSteps( parseInt(buildId, 10), ); @@ -112,11 +112,11 @@ const BuildWithStepsPage: FC<{}> = () => { } + className={pickClassName(classes, value)} + title={} cardClassName={classes.cardContent} > - + {loading ? : } @@ -125,7 +125,7 @@ const BuildWithStepsPage: FC<{}> = () => { ); }; -const BuildsList: FC<{ build: BuildWithSteps | null }> = ({ build }) => ( +const BuildsList: FC<{ build?: BuildWithSteps }> = ({ build }) => ( {build && build.steps && diff --git a/plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx b/plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx index 41001c91dd..bed96bb24c 100644 --- a/plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx +++ b/plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx @@ -13,73 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { FC, useEffect } from 'react'; -import { CITableBuildInfo, CITable } from '../CITable'; -import { BuildSummary } from '../../../../api'; -import { useSettings, useBuilds } from '../../../../state'; - -const makeReadableStatus = (status: string | undefined) => { - if (!status) return ''; - return ({ - retried: 'Retried', - canceled: 'Canceled', - infrastructure_fail: 'Infra fail', - timedout: 'Timedout', - not_run: 'Not run', - running: 'Running', - failed: 'Failed', - queued: 'Queued', - scheduled: 'Scheduled', - not_running: 'Not running', - no_tests: 'No tests', - fixed: 'Fixed', - success: 'Success', - } as Record)[status]; -}; - -const transform = ( - buildsData: BuildSummary[], - restartBuild: { (buildId: number): Promise }, -): CITableBuildInfo[] => { - return buildsData.map((buildData) => { - const tableBuildInfo: CITableBuildInfo = { - id: String(buildData.build_num), - buildName: buildData.subject - ? buildData.subject + - (buildData.retry_of ? ` (retry of #${buildData.retry_of})` : '') - : '', - onRestartClick: () => - typeof buildData.build_num !== 'undefined' && - restartBuild(buildData.build_num), - source: { - branchName: String(buildData.branch), - commit: { - hash: String(buildData.vcs_revision), - url: 'todo', - }, - }, - status: makeReadableStatus(buildData.status), - buildUrl: buildData.build_url, - }; - return tableBuildInfo; - }); -}; +import React, { FC } from 'react'; +import { CITable } from '../CITable'; +import { useBuilds } from '../../../../state'; export const Builds: FC<{}> = () => { const [ - builds, - { restartBuild: handleRestartBuild, startPolling, stopPolling }, + { total, loading, value, projectName, page, pageSize }, + { setPage, retry, setPageSize }, ] = useBuilds(); - const [{ repo, owner }] = useSettings(); - - useEffect(() => { - startPolling(); - return () => stopPolling(); - }, [repo, owner]); - - const transformedBuilds = transform(builds, handleRestartBuild); - return ( - + ); }; diff --git a/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx b/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx index f8e0026ff5..b349dcfcbe 100644 --- a/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx @@ -114,14 +114,46 @@ const generatedColumns: TableColumn[] = [ width: '10%', }, ]; -export const CITable: FC<{ + +type Props = { + loading: boolean; + retry: () => void; builds: CITableBuildInfo[]; projectName: string; -}> = React.memo(({ builds = [], projectName }) => { + page: number; + onChangePage: (page: number) => void; + total: number; + pageSize: number; + onChangePageSize: (pageSize: number) => void; +}; +export const CITable: FC = ({ + projectName, + loading, + pageSize, + page, + retry, + builds, + onChangePage, + onChangePageSize, + total, +}) => { return ( , + tooltip: 'Refresh Data', + isFreeAction: true, + onClick: () => retry(), + }, + ]} data={builds} + onChangePage={onChangePage} + onChangeRowsPerPage={onChangePageSize} title={ @@ -132,4 +164,4 @@ export const CITable: FC<{ columns={generatedColumns} /> ); -}); +}; diff --git a/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx b/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx deleted file mode 100644 index 62b874d70e..0000000000 --- a/plugins/circleci/src/pages/SettingsPage/SettingsPage.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { useState } from 'react'; -import { - Button, - TextField, - List, - Grid, - ListItem, - Snackbar, - Box, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import { InfoCard, Content } from '@backstage/core'; -import { Layout } from '../../components/Layout'; -import { PluginHeader } from '../../components/PluginHeader'; -import { useSettings } from '../../state'; - -const SettingsPage = () => { - const [ - { repo: repoFromStore, owner: ownerFromStore, token: tokenFromStore }, - { saveSettings }, - ] = useSettings(); - - const [token, setToken] = React.useState(() => tokenFromStore); - const [owner, setOwner] = React.useState(() => ownerFromStore); - const [repo, setRepo] = React.useState(() => repoFromStore); - - React.useEffect(() => { - if (tokenFromStore !== token) { - setToken(tokenFromStore); - } - if (ownerFromStore !== owner) { - setOwner(ownerFromStore); - } - if (repoFromStore !== repo) { - setRepo(repoFromStore); - } - }, [ownerFromStore, repoFromStore, tokenFromStore]); - - const [saved, setSaved] = useState(false); - - return ( - - - - - - - - Project Credentials - {/* {authed ? : } */} - setSaved(false)} - > - Credentials saved. - - - } - > - - - setToken(e.target.value)} - /> - - - setOwner(e.target.value)} - /> - - - setRepo(e.target.value)} - /> - - - - - - - - - - - - - ); -}; - -export default SettingsPage; diff --git a/plugins/circleci/src/state/AppState.tsx b/plugins/circleci/src/state/AppState.tsx index ecea9e5221..2e98f86661 100644 --- a/plugins/circleci/src/state/AppState.tsx +++ b/plugins/circleci/src/state/AppState.tsx @@ -17,7 +17,6 @@ import React, { FC, useReducer, Dispatch, Reducer } from 'react'; import { circleCIApiRef } from '../api'; import { State, Action, SettingsState } from './types'; export { SettingsState }; -import equal from 'fast-deep-equal'; export const AppContext = React.createContext<[State, Dispatch]>( [] as any, @@ -25,13 +24,10 @@ export const AppContext = React.createContext<[State, Dispatch]>( export const STORAGE_KEY = `${circleCIApiRef.id}.settings`; const initialState: State = { - settings: { - owner: '', - repo: '', - token: '', - }, - builds: [], - buildsWithSteps: {}, + owner: '', + repo: '', + token: '', + showSettings: false, }; const reducer: Reducer = (state, action) => { @@ -39,23 +35,12 @@ const reducer: Reducer = (state, action) => { case 'setCredentials': return { ...state, - settings: { ...state.settings, ...action.payload }, + ...action.payload, }; - case 'setBuilds': - if (equal(action.payload, state.builds)) return state; - return { - ...state, - builds: action.payload, - }; - case 'setBuildWithSteps': { - return { - ...state, - buildsWithSteps: { - ...state.buildsWithSteps, - [action.payload.build_num!]: action.payload, - }, - }; - } + case 'showSettings': + return { ...state, showSettings: true }; + case 'hideSettings': + return { ...state, showSettings: false }; default: return state; } diff --git a/plugins/circleci/src/state/types.ts b/plugins/circleci/src/state/types.ts index de801ad213..41b3577082 100644 --- a/plugins/circleci/src/state/types.ts +++ b/plugins/circleci/src/state/types.ts @@ -13,41 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BuildSummary, BuildWithSteps } from '../api'; -export type SettingsState = { - owner: string; - repo: string; - token: string; +export type Settings = { owner: string; repo: string; token: string }; +export type SettingsState = Settings & { + showSettings: boolean; }; -export type BuildsState = BuildSummary[]; +export type State = SettingsState; -export type State = { - settings: SettingsState; - builds: BuildsState; - buildsWithSteps: BuildsWithStepsState; -}; +type SettingsAction = + | { + type: 'setCredentials'; + payload: { + repo: string; + owner: string; + token: string; + }; + } + | { type: 'showSettings' } + | { type: 'hideSettings' }; -type SettingsAction = { - type: 'setCredentials'; - payload: { - repo: string; - owner: string; - token: string; - }; -}; - -type BuildsAction = { - type: 'setBuilds'; - payload: BuildSummary[]; -}; - -type BuildsWithStepsAction = { - type: 'setBuildWithSteps'; - payload: BuildWithSteps; -}; - -export type BuildsWithStepsState = Record; - -export type Action = SettingsAction | BuildsAction | BuildsWithStepsAction; +export type Action = SettingsAction; diff --git a/plugins/circleci/src/state/useBuildWithSteps.ts b/plugins/circleci/src/state/useBuildWithSteps.ts index 96d3a3f159..d77203cce0 100644 --- a/plugins/circleci/src/state/useBuildWithSteps.ts +++ b/plugins/circleci/src/state/useBuildWithSteps.ts @@ -14,50 +14,43 @@ * limitations under the License. */ import { errorApiRef, useApi } from '@backstage/core'; -import { useContext } from 'react'; +import { useCallback } from 'react'; import { circleCIApiRef, GitType } from '../api/index'; -import { AppContext } from '.'; import { useSettings } from './useSettings'; - import { useAsyncPolling } from './useAsyncPolling'; +import { useAsyncRetry } from 'react-use'; -const INTERVAL_AMOUNT = 3000; - +const INTERVAL_AMOUNT = 1500; export function useBuildWithSteps(buildId: number) { - const [settings] = useSettings(); - const [{ buildsWithSteps }, dispatch] = useContext(AppContext); + const [{ token, repo, owner }] = useSettings(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); - const { isPolling, startPolling, stopPolling } = useAsyncPolling( - () => getBuildWithSteps(), - INTERVAL_AMOUNT, - ); - - const getBuildWithSteps = async () => { + const getBuildWithSteps = useCallback(async () => { try { const options = { - token: settings.token, + token: token, vcs: { - owner: settings.owner, - repo: settings.repo, + owner: owner, + repo: repo, type: GitType.GITHUB, }, }; - const build = await api.getBuild(buildId, options); - if (isPolling) dispatch({ type: 'setBuildWithSteps', payload: build }); + const b = await api.getBuild(buildId, options); + return Promise.resolve(b); } catch (e) { errorApi.post(e); + return Promise.reject(e); } - }; + }, [token, owner, repo, buildId]); const restartBuild = async () => { try { await api.retry(buildId, { - token: settings.token, + token: token, vcs: { - owner: settings.owner, - repo: settings.repo, + owner: owner, + repo: repo, type: GitType.GITHUB, }, }); @@ -66,15 +59,22 @@ export function useBuildWithSteps(buildId: number) { } }; - const build = buildsWithSteps[buildId]; + const { loading, value, retry } = useAsyncRetry(() => getBuildWithSteps(), [ + getBuildWithSteps, + ]); + + const { startPolling, stopPolling } = useAsyncPolling( + getBuildWithSteps, + INTERVAL_AMOUNT, + ); return [ - build, + { loading, value, retry }, { restartBuild, + getBuildWithSteps, startPolling, stopPolling, - getBuildWithSteps, }, ] as const; } diff --git a/plugins/circleci/src/state/useBuilds.tsx b/plugins/circleci/src/state/useBuilds.tsx index d46ac642a5..4435c2b8bd 100644 --- a/plugins/circleci/src/state/useBuilds.tsx +++ b/plugins/circleci/src/state/useBuilds.tsx @@ -14,52 +14,102 @@ * limitations under the License. */ import { errorApiRef, useApi } from '@backstage/core'; -import { GitType } from 'circleci-api'; -import { useContext } from 'react'; +import { GitType, BuildSummary } from 'circleci-api'; +import { useState, useEffect, useCallback } from 'react'; import { circleCIApiRef } from '../api/index'; -import { AppContext } from '.'; -import { useAsyncPolling } from './useAsyncPolling'; +import { useAsyncRetry } from 'react-use'; +import { CITableBuildInfo } from '../pages/BuildsPage/lib/CITable'; +import { useSettings } from './useSettings'; -const INTERVAL_AMOUNT = 3000; +const makeReadableStatus = (status: string | undefined) => { + if (!status) return ''; + return ({ + retried: 'Retried', + canceled: 'Canceled', + infrastructure_fail: 'Infra fail', + timedout: 'Timedout', + not_run: 'Not run', + running: 'Running', + failed: 'Failed', + queued: 'Queued', + scheduled: 'Scheduled', + not_running: 'Not running', + no_tests: 'No tests', + fixed: 'Fixed', + success: 'Success', + } as Record)[status]; +}; + +export const transform = ( + buildsData: BuildSummary[], + restartBuild: { (buildId: number): Promise }, +): CITableBuildInfo[] => { + return buildsData.map((buildData) => { + const tableBuildInfo: CITableBuildInfo = { + id: String(buildData.build_num), + buildName: buildData.subject + ? buildData.subject + + (buildData.retry_of ? ` (retry of #${buildData.retry_of})` : '') + : '', + onRestartClick: () => + typeof buildData.build_num !== 'undefined' && + restartBuild(buildData.build_num), + source: { + branchName: String(buildData.branch), + commit: { + hash: String(buildData.vcs_revision), + url: 'todo', + }, + }, + status: makeReadableStatus(buildData.status), + buildUrl: buildData.build_url, + }; + return tableBuildInfo; + }); +}; export function useBuilds() { - const [{ builds, settings }, dispatch] = useContext(AppContext); + const [{ repo, owner, token }] = useSettings(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); - const { isPolling, startPolling, stopPolling } = useAsyncPolling( - () => getBuilds(), - INTERVAL_AMOUNT, - ); - const getBuilds = async () => { - if (settings.owner === '' || settings.repo === '') return; - try { - const newBuilds = await api.getBuilds({ - token: settings.token, - vcs: { - owner: settings.owner, - repo: settings.repo, - type: GitType.GITHUB, - }, - }); - if (isPolling) - dispatch({ - type: 'setBuilds', - payload: newBuilds, - }); - } catch (e) { - errorApi.post(e); - } - }; + const [total, setTotal] = useState(0); + const [page, setPage] = useState(0); + const [pageSize, setPageSize] = useState(5); + + const getBuilds = useCallback( + async ({ limit, offset }: { limit: number; offset: number }) => { + if (owner === '' || repo === '') { + return; + } + try { + return await api.getBuilds( + { limit, offset }, + { + token: token, + vcs: { + owner: owner, + repo: repo, + type: GitType.GITHUB, + }, + }, + ); + } catch (e) { + errorApi.post(e); + return Promise.reject(e); + } + }, + [repo, token, owner], + ); const restartBuild = async (buildId: number) => { try { await api.retry(buildId, { - token: settings.token, + token: token, vcs: { - owner: settings.owner, - repo: settings.repo, + owner: owner, + repo: repo, type: GitType.GITHUB, }, }); @@ -68,12 +118,35 @@ export function useBuilds() { } }; + useEffect(() => { + getBuilds({ limit: 1, offset: 0 }).then((b) => setTotal(b?.[0].build_num!)); + }, [repo]); + + const { loading, value, retry } = useAsyncRetry( + () => + getBuilds({ + offset: page * pageSize, + limit: pageSize, + }).then((builds) => transform(builds ?? [], restartBuild)), + [page, pageSize, getBuilds], + ); + + const projectName = `${owner}/${repo}`; return [ - builds, { + page, + pageSize, + loading, + value, + projectName, + total, + }, + { + getBuilds, + setPage, + setPageSize, restartBuild, - startPolling, - stopPolling, + retry, }, ] as const; } diff --git a/plugins/circleci/src/state/useSettings.ts b/plugins/circleci/src/state/useSettings.ts index 34b2f5e402..04ce83a0a9 100644 --- a/plugins/circleci/src/state/useSettings.ts +++ b/plugins/circleci/src/state/useSettings.ts @@ -14,12 +14,11 @@ * limitations under the License. */ import { useContext, useEffect } from 'react'; -import { AppContext, STORAGE_KEY, SettingsState } from '.'; +import { AppContext, STORAGE_KEY } from '.'; import { useApi, errorApiRef } from '@backstage/core'; - +import { Settings } from './types'; export function useSettings() { - const [{ settings }, dispatch] = useContext(AppContext); - + const [settings, dispatch] = useContext(AppContext); const errorApi = useApi(errorApiRef); @@ -45,20 +44,22 @@ export function useSettings() { rehydrate(); }, []); - const persist = (state: SettingsState) => { + const persist = (state: Settings) => { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)); }; return [ settings, { - saveSettings: (state: SettingsState) => { + saveSettings: (state: Settings) => { persist(state); dispatch({ type: 'setCredentials', payload: state, }); }, + showSettings: () => dispatch({ type: 'showSettings' }), + hideSettings: () => dispatch({ type: 'hideSettings' }), }, ] as const; }