NPM-pakke med hjelpefunksjoner for Nav-dekoratøren (header og footer på nav.no)
- Tar imot logging fra amplitude og forkaster hvis dekoratorenAmplitude ikke finnes. Dette er en justering fra tidligere hvor getAmplitudeInstance returnerte rejected promise.
- Eksporterer nye analyticsfunksjoner som logger både umami + amplitude
- Ny funksjonalitet for å sette cookies, localStorage og sessionStorage basert på tillatte lagring. Se egen seksjon for mer info.
- Oppdaterer avhengigheter, kun patch.
- Legger til
pageType
i params. Kan brukes til å logge sidetype til Analytics/Amplitude
- Legger til
redirectOnUserChange
i params
- Legger til prop for egendefinert komponent for
script
-elementer frafetchDecoratorReact
. Skal nå støtte bruk i next.js app-router layouts, se fetchDecoratorReact. - Peer dependencies er ikke lengre optional (med unntak av React).
- Server-side fetch-funksjoner henter nå ferdige HTML-fragmenter fra
/ssr
-endepunktet, istedenfor å parse hele dekoratørens HTML. - (breaking) Alle dekoratørens
<head>
-elementer er nå inkludert i det påkrevde fragmentetDECORATOR_HEAD_ASSETS
. CSS, favicon, etc. - (breaking) Fjerner
DECORATOR_STYLES
/Styles
fra responsen forfetchDecoratorHtml
/fetchDecoratorReact
(erstattes avDECORATOR_HEAD_ASSETS
). - Den innbygde cachen av dekoratørens elementer invalideres nå automatisk når en ny versjon av dekoratøren er tilgjengelig.
- Nye funksjoner:
addDecoratorUpdateListener
,removeDecoratorUpdateListener
,getDecoratorVersionId
. Tiltenkt brukt for cache-invalidering i apper som cacher dekoratøren på andre måter. - Fjerner typer for ubrukte parametre
urlLookupTable
ogenforceLogin
- (breaking) Fjerner
<EnforceLoginLoader/>
- (breaking) Fjerner
injectDecoratorServerSideDom
. Denne erstattes avinjectDecoratorServerSideDocument
, som tar inn et standard Document DOM-objekt. - (breaking) Fjerner
getUrlFromLookupTable
og tilhørende url-mappinger - (breaking) Fjerner
parseDecoratorHTMLToReact
- (breaking) Alle dependencies er nå optional peer dependencies
- (breaking) Node.js v18 eller nyere er påkrevd, ettersom vi ikke lengre benytter node-fetch. (Node 18 har fetch innebygd)
- (breaking) Server-side fetch-funksjoner benytter nå service discovery som default. Dette krever visse access policy regler.
- (breaking) Parametre til fetch-funksjoner er endret, slik at query-parametre til dekoratøren nå er et separat objekt.
Eksempel 1.x -> 2.0:{ env: "prod", context: "arbeidsgiver", simple: true}
->{ env: "prod", params: { context: "arbeidsgiver", simple: true }}
) - (breaking) Ved bruk av
env: "localhost"
må dekoratørens url nå alltid settes med parameteretlocalUrl
. Dette erstatter parametereneport
ogdekoratorenUrl
, og vi har ikke lengre en default localhost url. - Flere typer er endret eller har fått mer spesifikke navn (f.eks.
Params
->DecoratorParams
)
npm install --save @navikt/nav-dekoratoren-moduler
Obs! Oppdaterte pakker publiseres kun i GitHub Packages registry'et. For å kunne installere nyere versjoner må pakker fra @navikt-orgen scopes til GitHub Packages.
- Legg til dette i
.npmrc
-fila for prosjektet. Opprett fila på rot i prosjektet hvis den ikke finnes.
@navikt:registry=https://npm.pkg.github.com
- Opprett et PAT med
read:packages
scope og SSO auth, og bruk dette som passord ved login.
npm login --registry=https://npm.pkg.github.com --auth-type=legacy
- Sett registry url med f.eks.
actions/setup-node
:
- name: Setup node.js
uses: actions/setup-node@v4
with:
registry-url: 'https://npm.pkg.github.com'
- Sett
NODE_AUTH_TOKEN
pånpm ci
.READER_TOKEN
er en navikt org-wide secret til dette formålet.
- name: Install dependencies
run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.READER_TOKEN }}
Pakka inneholder funksjoner for å laste inn dekoratøren i apper på ulike måter.
Samtlige funksjoner for fetch av dekoratøren tar inn parametre med følgende type:
type DecoratorNaisEnv =
| "prod" // For produksjons-instans av dekoratøren
| "dev" // For stabil dev-instans
| "beta" // Beta dev-instanser er ment for internt test-bruk
| "betaTms"; // Disse kan være ustabile i lengre perioder
type DecoratorEnvProps =
// Dersom env er satt til localhost, må du selv sette url for dekoratøren.
| { env: "localhost"; localUrl: string }
// For nais-miljøer settes url automatisk
| { env: DecoratorNaisEnv; serviceDiscovery?: boolean };
type DecoratorFetchProps = {
// Query-parametre til dekoratøren, se dekoratørens readme for dokumentasjon
params?: DecoratorParams;
} & DecoratorEnvProps;
Server-side fetch-funksjonene benytter service discovery som default. Vær obs på at dette kun fungerer ved kjøring på dev-gcp eller prod-gcp nais-clusterne. Dersom appen ikke kjører i ett av disse clusterne, vil vi falle tilbake til å kalle eksterne ingresser.
Du kan også sette parameteret serviceDiscovery: false
for å alltid benytte eksterne ingresser.
fetchDecoratorHtml({
env: "prod",
serviceDiscovery: false,
});
Se nais doc for oppsett av access policy.
Ved bruk av service discovery må følgende regel inkluderes i access policy:
accessPolicy:
outbound:
rules:
- application: nav-dekoratoren
namespace: personbruker
Dersom service discovery ikke benyttes, vil dekoratørens eksterne ingresser kalles. Dette gjelder ved bruk av versjon 1.9 eller tidligere, eller dersom serviceDiscovery: false
er satt.
Følgende access policy kreves:
accessPolicy:
outbound:
external:
- host: www.nav.no # for prod
- host: dekoratoren.ekstern.dev.nav.no # for dev
Server-side rendering av dekoratøren anbefales for optimal brukeropplevelse. Dersom kallet feiler (etter 3 retries), faller vi tilbake til statiske placeholder-elementer som client-side rendres.
Parser en HTML-fil med JSDOM og returnerer en HTML-string som inkluderer dekoratøren. Krever at jsdom >=16.x
er installert.
import { injectDecoratorServerSide } from "@navikt/nav-dekoratoren-moduler/ssr";
injectDecoratorServerSide({
env: "prod",
filePath: "index.html",
params: { context: "privatperson", simple: true },
}).then((htmlWithDecorator: string) => {
res.send(htmlWithDecorator);
});
Setter inn dekoratøren i et Document DOM-objekt. Objektet i document-parameteret muteres.
import { injectDecoratorServerSideDocument } from "@navikt/nav-dekoratoren-moduler/ssr";
injectDecoratorServerSideDocument({
env: "prod",
document: myDocument,
params: { context: "privatperson", simple: true },
}).then((document: Document) => {
const html = document.documentElement.outerHTML;
res.send(html);
});
Henter dekoratøren som HTML-fragmenter.
Eksempel på bruk:
import { fetchDecoratorHtml } from "@navikt/nav-dekoratoren-moduler/ssr";
const fragments = await fetchDecoratorHtml({
env: "dev",
params: { context: "privatperson" },
});
const { DECORATOR_HEAD_ASSETS, DECORATOR_HEADER, DECORATOR_FOOTER, DECORATOR_SCRIPTS } = fragments;
// Sett inn fragmenter i app-html'en med f.eks. en template engine
Henter dekoratøren som React-komponenter. Kan benyttes med React rammeverk som støtter server-side rendering. Krever at react >=17.x
og html-react-parser >=5.x
er installert.
Ved behov kan det settes en egendefinert komponent for <script>
-elementer i <Decorator.Scripts>
. Denne vil erstatte standard <script>
-tags i parser'en. Ved bruk av next.js app-router kan next/script
benyttes her, se eksempel #2.
Settes inn i pages/_document.tsx
:
import { fetchDecoratorReact } from "@navikt/nav-dekoratoren-moduler/ssr";
class MyDocument extends Document<DocumentProps> {
static async getInitialProps(ctx: DocumentContext) {
const initialProps = await Document.getInitialProps(ctx);
const Decorator = await fetchDecoratorReact({
env: "prod",
params: { language: "no", context: "arbeidsgiver" },
});
return { ...initialProps, Decorator };
}
render() {
const { Decorator } = this.props;
return (
<Html lang={"no"}>
<Head>
<Decorator.HeadAssets />
</Head>
<body>
<Decorator.Header />
<Main />
<Decorator.Footer />
<Decorator.Scripts />
<NextScript />
</body>
</Html>
);
}
}
Settes inn i root layout med next/script
loader:
import { fetchDecoratorReact } from "@navikt/nav-dekoratoren-moduler/ssr";
import Script from "next/script";
const RootLayout = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
const Decorator = await fetchDecoratorReact({
env: "prod",
});
return (
<html lang="no">
<head>
<Decorator.HeadAssets />
</head>
<body>
<Decorator.Header />
{children}
<Decorator.Footer />
<Decorator.Scripts loader={Script} />
</body>
</html>
);
};
export default RootLayout;
CSR vil gi en redusert brukeropplevelse pga layout-shifting/"pop-in" når headeren rendres, og bør unngås om mulig. Ta gjerne kontakt i #dekoratøren_på_navno for bistand med å sette opp SSR i appen din!
Setter inn dekoratøren i DOM'en client-side. Service discovery kan ikke benyttes ved client-side injection.
Eksempel på bruk:
import { injectDecoratorClientSide } from "@navikt/nav-dekoratoren-moduler";
injectDecoratorClientSide({
env: "prod",
params: {
simple: true,
chatbot: true,
},
});
Dersom env
er satt til localhost
må dekoratørens URL settes med parametret localUrl
. Benyttes dersom du f.eks. kjører dekoratøren lokalt på egen maskin, eller den hentes via en proxy.
Eksempel:
injectDecoratorServerSide({
filePath: "index.html",
env: "localhost",
localUrl: "http://localhost:8089/dekoratoren",
});
Legger til/fjerner en callback-funksjon som kalles når en ny versjon av dekoratøren er deployet til valgt miljø.
Tiltenkt brukt for cache-invalidering i apper som cacher dekoratørens HTML.
import { addDecoratorUpdateListener } from "@navikt/nav-dekoratoren-moduler/ssr";
const flushHtmlCache = (versionId: string) => {
console.log(`New decorator version: ${versionId} - clearing render cache!`);
myHtmlCache.clear();
};
addDecoratorUpdateListener({ env: "prod" }, flushHtmlCache);
Henter nåværende versjons-id for dekoratøren i valgt miljø.
import { getDecoratorVersionId } from "@navikt/nav-dekoratoren-moduler/ssr";
const currentVersionId = await getDecoratorVersionId({ env: "prod" });
Bygger en Content-Security-Policy header som inkluderer dekoratørens påkrevde direktiver, kombinert med applikasjonens egne direktiver. Krever at csp-header >=5.x
er installert.
Funksjonen gjør et fetch-kall til dekoratøren for å hente gjeldende direktiver.
Eksempel på bruk:
import { buildCspHeader } from "@navikt/nav-dekoratoren-moduler/ssr";
// Direktiver appen din benytter
const myAppDirectives = {
"default-src": ["foo.bar.com"],
"style-src": ["my.css.cdn.com"],
};
const csp = await buildCspHeader(myAppDirectives, { env: "prod" });
app.get("*", (req, res) => {
res.setHeader("Content-Security-Policy", csp);
res.send("Hello!");
});
Bygger en logger-instans som sender events til Amplitude via dekoratørens klient. Tar i mot et parameter origin
slik at man kan filtrere events som kommer fra egen app.
Det er sterkt anbefalt å følge Navs taksonomi for analyseverktøy:
https://github.com/navikt/analytics-taxonomy
Eksempel på bruk:
import { getAmplitudeInstance } from "@navikt/nav-dekoratoren-moduler";
const logger = getAmplitudeInstance("minAppOrigin");
logger("skjema åpnet", {
skjemaId: 1234,
skjemanavn: "aap",
});
Du kan også utvide taxonomien som er definert for å tilpasse ditt bruk. Det har ingen funksjonell effekt, men vil gjøre det lettere for utviklerene i prosjektet å følge en standard hvis ønskelig.
Eksempel på å definere events:
import { AmplitudeEvent, getAmplitudeInstance } from "@navikt/nav-dekoratoren-moduler";
type SampleCustomEvents =
| AmplitudeEvent<"first", { hei: string }>
| AmplitudeEvent<"second", { hei: string }>;
const logger = getAmplitudeInstance<SampleCustomEvents>("minAppOrigin");
logger("first", {
hei: "hei",
});
Parameteret breadcrumbs
(brødsmulestien) kan endres / settes på klient-siden ved behov.
Obs! Klikk på breadcrumbs logges til analyseverktøy (Amplitude). Ettersom title i noen apper kan inneholde personopplysninger,
som f.eks. navn på bruker, så logges dette i utgangspunktet kun som [redacted]
til Amplitude.
Om ønskelig kan feltet analyticsTitle
også settes, dersom du ønsker å logge en title. Husk å fjerne eventuelle personopplysninger fra denne!
// Type
export type DecoratorBreadcrumb = {
url: string;
title: string;
analyticsTitle?: string;
handleInApp?: boolean;
};
// Bruk
import { setBreadcrumbs } from "@navikt/nav-dekoratoren-moduler";
setBreadcrumbs([
{ title: "Ditt Nav", url: "https://www.nav.no/person/dittnav" }, // Sender brukeren til definert url
{
title: "Kontakt oss",
url: "https://www.nav.no/person/kontakt-oss/nb/",
handleInApp: true, // Håndteres av onBreadcrumbClick
},
]);
// Bruk med analyticsTitle
setBreadcrumbs([
{ title: "Ditt Nav", url: "https://www.nav.no/person/dittnav" }, // Sender brukeren til definert url
{
title: "Opplysninger for Ola Nordmann",
analyticsTitle: "Opplysninger for <Navn>",
url: "https://www.nav.no/min-innloggede-tjeneste",
},
]);
Kalles med breadcrumb
-parametre dersom handleInApp
var satt til true
. Kan benyttes for client-side routing.
import { onBreadcrumbClick } from "@navikt/nav-dekoratoren-moduler";
import router from "my-routing-library";
onBreadcrumbClick((breadcrumb) => {
router.push(breadcrumb.url);
});
Parameteret languages
(liste av tilgjengelige språk i språkvelgeren) kan endres / settes client-side ved behov.
Aktivt språk kan hentes ut fra cookien decorator-language
.
// Type
export type DecoratorLocale = "nb" | "nn" | "en" | "se" | "pl" | "uk" | "ru";
export type DecoratorLanguageOption =
| {
url?: string;
locale: DecoratorLocale;
handleInApp: true;
}
| {
url: string;
locale: DecoratorLocale;
handleInApp?: false;
};
// Bruk
import { setAvailableLanguages } from "@navikt/nav-dekoratoren-moduler";
setAvailableLanguages([
{ locale: "nb", url: "https://www.nav.no/person/kontakt-oss/nb/" }, // Sender brukeren til definert url
{
locale: "en",
url: "https://www.nav.no/person/kontakt-oss/en/",
handleInApp: true,
}, // Håndteres av onLanguageSelect
]);
Kalles med language
-parametre dersom handleInApp
var satt til true
. Kan benyttes for client-side routing.
import { onLanguageSelect } from "@navikt/nav-dekoratoren-moduler";
import router from "my-routing-library";
onLanguageSelect((language) => {
router.push(language.url);
});
Samtlige parametre kan settes client-side via setParams
dersom setAvailableLanguages
og setBreadcrumbs
ikke er tilstrekkelig.
// Type
export type DecoratorParams = Partial<{
context: "privatperson" | "arbeidsgiver" | "samarbeidspartner";
simple: boolean;
simpleHeader: boolean;
simpleFooter: boolean;
redirectToApp: boolean;
redirectToUrl: string;
language: DecoratorLocale;
availableLanguages: DecoratorLanguageOption[];
breadcrumbs: DecoratorBreadcrumb[];
utilsBackground: "white" | "gray" | "transparent";
feedback: boolean;
chatbot: boolean;
chatbotVisible: boolean;
shareScreen: boolean;
logoutUrl: string;
logoutWarning: boolean;
redirectOnUserChange: boolean;
pageType: string;
}>;
// Bruk
import { setParams } from "@navikt/nav-dekoratoren-moduler";
setParams({
simple: true,
chatbot: true,
});
Hjelpefunksjon for å åpne Chatbot Frida. Denne setter parameteret chatbotVisible=true
og åpner chat-vinduet.
import { openChatbot } from "@navikt/nav-dekoratoren-moduler";
openChatbot();
Etter at en strengere Lov om elektronisk kommunikasjon (ekomloven) ble gjort gjeldende fra 1. januar 2025, har Nav måttet innhente samtykke før verktøy for analyse, statistikk etc kunne bli tatt i bruk. Du kan lese mer i Dekoratøren om bakgrunn og hvordan prinsippene og det juridiske ved samtykke fungerer.
For nav-dekoratoren-moduler har vi laget en rekke hjelpefunksjoner som et ment å bidra til at teamene etterlever den nye ekomloven.
Disse funksjonene er et forslag til hva vi tror teamene vil kunne trenge, så vi håper at team som ønsker seg andre funksjoner melder ifra på #dekoratøren_på_navno på Slack slik at vi kan utvide nav-dekoratoren-moduler og fortsatt gjøre den nyttig for teamene.
Dersom du trenger å lese/skrive cookies som en del av oppstarten i applikasjonen, kan det hende at du må vente til dekoratøren har lastet inn dataene.
const initMyApp = async () => {
await awaitDecoratorData();
doMyAppStuff();
};
Sjekker om en nøkkel er tillatt å sette:
- er den i tillatt-listen
- hvis nøkkelen er markert som frivillig (og dermed krever samtykke): har bruker samtykket til denne type lagring
Funksjonene for å lese og skrive (cookies, localstorage etc) sjekker dette selv automatisk, så denne funksjonen er laget for å gi team en mulighet til å sjekke skrivbarhet uten å faktisk skrive.
Kan brukes for både cookies, localStorage og sessionStorage.
import { isStorageKeyAllowed } from '@navikt/nav-dekoratoren-moduler'
// Returnerer false fordi 'jabberwocky' ikke er i tillatt-listen.
const isJabberwocky = isStorageKeyAllowed('jabberwocky'):
// Selv om 'usertest' er i tillatt-listen har ikke bruker gitt sitt samtykke i dette tenkte eksempelet, så funksjonen returnerer false.
const isUsertestAllowed = isStorageKeyAllowed('usertest-229843829')
Denne returnerer en liste over alle ting som er lov å sette, enten cookies, localStorage etc. Vi tilbyr denne til team som vil lage sine egne løsninger eller som trenger funksjonalitet som ikke finnes i nav-dekoratoren-moduler. I hovedsak tenker vi at isStorageKeyAllowed ovenfor vil fungere best i de fleste tilfeller.
Retunerer tillatt lagring for både cookies, localStorage og sessionStorage.
Denne kan brukes for å sette cookies og være sikker på at det er tillatt å sette de. Funksjonen sjekker på om (1) cookien er i tillatt-listen og (2) brukeren har gitt nødvendige samtykker hvis cookien er frivillig.
Dersom det for eksempel er en cookie som er team har definert som nødvendig kan den settes uansett så lenge den ligger i listen over tillatte cookies.
Dersom cookien er regnet som frivillig vil den ikke kunne settes dersom bruker ikke har gitt samtykke til at Nav kan lagre alle frivillige cookies.
import { setNavCookie, getNavCookie } from "@navikt/nav-dekoratoren-moduler";
// Tillatt fordi tillatt-listen har registrert 'usertest-*' som tillatt cookie.
setNavCookie("usertest-382738");
// Returnerer null fordi 'foobar' ikke er i tillatt-listen.
const foo = getNavCookie("foobar");
Utvider sessionStorage og localStorage og eksponerer de samme funksjonene. Forskjellen er at nav*Storage først sjekker om en nøkkel er tillatt å sette basert på tillattlisten og status på eksisterende samtykke.