Session Timeout
Dette er tingen hver store organisasjon bygger selv, og gjør feil. Enten kommer det ingen advarsel, og brukeren mister et halvutfylt søknadsskjema. Eller dialogen stjeler fokus midt i en setning. Eller skjermleseren leser nedtellingen hvert eneste sekund.
// main.ts, kjøres én gang når appen starterimport { defineFsSessionTimeout } from "@fristil/designsystem/session-timeout"import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/session-timeout.css"
defineFsSessionTimeout()Slik tar du den i bruk
Section titled “Slik tar du den i bruk”Her er økten satt til fem sekunder, så du slipper å vente i 25 minutter. Slutt å røre tastaturet og musa, så kommer varselet.
<!-- Stilarkene siden trenger. Uten byggesteg er det `<link>`, ikke `import`: en nettleser slår ikke opp et pakkenavn. --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/components/frittstaende/session-timeout/session-timeout.css"><!-- Eller alt i én fil: https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/dist/fristil.css --><fs-session-timeout class="fs-session-timeout" warn-at="1500" expires-at="1800" data-ignore-morph></fs-session-timeout>
<!-- Én gang for hele appen, i sidemalen. Ikke én gang per komponent. --><script type="module"> import { defineFsSessionTimeout } from "https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/dist/components/frittstaende/session-timeout/fs-session-timeout.js"
defineFsSessionTimeout()</script>
<script type="module"> const okt = document.querySelector("fs-session-timeout")
okt.addEventListener("session-extend", async () => { await fetch("/api/forleng-okt", { method: "POST" }) })
okt.addEventListener("session-expired", () => { location.href = "/logg-inn?arsak=utlopt" })</script>// src/fristil.d.ts, gir <fs-session-timeout> typer i JSXimport "@fristil/designsystem/react-jsx"import "@fristil/designsystem/session-timeout.css"import { useEffect, useRef } from "react"import { fs } from "@fristil/designsystem/react"import { defineFsSessionTimeout } from "@fristil/designsystem/session-timeout"import "@fristil/designsystem/tokens.css"
defineFsSessionTimeout()
export function Okt() { const ref = useRef<HTMLElement>(null)
useEffect(() => { const element = ref.current if (!element) return
const forleng = () => fetch("/api/forleng-okt", { method: "POST" }) const utlopt = () => { location.href = "/logg-inn?arsak=utlopt" }
element.addEventListener("session-extend", forleng) element.addEventListener("session-expired", utlopt) return () => { element.removeEventListener("session-extend", forleng) element.removeEventListener("session-expired", utlopt) } }, [])
return <fs-session-timeout ref={ref} {...fs.sessionTimeout({ warnAt: 1500, expiresAt: 1800 })} />}<!-- Datastar selv. Uten den gjør `data-`-attributtene under ingenting. --><script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar.js"></script>
<!-- Stilarkene siden trenger. Uten byggesteg er det `<link>`, ikke `import`: en nettleser slår ikke opp et pakkenavn. --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/components/frittstaende/session-timeout/session-timeout.css"><!-- Eller alt i én fil: https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/dist/fristil.css -->
<!-- Én gang for hele appen, i sidemalen. Ikke én gang per komponent. --><script type="module"> import { defineFsSessionTimeout } from "https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/dist/components/frittstaende/session-timeout/fs-session-timeout.js"
defineFsSessionTimeout()</script>
<fs-session-timeout class="fs-session-timeout" warn-at="1500" expires-at="1800" data-ignore-morph data-on:session-extend="@post('/api/forleng-okt')" data-on:session-expired="window.location = '/logg-inn?arsak=utlopt'"></fs-session-timeout>data-ignore-morph er nødvendig her. Uten den forsvinner dialogen i det serveren patcher området rundt.
Hvorfor den eier sitt eget innhold
Section titled “Hvorfor den eier sitt eget innhold”De fleste komponentene i Fristil rører ikke DOM-en serveren har sendt. Denne gjør, og grunnen er at nedtellingen er klientens klokke. Tallet endrer seg hvert sekund ut fra når brukeren sist rørte tastaturet, og det er en tilstand ingen server kan sende. Å patche den over en strøm hvert sekund ville vært meningsløst.
Derfor setter byggefunksjonen data-ignore-morph. Det ber Datastar la innholdet være, slik at en patch ikke river dialogen bort mens den står åpen. Se Markup og oppførsel for hele regelen.
<fs-session-timeout class="fs-session-timeout" warn-at="1500" expires-at="1800" data-ignore-morph></fs-session-timeout>Attributter
Section titled “Attributter”| Attributt | Betydning | Standard |
|---|---|---|
warn-at | Sekunder uten aktivitet før varselet kommer | 1500 (25 minutter) |
expires-at | Sekunder uten aktivitet før økten er ute | 1800 (30 minutter) |
Aktivitet er tastetrykk, klikk og rulling, også rulling i en tabell eller et panel. Mens dialogen står åpen teller ikke aktivitet, ellers ville et tilfeldig museklikk forlenget økten uten at brukeren mente det. Escape i dialogen regnes derimot som «jeg er her», og gjør det samme som knappen: forlenger, og sender session-extend.
Er warn-at eller expires-at ikke et tall større enn eller lik null, brukes standardverdien, og er warn-at ikke mindre enn expires-at, kommer varselet aldri. Komponenten sier fra om begge deler i konsollen.
Etter session-expired og session-logout står komponenten stille til extend() eller reset() kalles. Uten det fikk en app som ikke navigerte bort ny dialog og ny session-expired hvert expires-at-sekund, for en økt som alt var borte.
Hendelser
Section titled “Hendelser”| Hendelse | Når | Hva du gjør |
|---|---|---|
session-warn | Dialogen åpner seg | Som regel ingenting |
session-extend | Brukeren velger å fortsette, med knappen eller Escape | Be serveren forlenge økten |
session-logout | Brukeren velger å logge ut | Send brukeren til utloggingen |
session-expired | Tiden er ute | Send brukeren til innloggingen |
Komponenten vet ikke hvordan økten din forlenges. Den sier fra, du gjør kallet.
Metoder
Section titled “Metoder”| Metode | Hva den gjør |
|---|---|
extend() | Nullstiller klokka, lukker varselet og sender session-extend |
reset() | Nullstiller klokka og lukker varselet uten å sende noe. For en app som alt har forlenget økten selv, som når en autolagring gikk gjennom |
extendSession(element) og resetSession(element) fra @fristil/designsystem/session-timeout gjør det samme, men venter først på at elementet er registrert.
Klasser du kan style
Section titled “Klasser du kan style”| Klasse | Hva det er |
|---|---|
.fs-session-timeout | Vertselementet. Ligger som display: contents og tar ingen plass |
.fs-session-timeout__dialog | Selve dialogen |
.fs-session-timeout__title | Overskriften |
.fs-session-timeout__text | Avsnittet med nedtellingen i |
.fs-session-timeout__count | Tallet som teller ned |
.fs-session-timeout__actions | Raden med knapper |
Form og størrelse leses fra komponentvariabler, med systemets verdi som reserve:
| Variabel | Reserve |
|---|---|
--fs-session-timeout-width | 26rem |
--fs-session-timeout-padding | var(--fs-spacing-5) |
--fs-session-timeout-radius | var(--fs-spacing-1) |
.fs-session-timeout__dialog { --fs-session-timeout-width: 32rem;}Tilgjengelighet
Section titled “Tilgjengelighet”Dialogen er en ekte <dialog> åpnet med showModal(), så fokusfellen, Escape og topplaget kommer fra nettleseren. Den har role="alertdialog", fordi den avbryter noe brukeren ikke ba om å bli avbrutt i.
Tre ting er gjort med vilje, og alle tre er grunner til at dette er vanskelig å få riktig selv:
- Fokus går tilbake dit brukeren var. Uten det starter neste tastetrykk på toppen av siden, midt i et skjema.
- Nedtellingen leses ikke opp hvert sekund. Tallet på skjermen har
aria-hidden, og et eget område melder fra ved to minutter, ett minutt, 30 sekunder og 10 sekunder. En opplesning i sekundet gjør dialogen ubrukelig. - Knappen som forlenger står først. Det er den de fleste vil ha, og den skal være det første tastaturet treffer.