From 0aadec0439ee4a27a74f929344b85440e9ffb7b0 Mon Sep 17 00:00:00 2001 From: Jesper Paulsen Date: Mon, 11 Dec 2023 13:52:44 +0100 Subject: [PATCH 1/4] [KAIZEN-0] Ikke fnr i path --- src/featureToggle/FeatureToggles.ts | 3 ++- src/redux/api.ts | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/featureToggle/FeatureToggles.ts b/src/featureToggle/FeatureToggles.ts index 9c273c49..597e8a0f 100644 --- a/src/featureToggle/FeatureToggles.ts +++ b/src/featureToggle/FeatureToggles.ts @@ -1,3 +1,4 @@ export enum FeatureToggles { - NY_ARBEIDSSOKER_REGISTRERING_URL = 'modiacontextholder.ny-arbeidssoker-registrering-url' + NY_ARBEIDSSOKER_REGISTRERING_URL = 'modiacontextholder.ny-arbeidssoker-registrering-url', + IKKE_FNR_I_PATH = 'modiacontextholder.ikke-fnr-i-path' } diff --git a/src/redux/api.ts b/src/redux/api.ts index 68547061..4f5f547c 100644 --- a/src/redux/api.ts +++ b/src/redux/api.ts @@ -5,6 +5,7 @@ import { AktivBruker, AktivEnhet, AktorIdResponse, Saksbehandler } from '../inte import failureConfig from './../mock/mock-error-config'; import { ProxyConfig } from '../domain'; import { FeatureToggles } from '../featureToggle/FeatureToggles'; +import { useFeatureToggle } from '../featureToggle/FeatureToggleProvider'; export enum ContextApiType { NY_AKTIV_ENHET = 'NY_AKTIV_ENHET', @@ -51,8 +52,9 @@ export function lagModiacontextholderUrl(proxyConfig: ProxyConfig = false): stri } } function lagUrls(proxyConfig: ProxyConfig) { + const { isOn } = useFeatureToggle(FeatureToggles.IKKE_FNR_I_PATH) const modiacontextholderUrl = lagModiacontextholderUrl(proxyConfig); - return { + const config = { aktivEnhetUrl: `${modiacontextholderUrl}/api/context/aktivenhet`, aktivBrukerUrl: `${modiacontextholderUrl}/api/context/aktivbruker`, contextUrl: `${modiacontextholderUrl}/api/context`, @@ -60,6 +62,10 @@ function lagUrls(proxyConfig: ProxyConfig) { featureTogglesUrl: `${modiacontextholderUrl}/api/featuretoggle`, aktorIdUrl: (fnr: string) => `${modiacontextholderUrl}/api/decorator/aktor/${fnr}` }; + if (isOn) { + config.aktorIdUrl = () => `${modiacontextholderUrl}/api/v2/decorator/aktor/hent-fnr` + } + return config } export let urls = lagUrls(false); @@ -103,7 +109,7 @@ export async function getJson(info: RequestInfo, init?: RequestInit): Promise } } -async function postJson(url: string, body: T, options?: RequestInit): Promise> { +async function postJson(url: string, body: REQUEST, options?: RequestInit): Promise> { try { const response: Response = await doFetch(url, { ...(options || {}), @@ -115,7 +121,7 @@ async function postJson(url: string, body: T, options?: RequestInit): Promise const content = await response.text(); return { data: undefined, error: content }; } - return { data: body, error: undefined }; + return { data: response.json() as RESPONSE, error: undefined }; } catch (error) { return { data: undefined, error }; } @@ -144,6 +150,12 @@ export function hentAktorId(fnr: string): Promise return Promise.reject('Ugyldig fødselsnummer, kan ikke hente aktørId'); } + const { isOn } = useFeatureToggle(FeatureToggles.IKKE_FNR_I_PATH) + + if (isOn) { + return postJson(urls.aktorIdUrl(fnr), fnr) + } + return getJson(urls.aktorIdUrl(fnr)); } From 42eecf083f9831f2b1085b74f8c36301f07985e3 Mon Sep 17 00:00:00 2001 From: abrha Date: Wed, 20 Dec 2023 13:45:08 +0100 Subject: [PATCH 2/4] [KAIZEN-0] migrate to Google Artifact Registry --- .github/workflows/main.yaml | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index c397362d..4fe13aba 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -7,7 +7,6 @@ concurrency: cancel-in-progress: true env: - IMAGE: ghcr.io/${{ github.repository }}/internarbeidsflatedecorator:${{ github.sha }} CI: true TZ: Europe/Oslo @@ -35,15 +34,19 @@ jobs: runs-on: ubuntu-latest permissions: packages: write + contents: read + id-token: write + outputs: + image: ${{ steps.docker-build-push.outputs.image }} steps: - uses: actions/checkout@v3 - name: Publish Docker image - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - docker build --tag ${IMAGE} . - docker login ghcr.io -u ${GITHUB_REPOSITORY} -p ${GITHUB_TOKEN} - docker push ${IMAGE} + uses: nais/docker-build-push@v0 + id: docker-build-push + with: + team: personoversikt + identity_provider: ${{ secrets.NAIS_WORKLOAD_IDENTITY_PROVIDER }} + project_id: ${{ vars.NAIS_MANAGEMENT_PROJECT_ID }} deploy-qa: name: Deploy to preprod @@ -55,13 +58,13 @@ jobs: q_env: [q0, q1] steps: - uses: actions/checkout@v3 - - uses: nais/deploy/actions/deploy@v1 + - uses: nais/deploy/actions/deploy@v2 env: APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} PRINT_PAYLOAD: true CLUSTER: dev-fss RESOURCE: .nais/qa-template.yaml - VAR: q_env=${{matrix.q_env}} + VAR: q_env=${{matrix.q_env}},image=${{ needs.build-and-push.outputs.image }} deploy-prod: name: Deploy to prod @@ -70,12 +73,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: nais/deploy/actions/deploy@v1 + - uses: nais/deploy/actions/deploy@v2 env: APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} PRINT_PAYLOAD: true CLUSTER: prod-fss RESOURCE: .nais/prod.yaml + VAR: image=${{ needs.build-and-push.outputs.image }} deploy-gh-pages: name: Deploy til gh-pages From 7f88430d648aafd0ece31f9b0f195146f3fd4381 Mon Sep 17 00:00:00 2001 From: Jesper Paulsen Date: Thu, 21 Dec 2023 12:54:11 +0100 Subject: [PATCH 3/4] [KAIZEN-0] Skrive om logikk for feature toggles, fjerne toggle for arbeidsregistrering --- src/application.tsx | 5 +-- src/components/lenker.tsx | 35 +++++------------- src/featureToggle/FeatureToggleManager.ts | 39 ++++++++++++++++++++ src/featureToggle/FeatureToggleProvider.tsx | 41 --------------------- src/featureToggle/FeatureToggles.ts | 1 - src/mock/index.ts | 2 +- src/redux/api.ts | 29 +++++++++------ 7 files changed, 68 insertions(+), 84 deletions(-) create mode 100644 src/featureToggle/FeatureToggleManager.ts delete mode 100644 src/featureToggle/FeatureToggleProvider.tsx diff --git a/src/application.tsx b/src/application.tsx index 1643ece9..db5c3142 100644 --- a/src/application.tsx +++ b/src/application.tsx @@ -15,7 +15,6 @@ import { useOnMount } from './hooks/use-on-mount'; import { useOnChanged } from './hooks/use-on-changed'; import { getContextvalueValue, isContextvalueControlled, RESET_VALUE } from './redux/utils'; import { DecoratorHotkeysProvider } from './components/hurtigtaster/hurtigtaster'; -import FeatureToggleProvider from './featureToggle/FeatureToggleProvider'; function Application(props: ApplicationProps) { const dispatch = useDispatch>(); @@ -81,9 +80,7 @@ class ErrorHandler extends React.Component { render() { return ( - - - + ); } diff --git a/src/components/lenker.tsx b/src/components/lenker.tsx index 5d332cbb..18de3c86 100644 --- a/src/components/lenker.tsx +++ b/src/components/lenker.tsx @@ -1,19 +1,17 @@ -import React, {useEffect} from 'react'; +import React, { useEffect } from 'react'; import { finnMiljoStreng, finnNaisInternNavMiljoStreng, finnNaisMiljoStreng, hentMiljoFraUrl } from '../utils/url-utils'; -import {WrappedState} from "../hooks/use-wrapped-state"; -import {useInitializedState} from "../hooks/use-initialized-state"; -import {useEnhetContextvalueState, useFnrContextvalueState} from "../hooks/use-contextvalue-state"; -import {Hotkey, ProxyConfig} from "../domain"; -import {lagModiacontextholderUrl} from "../redux/api"; -import {useDecoratorHotkeys} from "./hurtigtaster/hurtigtaster"; +import { WrappedState } from "../hooks/use-wrapped-state"; +import { useInitializedState } from "../hooks/use-initialized-state"; +import { useEnhetContextvalueState, useFnrContextvalueState } from "../hooks/use-contextvalue-state"; +import { Hotkey, ProxyConfig } from "../domain"; +import { lagModiacontextholderUrl } from "../redux/api"; +import { useDecoratorHotkeys } from "./hurtigtaster/hurtigtaster"; import './lenker.css'; -import { FeatureToggles } from '../featureToggle/FeatureToggles'; -import { useFeatureToggle } from '../featureToggle/FeatureToggleProvider'; function Lenke(props: { href: string; children: string; target?: string; }) { /* eslint-disable jsx-a11y/anchor-has-content */ @@ -57,10 +55,7 @@ const pesysUrl = (fnr: string, path: string) => (fnr ? pesysDomain(path) : pesys export const gosysUrl = (fnr: string, path: string) => fnr ? gosysDomain(path) : gosysDomain('/gosys/'); const fpsakUrl = `https://fpsak${finnNaisInternNavMiljoStreng()}` const foreldrePengerUrl = (aktoerId: string) => aktoerId ? `${fpsakUrl}/aktoer/${aktoerId}` : `${fpsakUrl}/`; -function arbeidssokerregistreringURL(fnr: string, enhet: string) { - const queryParams = `?${fnr ? `fnr=${fnr}` : ''}${fnr && enhet ? '&' : ''}${enhet ? `enhetId=${enhet}` : ''}`; - return `https://arbeidssokerregistrering${finnNaisInternNavMiljoStreng()}${queryParams}`; -} + const inst2 = () => `https://inst2-web${finnNaisMiljoStreng(true)}/`; function k9Url(aktorId: string): string { const miljo = hentMiljoFraUrl(); @@ -106,14 +101,6 @@ interface Props { proxyConfig: ProxyConfig; } -const useArbeidssokerRegistreringUrl = (fnr: string, enhet: string) => { - const isOn = useFeatureToggle(FeatureToggles.NY_ARBEIDSSOKER_REGISTRERING_URL) - if (isOn) { - return `https://arbeidssokerregistrering-for-veileder${finnNaisInternNavMiljoStreng()}/` - } - return arbeidssokerregistreringURL(fnr, enhet) -} - function Lenker(props: Props) { const fnr = useFnrContextvalueState().withDefault(''); const enhet = useEnhetContextvalueState().withDefault(''); @@ -121,13 +108,11 @@ function Lenker(props: Props) { .map((resp) => resp.aktorId) .withDefault(''); - const {register} = useDecoratorHotkeys(); + const { register } = useDecoratorHotkeys(); useEffect(() => { lagHotkeys(fnr, aktorId).forEach(register); }, [register, fnr, aktorId]) - const arbeidssokerregistreringURL = useArbeidssokerRegistreringUrl(fnr, enhet) - if (!props.apen.value) { return null; } @@ -178,7 +163,7 @@ function Lenker(props: Props) { Aktivitetsplan - + Registrer person diff --git a/src/featureToggle/FeatureToggleManager.ts b/src/featureToggle/FeatureToggleManager.ts new file mode 100644 index 00000000..f7bed9fd --- /dev/null +++ b/src/featureToggle/FeatureToggleManager.ts @@ -0,0 +1,39 @@ +import { FeatureTogglesResponse, hentFeatureToggles } from '../redux/api'; +import { FeatureToggles } from './FeatureToggles'; + + +const TEN_SECONDS = 10000 + +class FeatureToggleManager { + private lastFetch?: number + private toggles: FeatureTogglesResponse + + constructor() { + this.toggles = this.defaultToggles() + } + + private defaultToggles = (): FeatureTogglesResponse => { + return { + 'modiacontextholder.ikke-fnr-i-path': false + }; + }; + + private getToggles = async () => { + const res = await hentFeatureToggles() + if (res.data) { + this.toggles = res.data + this.lastFetch = Date.now() + } + } + + private shouldFetchToggles = (): boolean => !this.lastFetch || this.lastFetch < Date.now() - TEN_SECONDS + + getToggle = async (toggleId: FeatureToggles): Promise => { + if (this.shouldFetchToggles()) { + await this.getToggles() + } + return !!this.toggles[toggleId] + } +} + +export default new FeatureToggleManager() \ No newline at end of file diff --git a/src/featureToggle/FeatureToggleProvider.tsx b/src/featureToggle/FeatureToggleProvider.tsx deleted file mode 100644 index b7634525..00000000 --- a/src/featureToggle/FeatureToggleProvider.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { createContext, useContext, useEffect, useState } from 'react'; -import { FeatureTogglesResponse, hentFeatureToggles } from '../redux/api'; -import { FeatureToggles } from './FeatureToggles'; - -const useFeatureToggles = (): FeatureTogglesResponse => { - const [toggles, setToggles] = useState(defaultToggles()); - - useEffect(() => { - hentFeatureToggles().then((res) => { - if (res.data) { - setToggles(res.data); - } - }); - }, []); - - return toggles; -}; - -const defaultToggles = (): FeatureTogglesResponse => { - return { - 'modiacontextholder.ny-arbeidssoker-registrering-url': false - }; -}; - -const featureToggleContext = createContext(defaultToggles()); - -const FeatureToggleProvider: React.FC = ({ children }) => { - const toggles = useFeatureToggles(); - - return ( - {children} - ); -}; - -export default FeatureToggleProvider; - -export const useFeatureToggle = (id: FeatureToggles) => { - const toggles = useContext(featureToggleContext); - - return toggles[id]; -}; diff --git a/src/featureToggle/FeatureToggles.ts b/src/featureToggle/FeatureToggles.ts index 597e8a0f..82207fc1 100644 --- a/src/featureToggle/FeatureToggles.ts +++ b/src/featureToggle/FeatureToggles.ts @@ -1,4 +1,3 @@ export enum FeatureToggles { - NY_ARBEIDSSOKER_REGISTRERING_URL = 'modiacontextholder.ny-arbeidssoker-registrering-url', IKKE_FNR_I_PATH = 'modiacontextholder.ikke-fnr-i-path' } diff --git a/src/mock/index.ts b/src/mock/index.ts index c577b24d..3eb9cef3 100644 --- a/src/mock/index.ts +++ b/src/mock/index.ts @@ -57,7 +57,7 @@ mock.get('/modiacontextholder/api/decorator/aktor/:fnr', (req, res, ctx) => { mock.get('/modiacontextholder/api/featuretoggle', (req, res, ctx) => { const response: FeatureTogglesResponse = { - 'modiacontextholder.ny-arbeidssoker-registrering-url': true + 'modiacontextholder.ikke-fnr-i-path': false }; return res(ctx.status(200), ctx.statusText('Ok'), ctx.json(response)); }); diff --git a/src/redux/api.ts b/src/redux/api.ts index 4f5f547c..7f729c4d 100644 --- a/src/redux/api.ts +++ b/src/redux/api.ts @@ -5,7 +5,7 @@ import { AktivBruker, AktivEnhet, AktorIdResponse, Saksbehandler } from '../inte import failureConfig from './../mock/mock-error-config'; import { ProxyConfig } from '../domain'; import { FeatureToggles } from '../featureToggle/FeatureToggles'; -import { useFeatureToggle } from '../featureToggle/FeatureToggleProvider'; +import FeatureToggleManager from '../featureToggle/FeatureToggleManager'; export enum ContextApiType { NY_AKTIV_ENHET = 'NY_AKTIV_ENHET', @@ -52,7 +52,6 @@ export function lagModiacontextholderUrl(proxyConfig: ProxyConfig = false): stri } } function lagUrls(proxyConfig: ProxyConfig) { - const { isOn } = useFeatureToggle(FeatureToggles.IKKE_FNR_I_PATH) const modiacontextholderUrl = lagModiacontextholderUrl(proxyConfig); const config = { aktivEnhetUrl: `${modiacontextholderUrl}/api/context/aktivenhet`, @@ -60,13 +59,12 @@ function lagUrls(proxyConfig: ProxyConfig) { contextUrl: `${modiacontextholderUrl}/api/context`, saksbehandlerUrl: `${modiacontextholderUrl}/api/decorator`, featureTogglesUrl: `${modiacontextholderUrl}/api/featuretoggle`, - aktorIdUrl: (fnr: string) => `${modiacontextholderUrl}/api/decorator/aktor/${fnr}` + aktorIdUrl: (fnr: string) => `${modiacontextholderUrl}/api/decorator/aktor/${fnr}`, + modiacontextholderUrl }; - if (isOn) { - config.aktorIdUrl = () => `${modiacontextholderUrl}/api/v2/decorator/aktor/hent-fnr` - } - return config + return config; } + export let urls = lagUrls(false); export type ResponseError = { data: undefined; error: string }; @@ -109,7 +107,11 @@ export async function getJson(info: RequestInfo, init?: RequestInit): Promise } } -async function postJson(url: string, body: REQUEST, options?: RequestInit): Promise> { +async function postJson( + url: string, + body: REQUEST, + options?: RequestInit +): Promise> { try { const response: Response = await doFetch(url, { ...(options || {}), @@ -121,7 +123,7 @@ async function postJson(url: string, body: REQUEST, opt const content = await response.text(); return { data: undefined, error: content }; } - return { data: response.json() as RESPONSE, error: undefined }; + return { data: (await response.json()) as RESPONSE, error: undefined }; } catch (error) { return { data: undefined, error }; } @@ -143,17 +145,20 @@ async function deleteJson(url: string, options?: RequestInit): Promise> { +export async function hentAktorId(fnr: string): Promise> { const feilmelding = lagFnrFeilmelding(fnr); if (feilmelding.isJust()) { return Promise.reject('Ugyldig fødselsnummer, kan ikke hente aktørId'); } - const { isOn } = useFeatureToggle(FeatureToggles.IKKE_FNR_I_PATH) + const isOn = await FeatureToggleManager.getToggle(FeatureToggles.IKKE_FNR_I_PATH); if (isOn) { - return postJson(urls.aktorIdUrl(fnr), fnr) + return postJson( + `${urls.modiacontextholderUrl}/api/v2/decorator/aktor/hent-fnr`, + fnr + ); } return getJson(urls.aktorIdUrl(fnr)); From 92950c40e264de4e34aeb57fe990d0230835e285 Mon Sep 17 00:00:00 2001 From: abrha Date: Fri, 5 Jan 2024 18:12:42 +0100 Subject: [PATCH 4/4] [KAIZEN-0] bump deploy@v2 --- .github/workflows/main.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 4fe13aba..eeba10c8 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -53,6 +53,9 @@ jobs: needs: build-and-push if: github.ref == 'refs/heads/dev' runs-on: ubuntu-latest + permissions: + contents: read + id-token: write strategy: matrix: q_env: [q0, q1] @@ -60,7 +63,6 @@ jobs: - uses: actions/checkout@v3 - uses: nais/deploy/actions/deploy@v2 env: - APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} PRINT_PAYLOAD: true CLUSTER: dev-fss RESOURCE: .nais/qa-template.yaml @@ -71,11 +73,13 @@ jobs: needs: build-and-push if: github.ref == 'refs/heads/master' runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - uses: actions/checkout@v3 - uses: nais/deploy/actions/deploy@v2 env: - APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} PRINT_PAYLOAD: true CLUSTER: prod-fss RESOURCE: .nais/prod.yaml