Compare commits
2 commits
main
...
alertsHove
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdd5c2ea2d | ||
|
|
e7e6a7ebd8 |
49 changed files with 491 additions and 1766 deletions
53
Dependencies.md
Normal file
53
Dependencies.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Dependencies
|
||||
|
||||
## Frontend
|
||||
|
||||
- Typescript
|
||||
> Javascript med typeing
|
||||
|
||||
- Next.js
|
||||
> React-basert frontend rammeverk
|
||||
|
||||
- TailwindCSS
|
||||
> CSS rammeverk bestående av små utility-klasser
|
||||
|
||||
- Axios
|
||||
> HTTP klient-rammeverk/bibliotek
|
||||
|
||||
- Aksel
|
||||
> NAVs design system som inkluderer ikoner, komponenter etc.
|
||||
|
||||
- useSWR
|
||||
> Bibliotek som forenkler datafetching over Axios
|
||||
|
||||
## Backend
|
||||
|
||||
- Kotlin
|
||||
> Moderne Java basert språk
|
||||
|
||||
- HikariCP
|
||||
> Database connection pool som etablerer forbindelser mellom database og backend
|
||||
|
||||
- PostgreSQL
|
||||
> SQL database rammeverk
|
||||
|
||||
- Ktor
|
||||
> Asynkron HTTP server ~ RESTAPI
|
||||
|
||||
- JUnit
|
||||
> Testrammeverk for backend i Kotlin
|
||||
|
||||
- Flyway
|
||||
> Databasemigrering rammeverk
|
||||
|
||||
- Exposed
|
||||
> ORM for å skrive SQL-spørringer i Kotlin
|
||||
|
||||
- Logback
|
||||
> Loggføringsbibliotek
|
||||
|
||||
## Build
|
||||
|
||||
- yarn
|
||||
|
||||
- gradle
|
||||
452
Dokumentasjon.md
452
Dokumentasjon.md
|
|
@ -1,452 +0,0 @@
|
|||
# Sprik
|
||||
|
||||
## Introduksjon
|
||||
Som en del av forarbeidet til utviklingen av Sprik ble det gjort omfattende dokumentasjon av behovet for en ny løsning, og hvordan en eventuell løsning ville være hensiktsmessig å utforme.
|
||||
|
||||
Dokumentasjonen er resultatet av brukerintervjuer, innsiktsarbeid, prototyping og funksjonalitetsprioritering.
|
||||
|
||||
Dokumentasjonen beskriver teknologien bak applikasjonen, referater fra innsiktsarbeidet, lenker til prototypeskissering i Figma, ROS og definerer problemet som Sprik skal løse.
|
||||
|
||||
## Innholdsfortegnelse
|
||||
|
||||
[Prosjekt plan](#prosjekt-plan)
|
||||
|
||||
- [Bakgrunnsinfo](#bakgrunnsinfo)
|
||||
|
||||
- [Problemdefinisjon](#problemdefinisjon)
|
||||
|
||||
- [Objective / Mål](#objective--mål)
|
||||
|
||||
- [Key Results](#key-results)
|
||||
|
||||
[Teknologier](#teknologier)
|
||||
|
||||
- [React & Typescript](#react--typescript)
|
||||
- [Aksel & TailwindCSS](#aksel--tailwindcss)
|
||||
- [Axios & Ktor](#axios--ktor)
|
||||
- [Kotlin](#kotlin)
|
||||
- [PostegreSQL & Flyway](#postgresql--flyway)
|
||||
- [HikariCP & Exposed](#hikaricp--exposed)
|
||||
- [JUnit & Cypress](#junit--cypress)
|
||||
- [Yarn & Gradle](#yarn--gradle)
|
||||
|
||||
[Kartlegging](#kartlegging)
|
||||
|
||||
- [Brukerintervjuer/tester](#brukerintervjuertester)
|
||||
|
||||
- [Utviklingsteam](#utviklingsteam)
|
||||
|
||||
- [Utvikler #1](#utvikler-1)
|
||||
|
||||
- [Utvikler #2](#utvikler-2)
|
||||
|
||||
- [Fagperson](#fagperson)
|
||||
|
||||
- [Saksbehandlere](#saksbehandlere)
|
||||
|
||||
- [Saksbehandler #1](#saksbehandler-1)
|
||||
|
||||
- [Saksbehandler #2](#saksbehandler-2)
|
||||
|
||||
- [Saksbehandler #3](#saksbehandler-3)
|
||||
|
||||
- [Saksbehandler #4](#saksbehandler-4)
|
||||
|
||||
- [Saksbehandler #5](#saksbehandler-5)
|
||||
|
||||
- [Brukerhistorier og ønsker](#brukerhistorier-og-ønsker)
|
||||
|
||||
- [Funksjonalitet basert på ønsker og problemløsning (MoSCoW)](#funksjonalitet-basert-på-ønsker-og-problemløsning-moscow)
|
||||
|
||||
[Jus & Ros](#jus--ros)
|
||||
|
||||
[Design](#design)
|
||||
|
||||
## Prosjekt plan
|
||||
|
||||
### Bakgrunnsinfo
|
||||
Når saksbehandlere oppdager feil eller avvik i sykepengeløsningen Speil må dette meldes til utviklingsteamet.
|
||||
|
||||
Vår oppgave var å få innsikt i utfordringer ved dagens løsning, behovene til saksbehandlere og utviklingsteamet, samt påbegynne en løsning basert på innsiktsarbeidet.
|
||||
|
||||
#### Utfordringer med dagens løsning
|
||||
- Dagens løsning for kommunikasjon mellom saksbehandlere og teamet er både treig og lang. Saksbehandler → Teams → Coach → slack → Teams
|
||||
|
||||
- Det er ikke tilstrekkelig tilgangskontroll for å verne om brukere (personvern), under innmelding av saker. Saker relatert til kode 6 og 7 brukere er veldig utsatte i dagens løsning da de kan formidles mot mange som ikke har tjenstlig behov for informasjonen.
|
||||
|
||||
- De fleste saksbehandlere har ikke direkte mulighet til å melde ifra om feil og feature requests hvilket kan føre til at mange feil går under radaren.
|
||||
|
||||
- Uoversiktlig presentasjon og formidling av saker fører til at saker rapporteres inn gjentatte ganger (dobbelt arbeid), at de kan glemmes bort, og i verste fall gå uløst.
|
||||
|
||||
- Det er et utydelig skille mellom feature-requests og innmeldte feil i dagens løsning.
|
||||
|
||||
- Det er vanskelig å se hvem som er egnet til å besvare
|
||||
|
||||
### Problemdefinisjon
|
||||
Applikasjonens formål er i henhold til oppgaveteksten:
|
||||
|
||||
> Lage en applikasjon der saksbehandlere kan melde inn feil/mangler/ønsker. Og potensielt en visning over hva som er meldt inn.
|
||||
>
|
||||
|
||||
> Feil med speil skal kunne gi både saksbehandlere og utviklere en raskere og bedre flyt i kommunikasjonen. Dette vil føre til at vi utviklere kan oppdage og rette opp i feil raskere. Det vil forhåpentligvis også føre til en bedre saksbehandleropplevelse.
|
||||
>
|
||||
|
||||
### Objective / Mål
|
||||
"Lage et fantastisk produkt som har ekstremt stor verdi for de fine saksbehandlerne og strålende utviklerne."
|
||||
|
||||
Dette mener vi at vi har fått til når:
|
||||
- 80% av saksbehandlere klarer å melde inn feil (KR1)
|
||||
- 75% av brukere synes Sprik er mer oversiktlig enn dagens løsninger (KR2)
|
||||
- Ingen uten tjenstlig behov har tilgang til persondata i innmeldte saker (KR3)
|
||||
|
||||
#### Key Results
|
||||
*KR1 og KR2:*
|
||||
- Ikke hatt brukertester med saksbehandlere der de får prøve å bruke applikasjonene selv grunnet mangel på tid. Derfor har vi ikke målbare tall.
|
||||
|
||||
*KR3:*
|
||||
- Har foreløpig ikke implementert tilgangskontroll.
|
||||
|
||||
*Fokus i sommer:*
|
||||
- Viktige saker første fire uker:
|
||||
- Få på plass basic funksjonalitet
|
||||
- Forstå hva tjenesten innebærer og illustrere dette i prototype
|
||||
- Få deploya applikasjonen i devmiljø
|
||||
- Viktige saker siste fire uker:
|
||||
- Ha en brukervennlig applikasjon
|
||||
- Et utvalg av brukere har begynt å teste/ta i bruk applikasjonen
|
||||
- Ha en overføringsklar dokumentasjonsbase
|
||||
- Implementere alle must-haves
|
||||
|
||||
## Teknologier
|
||||
|
||||
### React & Typescript
|
||||
Frontend applikasjonen bygges med React på TypeScript
|
||||
|
||||
### Aksel & TailwindCSS
|
||||
Applikasjonen er hovedsaklig bygget av komponentbiblioteket til NAVs designsystem Aksel, men egen styling gjøres gjennom utility-first rammeverket TailwindCSS. Tailwind sine små utilityklasser er kompatible med Aksel og gjør at styling går svært fort. Ikoner og farger er også hentet fra Aksel.
|
||||
|
||||
### Axios & Ktor
|
||||
Axios benyttes som HTTP klient-rammeverk for kommunikasjon med endepunkter i backend. Ktor er en asynkron HTTP server, som brukes som et HTTP API. Ktor hører til Kotlin språket.
|
||||
|
||||
### Kotlin
|
||||
Kotlin er et moderne javabasert språk. Applikasjonens backend er skrevet i Kotlin.
|
||||
|
||||
### PostgreSQL & Flyway
|
||||
Databasen er skrevet i PostgreSQL og i backenden brukes Flyway rammeverket for migrering av databasen slik at en enkelt kan gjøre endringer på databasen
|
||||
|
||||
### HikariCP & Exposed
|
||||
HikariCP danner en database connection pool mellom DB og backend. Exposed er jetbrains sin SQL-ORM for Kotlin, som brukes til å gjøre spørringer mot databasen. Sammen utgjør de kommunikasjonen mellom Backend og database.
|
||||
|
||||
### JUnit & Cypress
|
||||
JUnit er et Kotlin kompatibelt testrammeverk, og Cypress er et testrammeverk for frontend som kan utføre både komponenttesting og ende-til-ende testing. Cypress-axe er en pakke for cypress som kan brukes til UU-testing.
|
||||
|
||||
### Yarn & Gradle
|
||||
Yarn og Gradle er dependency-management verktøyene for frontend og backend applikasjonene.
|
||||
|
||||
## Kartlegging
|
||||
|
||||
### Brukerintervjuer/tester
|
||||
|
||||
#### Utviklingsteam
|
||||
|
||||
##### Utvikler #1
|
||||
- *Hva anser du som en utfordring ved å bruke dagens løsning (slack)?*
|
||||
- Utfordring at mange av saksbehandlerne ikke er på slack
|
||||
- Teams = møk
|
||||
- Delayed rapportering fordi det er en lang vei
|
||||
- Gjentakende rapportering av samme feil
|
||||
- Noen kan vurdere det som meldes inn før det går videre til teamet.
|
||||
- Usikker på om redteam er nødvendig i kommunikasjonsprosessen
|
||||
- Tråd kommunikasjonen er tungvinnt
|
||||
- Ting vi har avklart drukner i slack
|
||||
|
||||
- *Er det noe du er fornøyd med rundt dagens løsning?*
|
||||
- Redteam løsningen vi har i dag fungerer ganske bra, med tanke på å rotere på hvem som er redteam
|
||||
|
||||
- *Hva slags arbeidsflyt ønsker du å ha med ny løsning?*
|
||||
- Varslinger nice, ellers lite preferanser
|
||||
|
||||
- *Hva er spesielt viktig for saksbehandlere/utviklere/jurister/designer/… å få ut av en slik plattform.*
|
||||
- Vanskelig å fange opp hvor stor grad en feil skjer.
|
||||
- Jetbrains har en issue tracker med voting
|
||||
- De kan se hvilke feil som er meldt inn og saksbehandlere skal kunne vote opp spesiellt relevante cases for å se “hvor skoen trykker i systemet”
|
||||
|
||||
- *Hvilke data ønsker du skal være presentert om en sak i Sprik?*
|
||||
- Greit å ha med innmelder av en sak
|
||||
- Greit at utvikler kan labele saker mtp app og sann
|
||||
- Kunne generere lapper i Trello.
|
||||
|
||||
- *Hvordan kunne du sett for deg at dataen presenteres i sprik?*
|
||||
- Enkelt kunne skille feil og feature requests
|
||||
- Enkle detaljer
|
||||
- Sortere etter traction etc
|
||||
- Kanskje tenk gallery view, eller feed.
|
||||
- Type feil: Feilinfo, handlingsfeil, grensesnittsfeil etc.
|
||||
|
||||
##### Utvikler #2
|
||||
- *Feature requests*
|
||||
- Vanskelig å sørge for at saksbehandlere ikke blir demotiverte dersom endringene ikke skjer.
|
||||
- Feature voting side hvor man kan vote opp feature forslag
|
||||
- Lar utviklere se hvor skoen trykker
|
||||
- Veldig delte meninger
|
||||
|
||||
- *Hvilke behov ønsker du at applikasjonen skal dekke? (forstå hva folk vil bruke det til)*
|
||||
- “Jeg bruker appen når jeg er redteam”
|
||||
- Enkel måte å få vite om noe er galt, vite om noe haster eller ikke”
|
||||
- Ikke en stor blob med tekst men kategorisert og organisert.
|
||||
- Voting er bra for å se hva som er veldig aktuellt.
|
||||
- Hashtags/emneknagger/tags for å organisere i type feil → ser antall feil av en type.
|
||||
|
||||
- *Hvilken funksjonalitet er det viktig for deg at er med i applikasjon?*
|
||||
- “Feilen kommer lett frem”, “beskrivelse av casen” hadde vært enkelt med en kort tittel på problemet.
|
||||
- Oversikt over hva som er meldt inn tidligere
|
||||
|
||||
- *Hvilken funksjonalitet tenker du har mest verdi for deg? Altså hva er viktigst først?*
|
||||
- Å kunne kategoriesere hvilke feil man har
|
||||
- Få inntrykk av hvilke features som eksisterer samt muligheten til å komme med tilbakemelding.
|
||||
|
||||
- *Hva anser du som en utfordring ved å bruke dagens løsning (Slack)?*
|
||||
- Ikke god oversikt over hva som er meldt ifra før
|
||||
- Vanskelig å se hvem som passer til å svare på spm
|
||||
|
||||
- *Hva er den største av disse utfordringene?*
|
||||
- Vanskelig å ha oversikt over hva som er meldt inn (enklere med status, men tungvinnt).
|
||||
- Mistenker dobbelt arbeid
|
||||
|
||||
- *Er det noe du er fornøyd med rundt dagens løsning?*
|
||||
- Mulighet til å ta kontakt med saksbehandlere hvis det trengs (ved feks ønske om flere opplysninger)
|
||||
- Trådsvar - nais to have, ikke kritisk
|
||||
|
||||
- *Hva slags arbeidsflyt ønsker du å ha med ny løsning?*
|
||||
- Er en del felter som ville gjort det enklere (Dette går under data også)
|
||||
- Skjermbilde
|
||||
- Tags
|
||||
- AktørID
|
||||
- Egendefinerte tags
|
||||
- Kan være en utfordring med flere måter å definere et begrep (grunnbeløp vs G vs 6G)
|
||||
- Tildele til personer
|
||||
|
||||
- *Hva er spesielt viktig for saksbehandlere/utviklere/jurister/designer/… å få ut av en slik plattform.*
|
||||
- Unngå dobbeltarbeid
|
||||
- Sortere traction eller hvor kritisk det er
|
||||
|
||||
- *Hvilke data ønsker du skal være presentert om en sak i Sprik*
|
||||
- +aktøride
|
||||
- +skjermbilde
|
||||
- +tags
|
||||
- +tittel,
|
||||
- +status
|
||||
- +innmeldt saksbehandler
|
||||
- statusflagg?
|
||||
- forklarende bilde?
|
||||
- Saksnummer?
|
||||
- Beskrivelse?
|
||||
- innsender?
|
||||
- mer?
|
||||
|
||||
- *Hvordan kunne du sett for deg at dataen presenteres i sprik?*
|
||||
- Galleri-visning
|
||||
|
||||
- *Syntes du at redteam ordningen som et vaktlag skal implementeres videre? har du noe forslag*
|
||||
- Red team har tatt lang tid å få til å fungere
|
||||
- Er ikke nødvendigvis beste løsning
|
||||
- Handler om at man skal rullere for å få noen til å ta ansvar
|
||||
|
||||
##### Fagperson
|
||||
- *Hva er din opplevelse av dagens løsning?*
|
||||
- Skille mellom innspill og feil kan være litt uklart
|
||||
- Det er bra med direkte kontakt (fine med meldingstjenesten)
|
||||
- En del som meldes inn flere ganger
|
||||
- En del saksbehandlere man ikke har kontakt med
|
||||
|
||||
- *Hvorfor fungerer ikke dagens løsning?*
|
||||
- Ikke kontakt med alle saksbehandlere ~ saksbehandler-kanalen kan bli litt uoversiktelig
|
||||
- Viktig-info kanalen funker fint ettersom det kun kommer enveis-meldinger
|
||||
- Er nok en del feil som glipper (går under radaren/ikke blir meldt inn)
|
||||
|
||||
- *Hva er de største utfordringene i dagens løsning?*
|
||||
- Går under radaren
|
||||
- Hvorfor? Travel hverdag
|
||||
- Slack ikke optimal til oppfølging
|
||||
|
||||
- *Hva fungerer godt i dagens løsning?*
|
||||
- Funker bra at det er en direkte kontakt mellom saksbehandlere og utviklingsteam (ikke erstatte dette)
|
||||
- Gir ett forhold til brukeren og løsninga si
|
||||
- Mange ting som blir fiksa fortløpende
|
||||
|
||||
- *Hva er det viktigste for deg som (utvikler/saksbehandler/…) å oppnå med plattformen?*
|
||||
- Hjelpe dem med å jobbe med de riktige tingene
|
||||
- Slippe å bruke unødvendig tid
|
||||
|
||||
- *Hva tenker du er formålet med Sprik?*
|
||||
- Å fjerne gapet mellom saksbehandlere og utviklingsteam
|
||||
- Gapet = de som ikke er i Slack, ikke alle tør å poste i Slack (fører til lite kontakt)
|
||||
- Få flere informerte saksbehandlere
|
||||
|
||||
- *ukategorisert*
|
||||
- en ting som kunne vært kult hvis vi skal jobbe med målinger, kunne vært kult med temperaturmålinger for saksbehandling (hvordan trives du med å jobbe i speil, får du hjelp når du trenger det, hvordan har du det, hvordan er motivasjonen, målt over tid for å påvirke prouktet)
|
||||
- hvordan gjøres: brukt en vanlig helsesjekk i starten for å sjekke om de vil bruke denne, evt. spesiallaget noe i speil der det kommer en boble i speil eksempelvis hver fredag som tar 30sek å svare på
|
||||
- kunne forbedret dagens løsning
|
||||
- vanlig spørsmål og svar (q&a forum)
|
||||
- hvordan gjør jeg dette og dette
|
||||
- løsning: faq side
|
||||
- tips
|
||||
- intervjue de som ikke er i slack av saksbehandlere (ikke like mye innsikt, mer realistisk brukeropplevelse)
|
||||
- rammeverk å tenke på når vi skal arbeide:
|
||||
- kjapt å lage → tar lang tid å lage (x akse)
|
||||
- lav verdi ^ høy verdi (y akse)
|
||||
- lapper med forslag man plasserer på grafen
|
||||
- prioriterer kjapt å lage med høy verdi
|
||||
- redteam fungerer?
|
||||
- funker, men må kanskje gjøres på en annen måte ved ny løsning
|
||||
- det de blir tagga i blir oftest løst, men er fortsatt ting som kan forsvinne pga. mengden meldinger
|
||||
- ikke alle i redteam er like på, eksempelvis jurister, til å svare på saker
|
||||
|
||||
#### Saksbehandlere
|
||||
|
||||
##### Saksbehandler #1
|
||||
- *Hva skal vi kalle hvert element (lapp, feilmelding, feil)?*
|
||||
- Innmeldte feil (med parantes på)
|
||||
- *Hva syntes du om statuslappene?*
|
||||
- Likte statuslabelsa
|
||||
- Dropdown var veldig intuitivt
|
||||
- *For å holde oversikt over egne saker, syntes du det funker å bare bruke filtrering for dette? (evt. bruke egne farger for lapper eller labels)*
|
||||
- filtrering enten høyere eller venstre side, mer naturlig på venstresiden
|
||||
- egne saker → filtrer etter initialer
|
||||
- filtrer automatisk etter kronologisk tid, tidligst først
|
||||
- egen farger for egne saker kan bli litt mye
|
||||
- *Hva tenker du om å se feil på denne måten? (oversiktelig?)*
|
||||
- Førsteinntrykk er mye, men etterhvert veldig oversiktelig
|
||||
- “melde inn feil/funksjonalitetsønsker”-knapper legges høyere
|
||||
- *Hva er det første du ser?*
|
||||
- Mye informasjon, mye tekst, må bruke litt tid for å forstå hva det egt er
|
||||
- “Hva er søkefeltet til”-spørsmål
|
||||
|
||||
##### Saksbehandler #2
|
||||
- *Hvordan syntes du det er å jobbe med speil idag?*
|
||||
- *Kan du fortelle litt om hvordan du bruker Speil i dag?*
|
||||
- Skjønte ikke helt spørsmålet her
|
||||
- *Hvordan går du frem når du finner feil i Speil i dag?*
|
||||
- Tar kontakt med coacher eller super
|
||||
- De melder videre
|
||||
- eller kan melde fra i support-kanal på teams
|
||||
|
||||
- *Hvordan synes du feilinnmelding angående Speil fungerer i dag?*
|
||||
- Slack ble fjernet som forstyrrende element i arbeid
|
||||
- mener de fortsatt burde hatt slack, lavere terskel for å melde inn
|
||||
- tungvinnt å gå via coacher
|
||||
- La kanskje til henne en mening om lang vei??
|
||||
|
||||
##### Saksbehandler #3
|
||||
- *Hvordan syntes du det er å jobbe med speil idag?*
|
||||
- *Kan du fortelle litt om hvordan du bruker Speil i dag?*
|
||||
- *Hvordan går du frem når du finner feil i Speil i dag?*
|
||||
- Går til coach som melder til utvikler
|
||||
- Svarer som de gjør fordi hovedproblemet med å jobbe med sykepenger fordi det er for mange som ikke kan sykepenger
|
||||
- omfattende domene
|
||||
- Noen er raske fordi vi har produksjonstall
|
||||
- Lang tid å skaffe domene kunnskap
|
||||
- Mange tror de kan sette seg ned og bare gjøre ting, det er mye å sette seg inn i
|
||||
|
||||
- *Hvordan synes du feilinnmelding angående Speil fungerer i dag?*
|
||||
- Det er så som så
|
||||
- tror at utfordringen er at noen enheter er flinke til å bruke faglige ressurser rundt seg, samtidig som andre bruker support rollen
|
||||
- Bruker ikke mye tid der, men drukner i repetetive innmeldinger.
|
||||
- brukerutbetaling skaper mange feil → større konsekvens
|
||||
- Siden det er så komplisert det vi jobber med (sykepenger) → fordi ting gjøres automatisk
|
||||
|
||||
##### Saksbehandler #4
|
||||
- *Hva er det viktigste for deg i en ny løsning for feilinnmelding?*
|
||||
- det må være toveiskommunikasjon
|
||||
- å melde inn er ikke nok så lenge man ikke får noe respons
|
||||
|
||||
##### Saksbehandler #5
|
||||
- *Hvordan synes du feilinnmelding angående Speil fungerer i dag?*
|
||||
- *Er det noe som fungerer godt?*
|
||||
- *Er det noe som fungerer mindre godt?*
|
||||
- ordinær opplæring innenfor fag og systemer, fungerte ikke fordi ingen har kunnskaper om speil
|
||||
- er veldig misfornøyd med oversikten over benken min
|
||||
|
||||
### Brukerhistorier og ønsker
|
||||
| Ønsker | Intervjuobjekt | Prioritet | Brukerhistorie |
|
||||
| - | - | - | - |
|
||||
| Kunne se helt tydelig, uten å grave i diskusjonstråd, hva status og konklusjon er for en sak. | Saksbehandler | | - Jeg vil se behandlingsstatus på en sak <br /> - Jeg ønsker å enkelt kunne finne frem konklusjonen for en lukket sak |
|
||||
| Ønsker type nyhets feed eller gallery view | Utvikler | | - Jeg vil se en ryddig og organisert visning av innmeldte saker |
|
||||
| Ryddig oversikt over innmeldte saker | Utvikler | | - Jeg vil se en ryddig og organisert visning av innmeldte saker |
|
||||
| Voting er bra for å se hva som er aktuelt | Utvikler | | - Jeg vil se hvor aktuell en sak er |
|
||||
| Måle “traction” på ulike saker for å fange opp i hvor stor grad en feil skjer. Foreslår et voting system. Hvor trykker skoen i systemet. Fint om utviklere kan sortere etter traction | Utvikler | Største ønske | - Jeg vil se hvor akutell en sak er <br /> - Jeg ønsker å sortere etter hvor aktuell en sak er |
|
||||
| Se om en sak er rapportert tidligere evt behandlet (unngå gjentakende rapportering) | Saksbehandler | Største ønske | - Jeg vil sjekke om en sak er rapportert inn tidligere <br /> - Jeg vil se behandlingsstatus på en sak |
|
||||
| Tydelig skille mellom rapporterte feil og feature requests | Utvikler | | - Jeg vil se tydelig skille mellom feature requests for en sak jeg "følger" |
|
||||
| Bli varslet om aktivitet på en sak/post (diskusjon, status endringer, etc.). Da slipper man å overvåke. | Saksbehandler | | - Jeg vil varsles ved endringer/aktiviteter for en sak jeg "følger" |
|
||||
| Kunne være i direkte kontakt med utviklere | Saksbehandler | | - Jeg ønsker å ha direkte kontakt med saksbehandler/utvikler |
|
||||
| Utvikler skal kunne varsle saksbehandler dersom mer informasjon om sak trengs for å løse den. | Saksbehandler | | - Jeg ønsker å ha direkte kontakt med saksbehandler/utvikler |
|
||||
| Kunne kontakte saksbehandler dersom det trengs for ytterligere info om saken | Utvikler | | - Jeg ønsker å ha idrekte kontakt med saksbehandler/utvikler |
|
||||
| Kunne søke opp saker på nøkkelord | Saksbehandler | Største ønske | - Jeg ønsker å kunne søke opp saker på nøkkelord og tagger |
|
||||
| Generere lapper på en sak i Trello | Utvikler | Nice to have | - Jeg ønsker å lage en lapp på en sak i Trello |
|
||||
| Mulighet til å initiere samtale relatert til posten. Utviklere og saksbehandlre kan ha en dialog som kan organiseres i en tråd festet til en post. | Saksbehandler | | - Jeg ønsker å lese/skrive i diskusjonstråd for en sak |
|
||||
| Trådsvar | Utvikler | Nice to have | - Jeg ønsker å lese/skrive i diskusjonstråd for en sak |
|
||||
| Kunne se en diskusjonstråd eller annen aktivtet/varsler rundt en sak. | Saksbehandler | | - Jeg ønsker å lese/skrive i diskusjonstråd for en sak <br /> - Jeg vil varsles ved endringer/aktiviteter for en sak jeg "følger" |
|
||||
| En sak skal kunne innehold skjermbilder, beskrivelse, aktør-id og dato(er) | Saksbehandler | | - Jeg ønsker å opprette/lese en sak som inneholder tittel, beskrivelse, skjermbilder, datoer, innmelder, feiltype (grensesnitt, handling, logik) og behandlingsstatus |
|
||||
| Innmelder må være felt på en sak, type feil (grensesnitt, handlingsfeil, verdifeil) | Utvikler | | - Jeg ønsker å opprette/lese en sak som inneholder tittel, beskrivelse, skjermbilder, datoer, innmelder, feiltype (grensesnitt, handling, logik) og behandlingsstatus |
|
||||
| Feilen kommer lett frem med en beskrivelse og tittel | Utvikler | | - Jeg ønsker å opprette/lese en sak som inneholder tittel, beskrivelse, skjermbilder, datoer, innmelder, feiltype (grensesnitt, handling, logik) og behandlingsstatus |
|
||||
| Sak burde ha aktørid, mulighet for skjermbilde opplastning, tags, tittel, status. innmelder (saksbehandler) | Utvikler | | - Jeg ønsker å opprette/lese en sak som inneholder tittel, beskrivelse, skjermbilder, datoer, innmelder, feiltype (grensesnitt, handling, logik) og behandlingsstatus |
|
||||
| Oversikt over hva som støttes i Speil. Funksjonalitetsoversikt (kommunikasjonskanal for ny funksjonalitet i Speil) | Saksbehandler | | - Jeg ønsker å se hvilken funksjonalitet som Speil har |
|
||||
| Få inntrykk av hvilke features som eksisterer samt. muligheten til å komme med tilbakemelding | Utvikler | Største ønske | - Jeg ønsker å se hvilken ufnksjonalitet som Speil har |
|
||||
| Se om saken haster å løse | Utvikler | | - Jeg ønsker å se om en sak haster å løse |
|
||||
| Utviklere skal kunne gi en label til en sak ifht. relatert app | Utvikler | | Jeg ønsker å tildele en sak en emneknagg |
|
||||
| Kategoriere hvilke typer feil som finnes | Utvikler | Største ønske | - Jeg ønsker å tildele en sak en emneknagg |
|
||||
| Hashtags/emneknagger|tags for å organisere i type feil -> ser antall feil av en type. Disse kan være egendefinerte | Utvikler | | - Jeg ønsker å tildele en sak en emneknagg <br /> - Jeg ønsker å se antall aktive saker på en emneknagg |
|
||||
| Ha et "beredskapsteam" (redteam), som svarer raskt | Saksbehandler | REDTEAM | |
|
||||
| Låse en løst tråd??? | Saksbehandler | | |
|
||||
| Vurdere en innmeldt sak før den sendes videre til utviklingsteam - for å unngå gjentakende rapportering | Utvikler | |
|
||||
|
||||
|
||||
### Funksjonalitet basert på ønsker og problemløsning (MoSCoW)
|
||||
|
||||
| Funksjonalitet | Implementasjonsdetaljer | MoSCoW | Status |
|
||||
| - | - | - | - |
|
||||
| Oppdatere innmeldt feil | | Must have (dev) | Done (mangler aktorid) |
|
||||
| Saksbehandlere skal kunne melde inn saker | • Legge til en god beskrivelse av saken (~ juss) <br /> ◦ Skjermbilder, aktør-id, datoer <br /> ◦ Se en oversikt over meldte saker (egne saker? ~ juss) | Must have (dev) | Done |
|
||||
| Kunne se innmeldte feil | | Must have (dev) | Done |
|
||||
| Teamet skal kunne gi beskjed om at saker er løst | | Must have (dev) | Done |
|
||||
| Enkelt se konklusjon av en sak | | Must have (dev) | Done |
|
||||
| Søkefunksjonalitet | | Must have (dev) | Done |
|
||||
| Redigere innmeldt feil | | Should have | Done |
|
||||
| Filtrering av saker etter type feil og lables | | Should have | Started frontend |
|
||||
| Gi labels/kategorisering av/til feil | | Should have | Not started |
|
||||
| Kunne oppdage at noe er meldt inn tidligere | | Could have | Not started |
|
||||
| Kunne stemme på saker for å måle "hvor skoen trykker i systemet" | | Could have | Not started |
|
||||
| Trådsvar | | Could have | Not started |
|
||||
| Oversikt over kjente feil / løsninger | | Could have | Not started |
|
||||
| Opprette Trello lapper direkte fra appen på en rapportert sak | | Will not have | Not started |
|
||||
| Formidle støttet funksjonalitet i Speil | | Will not have | Not started |
|
||||
| Komme med tilbakemelding på støttet funksjonalitet i Speil | | Will not have | Not started |
|
||||
| FAQ side om Speil | | Will not have | Not started |
|
||||
| Sortering av saker etter traction | | Will not have | Not started |
|
||||
| Ved jobbing med målinger hadde det vært kult med temperaturmålings for saksbehandling (spørsmål rundt trivsel målt over tid for å påvirke produktet) | | Will not have | Not started |
|
||||
| Direkte kontakt mellom de to partene | | Must have (prod) | Not started |
|
||||
|
||||
## Juss & ROS
|
||||
|
||||
Hensyn å ta:
|
||||
- Hvem har tjenstlig behov for å se innmeldte feil?
|
||||
- Tilgangskontroll
|
||||
- Logging og sporing
|
||||
- Skal alle kunne se alle felter av innmeldte feil?
|
||||
- Skal kun RedTeam se saker?
|
||||
- Personvernhensyn
|
||||
- Akørid må nesten med både for å kunne sjekke en sak, men også for å logge hvordan en brukers info er behandlet
|
||||
- Ha info-bokser for å minne på at personopplysninger ikke skal deles
|
||||
- Kan ha en pop-up som kommer når man trykker "meld inn sak" som ber innmelder dobbeltsjekke personopplysninger
|
||||
- Deling av personopplysninger i skjermbilde?
|
||||
- Færre muligheter for å skrive fritekst kan redusere sannsynligheten for å dele for mye, men kan bli vanskelig med standard kategorier som er dekkende
|
||||
- Spesielle hensyn å ta ang. kode 6 og 7?
|
||||
|
||||
> ROS er påbegynt og registert i TryggNok
|
||||
|
||||
## Design
|
||||
- Applikasjonen er skissert i Figma.
|
||||
- Figma prosjektet finner du [her](https://www.figma.com/files/810213623608415105/team/1256163063148444981).
|
||||
- Underveis i designprosessen har UX/UI-Designer i PO-Helse gitt råd.
|
||||
- Prototypen er raffinert gjennom flere iterasjoner med brukerintervjuer av fagfolk, utviklere og saksbehandlere.
|
||||
- Prototypen bygges på designsystemet Aksel sine tokens og komponenter.
|
||||
13
backend/src/main/kotlin/no/nav/helse/sprik/Test.kt
Normal file
13
backend/src/main/kotlin/no/nav/helse/sprik/Test.kt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package no.nav.helse.sprik
|
||||
|
||||
import kotlinx.serialization.*
|
||||
|
||||
@Serializable
|
||||
data class Test (
|
||||
var ord: String,
|
||||
var tall: Int
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "Test(ord='$ord', tall=$tall)"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
package no.nav.helse.sprik.db
|
||||
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.aktorid
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.arbeidsstatus
|
||||
import com.typesafe.config.ConfigException.Null
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.beskrivelse
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.dato
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.haster
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.id
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.kommentar
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable.tittel
|
||||
import no.nav.helse.sprik.modell.Feilmelding
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import java.time.LocalDateTime
|
||||
|
||||
class FeilmeldingRepository {
|
||||
fun lagre(feilmelding: Feilmelding) {
|
||||
|
|
@ -22,25 +18,15 @@ class FeilmeldingRepository {
|
|||
it[FeilmeldingTable.tittel] = feilmelding.tittel
|
||||
it[FeilmeldingTable.beskrivelse] = feilmelding.beskrivelse
|
||||
it[FeilmeldingTable.dato] = feilmelding.dato
|
||||
it[FeilmeldingTable.arbeidsstatus] = feilmelding.arbeidsstatus
|
||||
it[FeilmeldingTable.haster] = feilmelding.haster
|
||||
feilmelding.aktorid?.also { aktorid ->
|
||||
it[FeilmeldingTable.aktorid] = aktorid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun radTilFeilmelding(rad: ResultRow) = Feilmelding(
|
||||
id = rad[id],
|
||||
private fun radTilFeilmelding(rad: ResultRow) = Feilmelding(
|
||||
tittel = rad[tittel],
|
||||
beskrivelse = rad[beskrivelse],
|
||||
dato = rad[dato],
|
||||
arbeidsstatus = rad[arbeidsstatus],
|
||||
haster = rad[haster],
|
||||
kommentar = rad[kommentar],
|
||||
aktorid = rad[aktorid]
|
||||
dato = rad[dato]
|
||||
)
|
||||
|
||||
fun hentAlleFeilmeldinger(): List<Feilmelding> = transaction {
|
||||
|
|
@ -48,31 +34,11 @@ class FeilmeldingRepository {
|
|||
}
|
||||
|
||||
fun hentSokteFeilmeldinger(sokeord: String): List<Feilmelding> = transaction {
|
||||
val sok = "%${sokeord.lowercase().trim()}%"
|
||||
FeilmeldingTable.select(
|
||||
(FeilmeldingTable.tittel.lowerCase() like sok)
|
||||
or (FeilmeldingTable.beskrivelse.lowerCase() like sok)
|
||||
)
|
||||
.map(::radTilFeilmelding)
|
||||
}
|
||||
val sok = "%${sokeord.lowercase()}%"
|
||||
|
||||
fun oppdaterFeilmelding(feilmelding: Feilmelding) = transaction {
|
||||
checkNotNull(feilmelding.id) { "Id kan ikke være null når vi skal oppdatere feilmelding" }
|
||||
FeilmeldingTable.update({ FeilmeldingTable.id eq feilmelding.id }) {
|
||||
it[FeilmeldingTable.tittel] = feilmelding.tittel
|
||||
it[FeilmeldingTable.beskrivelse] = feilmelding.beskrivelse
|
||||
it[FeilmeldingTable.arbeidsstatus] = feilmelding.arbeidsstatus
|
||||
it[FeilmeldingTable.haster] = feilmelding.haster
|
||||
}
|
||||
}
|
||||
FeilmeldingTable.select((FeilmeldingTable.tittel.lowerCase() like sok)
|
||||
or (FeilmeldingTable.beskrivelse.lowerCase() like sok))
|
||||
.map(::radTilFeilmelding)
|
||||
|
||||
fun oppdaterKommentar(id: Int, kommentar: String) = transaction {
|
||||
FeilmeldingTable.update({ FeilmeldingTable.id eq id }) {
|
||||
it[FeilmeldingTable.kommentar] = kommentar
|
||||
}
|
||||
}
|
||||
|
||||
fun slettFeilmelding(id: Int) = transaction {
|
||||
FeilmeldingTable.deleteWhere { FeilmeldingTable.id eq id }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@ import org.jetbrains.exposed.sql.Table
|
|||
import org.jetbrains.exposed.sql.javatime.datetime
|
||||
|
||||
object FeilmeldingTable : Table("feilmelding") {
|
||||
val id = integer("id")
|
||||
val tittel = text("tittel")
|
||||
val beskrivelse = text("beskrivelse")
|
||||
val dato = datetime("dato")
|
||||
val arbeidsstatus = integer("arbeidsstatus")
|
||||
val haster = bool("haster")
|
||||
val kommentar = text("kommentar")
|
||||
val aktorid = long("aktorid")
|
||||
}
|
||||
|
|
@ -13,15 +13,11 @@ import java.time.LocalDateTime
|
|||
* Objekt for feilmeldinger i Sprik
|
||||
* */
|
||||
@Serializable
|
||||
data class Feilmelding(
|
||||
val id: Int?,
|
||||
class Feilmelding(
|
||||
val tittel: String,
|
||||
val beskrivelse: String,
|
||||
val dato: LocalDateTime, //Krever en spesiallaget serialiserer i KotlinX
|
||||
val arbeidsstatus: Int,
|
||||
val haster: Boolean,
|
||||
val kommentar: String?,
|
||||
val aktorid: Long?
|
||||
//val tags: ArrayList<String> = arrayListOf<String>()
|
||||
//val bilde: String,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class InnkommendeKommentar(val id: Int, val kommentar: String)
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package no.nav.helse.sprik.plugins
|
||||
|
||||
import InnkommendeKommentar
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.response.*
|
||||
|
|
@ -13,10 +12,7 @@ import io.ktor.server.http.content.*
|
|||
import io.ktor.server.plugins.cors.routing.*
|
||||
import io.ktor.server.request.*
|
||||
import no.nav.helse.sprik.db.FeilmeldingRepository
|
||||
import no.nav.helse.sprik.db.FeilmeldingTable
|
||||
import no.nav.helse.sprik.modell.Feilmelding
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.update
|
||||
|
||||
fun configureRouting(): ApplicationEngine = embeddedServer(CIO, applicationEngineEnvironment {
|
||||
//Repositories for handlinger mot database:
|
||||
|
|
@ -27,8 +23,6 @@ fun configureRouting(): ApplicationEngine = embeddedServer(CIO, applicationEngin
|
|||
anyHost()
|
||||
allowMethod(HttpMethod.Get)
|
||||
allowMethod(HttpMethod.Post)
|
||||
allowMethod(HttpMethod.Put)
|
||||
allowMethod(HttpMethod.Delete)
|
||||
allowNonSimpleContentTypes = true
|
||||
}
|
||||
install(ContentNegotiation) {
|
||||
|
|
@ -49,47 +43,29 @@ fun configureRouting(): ApplicationEngine = embeddedServer(CIO, applicationEngin
|
|||
get("/isready"){
|
||||
call.respondText("READY")
|
||||
}
|
||||
get("/api/hentallefeil"){
|
||||
val feilmeldinger = feilmeldingRepository.hentAlleFeilmeldinger()
|
||||
call.respond(status = HttpStatusCode.OK, message = feilmeldinger)
|
||||
}
|
||||
get("/api/hentsok/{sokestreng}"){
|
||||
val sokestreng = call.parameters["sokestreng"]
|
||||
?: return@get call.respond(HttpStatusCode.BadRequest, "Søkestreng må være definert")
|
||||
val sokeresultat = feilmeldingRepository.hentSokteFeilmeldinger(sokestreng)
|
||||
call.respond(status = HttpStatusCode.OK, message = sokeresultat)
|
||||
get("/api/test") {
|
||||
call.respondText("test")
|
||||
}
|
||||
post("/api/nyfeil") {
|
||||
val feilmelding = call.receive<Feilmelding>()
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
call.respond(status = HttpStatusCode.Created, message = "Feilmelding motatt og lagret")
|
||||
call.respond(status = HttpStatusCode.Created, message = "Feilmelding motatt og sendt til database")
|
||||
}
|
||||
put("/api/oppdaterfeil") {
|
||||
val oppdatertFeilmelding = call.receive<Feilmelding>()
|
||||
feilmeldingRepository.oppdaterFeilmelding(oppdatertFeilmelding)
|
||||
call.respond(status = HttpStatusCode.OK, message = "Feilmelding oppdatert")
|
||||
get("/api/hentallefeil"){
|
||||
val testMelding = feilmeldingRepository.hentAlleFeilmeldinger()
|
||||
call.respond(status = HttpStatusCode.Created, message = testMelding)
|
||||
}
|
||||
put("/api/oppdaterkommentar") {
|
||||
val innkommendeKommentar = call.receive<InnkommendeKommentar>()
|
||||
feilmeldingRepository.oppdaterKommentar(innkommendeKommentar.id, innkommendeKommentar.kommentar)
|
||||
call.respond(status = HttpStatusCode.OK, message = "Kommentar oppdatert")
|
||||
}
|
||||
delete("api/slettfeilmelding/{id}") {
|
||||
val id = call.parameters["id"]
|
||||
checkNotNull(id) {"Id kan ikke være null"}
|
||||
feilmeldingRepository.slettFeilmelding(id.toInt())
|
||||
call.respond(status = HttpStatusCode.OK, message = "Feilmelding slettet")
|
||||
}
|
||||
delete("api/slettfeilmelding/{id}") {
|
||||
val id = call.parameters["id"]
|
||||
checkNotNull(id) {"Id kan ikke være null"}
|
||||
feilmeldingRepository.slettFeilmelding(id.toInt())
|
||||
call.respond(status = HttpStatusCode.Created, message = "Feilmelding slettet")
|
||||
get("/api/hentsok/{sokestreng}"){
|
||||
val sokestreng = call.parameters["sokestreng"]
|
||||
?: return@get call.respond(HttpStatusCode.BadRequest, "Sokestreng må være definert")
|
||||
val sokeresultat = feilmeldingRepository.hentSokteFeilmeldinger(sokestreng)
|
||||
call.respond(status = HttpStatusCode.Created, message = sokeresultat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connector {
|
||||
port = 8080
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
DROP TABLE feilmelding;
|
||||
|
||||
CREATE TABLE feilmelding (
|
||||
id SERIAL PRIMARY KEY ,
|
||||
tittel VARCHAR NOT NULL,
|
||||
beskrivelse VARCHAR NOT NULL,
|
||||
dato TIMESTAMP NOT NULL,
|
||||
arbeidsstatus SMALLINT NOT NULL DEFAULT 0,
|
||||
haster BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE feilmelding ADD kommentar VARCHAR
|
||||
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE feilmelding ADD aktorid INT
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
ALTER TABLE feilmelding
|
||||
ALTER COLUMN aktorid TYPE BIGINT
|
||||
|
|
@ -1 +0,0 @@
|
|||
TRUNCATE feilmelding
|
||||
|
|
@ -22,11 +22,10 @@ fun main() {
|
|||
|
||||
private fun oppretteMockData() {
|
||||
val feilmeldingRepository = FeilmeldingRepository()
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Mangel på hensyn til tariffoppgjør", "Det har vært ett tariffoppgjør og speil sier sykepengene må tilbakekreves, noe som er feil. (sier vi.. har ikke domenekunnskap)", LocalDateTime.of(2023, 1, 1, 8, 0, 0), 0, false, null, null))
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Speil sier NAV må tilbakekreve sykepenger på feil grunnlag", "Beskrivelse Test2", LocalDateTime.of(2023, 2, 1, 8, 0, 0), 1, true, null, null))
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Feil A", "Lorem Ipsum", LocalDateTime.of(2023, 3, 1, 8, 0, 0), 2, false, null, null))
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Feil B", "Lorem Ipsum", LocalDateTime.of(2023, 4, 1, 8, 0, 0), 1, true, null, null))
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Feil C", "Lorem Ipsum", LocalDateTime.of(2023, 5, 1, 8, 0, 0), 1, true, null, null))
|
||||
feilmeldingRepository.lagre(Feilmelding(null, "Feil D", "Lorem Ipsum", LocalDateTime.of(2023, 6, 1, 8, 0, 0), 0, false, null, null))
|
||||
feilmeldingRepository.oppdaterKommentar(1, "Test kommentar")
|
||||
feilmeldingRepository.lagre(Feilmelding("Mangel på hensyn til tariffoppgjør", "Det har vært ett tariffoppgjør og speil sier sykepengene må tilbakekreves, noe som er feil. (sier vi.. har ikke domenekunnskap)", LocalDateTime.of(2023, 1, 1, 8, 0, 0)))
|
||||
feilmeldingRepository.lagre(Feilmelding("Speil sier NAV må tilbakekreve sykepenger på feil grunnlag", "Beskrivelse Test2", LocalDateTime.of(2023, 2, 1, 8, 0, 0)))
|
||||
feilmeldingRepository.lagre(Feilmelding("Feil A", "Lorem Ipsum", LocalDateTime.of(2023, 3, 1, 8, 0, 0)))
|
||||
feilmeldingRepository.lagre(Feilmelding("Feil B", "Lorem Ipsum", LocalDateTime.of(2023, 4, 1, 8, 0, 0)))
|
||||
feilmeldingRepository.lagre(Feilmelding("Feil C", "Lorem Ipsum", LocalDateTime.of(2023, 5, 1, 8, 0, 0)))
|
||||
feilmeldingRepository.lagre(Feilmelding("Feil D", "Lorem Ipsum", LocalDateTime.of(2023, 6, 1, 8, 0, 0)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package no.nav.helse.sprik
|
||||
|
||||
|
||||
class ApplicationTest {
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package no.nav.helse.sprik
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
fun Int.januar(år: Int = 2023, time: Int = 8, minutt: Int = 0) = LocalDateTime.of(år, 1,this, time, minutt)
|
||||
|
||||
val Int.januar get() = this.januar()
|
||||
|
|
@ -8,38 +8,31 @@ import no.nav.helse.sprik.modell.Feilmelding
|
|||
import org.jetbrains.exposed.sql.deleteAll
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.junit.jupiter.api.*
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import org.jetbrains.exposed.sql.Database as ExposedDatabase
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class FeilmeldingTest {
|
||||
private val database = Database(dbconfig()).configureFlyway()
|
||||
private val feilmeldingRepository = FeilmeldingRepository()
|
||||
private companion object {
|
||||
val feilmelding = Feilmelding(
|
||||
null,
|
||||
"Test",
|
||||
"Testesen",
|
||||
1.januar,
|
||||
0,
|
||||
true,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun getId() = transaction {
|
||||
FeilmeldingTable.selectAll().single()[FeilmeldingTable.id]
|
||||
}
|
||||
private val feilmelding = Feilmelding("Test", "Testesen", LocalDateTime.of(2023,1,1,8,0))
|
||||
private val feilmelding2 = Feilmelding("Tittel", "Beskrivelse", LocalDateTime.of(2023,2,1,8,0))
|
||||
|
||||
@BeforeAll
|
||||
fun setup() {
|
||||
ExposedDatabase.connect(database.dataSource)
|
||||
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun lagreFeilmelding() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
@ -48,10 +41,8 @@ class FeilmeldingTest {
|
|||
FeilmeldingTable.deleteAll()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Sett opp testdatabasen riktig`(){
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
transaction {
|
||||
assertEquals(1, FeilmeldingTable.selectAll().map {
|
||||
it
|
||||
|
|
@ -60,140 +51,54 @@ class FeilmeldingTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `Lagrer feilmelding uten aktørid i databasen`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
fun `Lagrer feilmelding i databasen`() {
|
||||
transaction {
|
||||
val forventetFeilmelding = Feilmelding(
|
||||
getId(),
|
||||
"Test",
|
||||
"Testesen",
|
||||
1.januar,
|
||||
0,
|
||||
true,
|
||||
null,
|
||||
null
|
||||
)
|
||||
val faktiskFeilmelding = feilmeldingRepository.radTilFeilmelding(FeilmeldingTable.selectAll().single())
|
||||
assertEquals(forventetFeilmelding, faktiskFeilmelding)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Lagrer feilmelding med aktørid i databasen`() {
|
||||
feilmeldingRepository.lagre(feilmelding.copy(aktorid = 12345678))
|
||||
transaction {
|
||||
val forventetFeilmelding = Feilmelding(
|
||||
getId(),
|
||||
"Test",
|
||||
"Testesen",
|
||||
1.januar,
|
||||
0,
|
||||
true,
|
||||
null,
|
||||
12345678
|
||||
)
|
||||
val faktiskFeilmelding = feilmeldingRepository.radTilFeilmelding(FeilmeldingTable.selectAll().single())
|
||||
assertEquals(forventetFeilmelding, faktiskFeilmelding)
|
||||
val actual = FeilmeldingTable.selectAll().single()
|
||||
assertEquals("Test", actual[FeilmeldingTable.tittel])
|
||||
assertEquals("Testesen", actual[FeilmeldingTable.beskrivelse])
|
||||
assertEquals(LocalDateTime.of(2023, 1, 1, 8, 0), actual[FeilmeldingTable.dato])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Henter alle feilmeldinger i databasen`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
transaction {
|
||||
val resultat: List<Feilmelding> = feilmeldingRepository.hentAlleFeilmeldinger()
|
||||
val forventet = FeilmeldingTable.selectAll().map { it }
|
||||
assertEquals(forventet.size, resultat.size)
|
||||
val actual = FeilmeldingTable.selectAll()
|
||||
assertEquals(actual.map { it }.size, resultat.size)
|
||||
assertEquals("Test", resultat[0].tittel)
|
||||
assertEquals("Testesen", resultat[0].beskrivelse)
|
||||
assertEquals(LocalDateTime.of(2023, 1, 1, 8, 0), resultat[0].dato)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Henter feilmeldinger som matcher søk`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val sokeresultat: List<Feilmelding> = feilmeldingRepository.hentSokteFeilmeldinger("Test")
|
||||
assertEquals(1, sokeresultat.size)
|
||||
assertEquals("Test", sokeresultat[0].tittel)
|
||||
assertEquals("Testesen", sokeresultat[0].beskrivelse)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Henter alle feilmeldinger som har søkestreng som substreng`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
feilmeldingRepository.lagre(feilmelding.copy(tittel = "Heste"))
|
||||
fun `Henter feilmeldinger som har søkestreng som substreng`() {
|
||||
val sokeresultat: List<Feilmelding> = feilmeldingRepository.hentSokteFeilmeldinger("este")
|
||||
assertEquals(2, sokeresultat.size)
|
||||
assertEquals(1, sokeresultat.size)
|
||||
assertEquals("Test", sokeresultat[0].tittel)
|
||||
assertEquals("Testesen", sokeresultat[0].beskrivelse)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Finner ingen feilmeldinger som matcher søk`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val sokeresultat: List<Feilmelding> = feilmeldingRepository.hentSokteFeilmeldinger("abrakadabra")
|
||||
assertEquals(0, sokeresultat.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Søk er ikke case sensitivt`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val sokeresultat: List<Feilmelding> = feilmeldingRepository.hentSokteFeilmeldinger("test")
|
||||
assertEquals(1, sokeresultat.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Søk er ikke mellomrom-sensitiv`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val sokeresultat: List<Feilmelding> = feilmeldingRepository.hentSokteFeilmeldinger("Test ")
|
||||
assertEquals(1, sokeresultat.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Oppdaterer en feilmelding`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val oppdatertFeilmelding = Feilmelding(getId(), "Oppdatert", "Oppdatert feil", 1.januar, 1, false, null, null)
|
||||
feilmeldingRepository.oppdaterFeilmelding(oppdatertFeilmelding)
|
||||
val actualOppdatert = transaction { FeilmeldingTable.selectAll().single() }
|
||||
assertEquals("Oppdatert", actualOppdatert[FeilmeldingTable.tittel])
|
||||
assertEquals("Oppdatert feil", actualOppdatert[FeilmeldingTable.beskrivelse])
|
||||
assertFalse ( actualOppdatert[FeilmeldingTable.haster] )
|
||||
assertEquals(1, actualOppdatert[FeilmeldingTable.arbeidsstatus])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Prøver å oppdatere feilmelding uten id`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val oppdatertFeilmelding = Feilmelding(null, "Oppdatert", "Oppdatert feil", 1.januar, 1, false, null, null)
|
||||
assertThrows<IllegalStateException> {
|
||||
feilmeldingRepository.oppdaterFeilmelding(oppdatertFeilmelding)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Kommentar er tom når feilmelding opprettes`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
val initiellKommentar = transaction { FeilmeldingTable.selectAll().single()[FeilmeldingTable.kommentar] }
|
||||
assertNull(initiellKommentar)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Oppdaterer feilmeldingskommentar`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
feilmeldingRepository.oppdaterKommentar(getId(), "Feilen fikses nå!")
|
||||
val oppdatertKommentar = transaction { FeilmeldingTable.selectAll().single()[FeilmeldingTable.kommentar] }
|
||||
assertEquals("Feilen fikses nå!", oppdatertKommentar)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Ny kommentar skal overskrive gammel`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
feilmeldingRepository.oppdaterKommentar(getId(), "Initiell kommentar")
|
||||
feilmeldingRepository.oppdaterKommentar(getId(), "Oppdatert kommentar")
|
||||
val oppdatertKommentar = transaction { FeilmeldingTable.selectAll().single()[FeilmeldingTable.kommentar] }
|
||||
assertEquals("Oppdatert kommentar", oppdatertKommentar)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Feilmelding slettes basert på id`() {
|
||||
feilmeldingRepository.lagre(feilmelding)
|
||||
feilmeldingRepository.slettFeilmelding(getId())
|
||||
val resultat = transaction { FeilmeldingTable.selectAll().map { it }.size }
|
||||
assertEquals(0, resultat)
|
||||
assertEquals("Test", sokeresultat[0].tittel)
|
||||
assertEquals("Testesen", sokeresultat[0].beskrivelse)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,9 @@
|
|||
import { defineConfig } from "cypress";
|
||||
import { plugin } from "./cypress/plugins/index";
|
||||
|
||||
export default defineConfig({
|
||||
viewportHeight: 1300,
|
||||
viewportWidth: 1800,
|
||||
requestTimeout: 10000,
|
||||
defaultCommandTimeout: 10000,
|
||||
video: false,
|
||||
retries: {
|
||||
runMode: 2,
|
||||
},
|
||||
e2e: {
|
||||
//@ts-ignore
|
||||
setupNodeEvents(on, config) {
|
||||
return plugin(on, config);
|
||||
// implement node event listeners here
|
||||
},
|
||||
baseUrl: "http://localhost:5173",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
const fyllFeilmeldingInputs = () => {
|
||||
cy.getByTestId('tittel-inputfelt').type('Cypress-test Tittel')
|
||||
cy.getByTestId('beskrivelse-inputfelt').type('Cypress-test Beskrivelse')
|
||||
cy.getByTestId('switch-toggle').click()
|
||||
}
|
||||
|
||||
describe('Klarer å melde inn feil', () => {
|
||||
context('Fyller ut felt, melder inn og går tilbake til hovedside', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
cy.visit('http://localhost:5173/')
|
||||
})
|
||||
|
||||
it('sjekker axe', () => {
|
||||
cy.checkPageA11y()
|
||||
})
|
||||
|
||||
it('Fyller ut felt og melder inn feil som haster', () => {
|
||||
cy.contains('Meld inn feil').click()
|
||||
|
||||
fyllFeilmeldingInputs()
|
||||
|
||||
cy.contains('Meld inn feil').click()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
describe('Landingsside loader ordentlig', () => {
|
||||
context('Loader landingsside i riktig dimensjon', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
cy.visit('http://localhost:5173/')
|
||||
})
|
||||
|
||||
it('sjekker axe', () => {
|
||||
cy.checkPageA11y()
|
||||
})
|
||||
|
||||
it('bør loade liste med feil', () => {
|
||||
cy.contains('Speil sier NAV må tilbakekreve sykepenger på feil grunnlag')
|
||||
cy.contains('Feil A')
|
||||
cy.contains('Feil B')
|
||||
cy.contains('Feil C')
|
||||
cy.contains('Feil D')
|
||||
cy.contains('Mangel på hensyn til tariffoppgjør')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
describe('Sjekker søkefunksjonalitet', () => {
|
||||
context('Loader landingsside i riktig dimensjon', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
cy.visit('http://localhost:5173/')
|
||||
})
|
||||
|
||||
it('sjekker axe', () => {
|
||||
cy.checkPageA11y()
|
||||
})
|
||||
|
||||
it('Klarer å søke etter en spesifik feil: "Mangel på hensyn til tariffoppgjør"', () => {
|
||||
cy.getByTestId('soke-inputfelt').type('Man')
|
||||
})
|
||||
})
|
||||
})
|
||||
43
frontend/cypress/e2e/testspec.cy.ts
Normal file
43
frontend/cypress/e2e/testspec.cy.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { slowCypressDown } from 'cypress-slow-down'
|
||||
|
||||
// Notat: Husk å kjør opp frontend før tester
|
||||
|
||||
slowCypressDown() // gjør at testene ikke kjører dritfort
|
||||
|
||||
describe('Landingsside loader ordentlig', () => {
|
||||
context('Resolution er 1080p', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
})
|
||||
|
||||
it('passes', () => {
|
||||
cy.visit('http://localhost:5173/')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Klarer å navigere frem og tilbake til/fra "Meld inn feil"-side', () => {
|
||||
context('Går til "Meld inn feil"-siden', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
})
|
||||
|
||||
it('passes', () => {
|
||||
cy.visit('http://localhost:5173/')
|
||||
|
||||
cy.contains('Meld inn feil').click()
|
||||
})
|
||||
})
|
||||
|
||||
context('Går tilbake til hovedsiden', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080)
|
||||
})
|
||||
|
||||
it('passes', () => {
|
||||
cy.visit('http://localhost:5173/nyfeil')
|
||||
|
||||
cy.contains('Gå tilbake til hovedmenyen').click()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const plugin: Cypress.PluginConfig = (on: Cypress.PluginEvents) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
on("task", {
|
||||
log(message: string) {
|
||||
console.log(message);
|
||||
|
||||
return null;
|
||||
},
|
||||
table(message: string) {
|
||||
console.table(message);
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import 'cypress-axe'
|
||||
/// <reference types="cypress" />
|
||||
// ***********************************************
|
||||
// This example commands.ts shows you how to
|
||||
|
|
@ -25,23 +24,14 @@ import 'cypress-axe'
|
|||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
|
||||
Cypress.Commands.add("getByTestId", (selector, ...args) => {
|
||||
return cy.get(`[data-testid=${selector}]`, ...args);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("checkPageA11y", () => {
|
||||
cy.injectAxe();
|
||||
cy.configureAxe({
|
||||
rules: [
|
||||
// {
|
||||
// id: "svg-img-alt",
|
||||
// enabled: false,
|
||||
// },
|
||||
// Skrur av fordi checkA11y ikke vet at div er en gyldig children av <dl>-elementer
|
||||
],
|
||||
});
|
||||
cy.checkA11y(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
@ -17,16 +17,4 @@
|
|||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
getByTestId(
|
||||
selector: string,
|
||||
...rest: any
|
||||
): Chainable<JQuery<HTMLElement>>;
|
||||
checkPageA11y(): Chainable<JQuery<HTMLElement>>;
|
||||
}
|
||||
}
|
||||
}
|
||||
// require('./commands')
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/Rød.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sprik</title>
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
98
frontend/package-lock.json
generated
98
frontend/package-lock.json
generated
|
|
@ -32,8 +32,6 @@
|
|||
"@typescript-eslint/parser": "^5.61.0",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
"cypress": "^12.17.2",
|
||||
"cypress-axe": "^1.4.0",
|
||||
"cypress-slow-down": "^1.2.1",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.1",
|
||||
|
|
@ -654,10 +652,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cypress/request": {
|
||||
"version": "2.88.12",
|
||||
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz",
|
||||
"integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==",
|
||||
"version": "2.88.11",
|
||||
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz",
|
||||
"integrity": "sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
|
|
@ -674,7 +673,7 @@
|
|||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.10.3",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "^4.1.3",
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
|
|
@ -2036,16 +2035,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axe-core": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz",
|
||||
"integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||
|
|
@ -2704,34 +2693,6 @@
|
|||
"node": "^14.0.0 || ^16.0.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress-axe": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cypress-axe/-/cypress-axe-1.4.0.tgz",
|
||||
"integrity": "sha512-Ut7NKfzjyKm0BEbt2WxuKtLkIXmx6FD2j0RwdvO/Ykl7GmB/qRQkwbKLk3VP35+83hiIr8GKD04PDdrTK5BnyA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"axe-core": "^3 || ^4",
|
||||
"cypress": "^10 || ^11 || ^12"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress-plugin-config": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cypress-plugin-config/-/cypress-plugin-config-1.2.1.tgz",
|
||||
"integrity": "sha512-z+bQ7oyfDKun51HiCVNBOR+g38/nYRJ7zVdCZT2/9UozzE8P4iA1zF/yc85ePZLy5NOj/0atutoUPBBR5SqjSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cypress-slow-down": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cypress-slow-down/-/cypress-slow-down-1.2.1.tgz",
|
||||
"integrity": "sha512-Pd+nESR+Ca8I+mLGbBrPVMEFvJBWxkJcEdcIUDxSBnMoWI00hiIKxzEgVqCv5c6Oap2OPpnrPLbJBwveCNKLig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cypress-plugin-config": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
|
|
@ -5239,7 +5200,8 @@
|
|||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.0",
|
||||
|
|
@ -5278,12 +5240,6 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
|
@ -5530,12 +5486,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||
|
|
@ -6453,27 +6403,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tough-cookie": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
"universalify": "^0.2.0",
|
||||
"url-parse": "^1.5.3"
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tough-cookie/node_modules/universalify": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/trim-newlines": {
|
||||
|
|
@ -6644,16 +6584,6 @@
|
|||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
"@typescript-eslint/parser": "^5.61.0",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
"cypress": "^12.17.2",
|
||||
"cypress-axe": "^1.4.0",
|
||||
"cypress-slow-down": "^1.2.1",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="269px" height="169px" viewBox="0 0 269 169" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>NAV logo / rød</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<polygon id="path-1" points="22.407 43.4168 22.407 0.6878 0.5635 0.6878 0.5635 43.4168 22.407 43.4168"></polygon>
|
||||
</defs>
|
||||
<g id="Modul-forslag" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="NAV-logo-/-rød">
|
||||
<g id="Page-1-Copy">
|
||||
<path d="M125.3091,168.942 C78.6681,168.942 40.8491,131.125 40.8491,84.477 C40.8491,37.824 78.6681,0 125.3091,0 C171.9671,0 209.7901,37.824 209.7901,84.477 C209.7901,131.125 171.9671,168.942 125.3091,168.942 Z" id="Fill-1" fill="#C30000"></path>
|
||||
<polygon id="Fill-3" fill="#C30000" points="0 121.3588 17.265 78.6298 33.854 78.6298 16.611 121.3588"></polygon>
|
||||
<polygon id="Fill-5" fill="#C30000" points="213.044 121.3588 230.088 78.6298 239.132 78.6298 222.089 121.3588"></polygon>
|
||||
<g id="Group-9" transform="translate(246.000000, 77.942000)">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Clip-8"></g>
|
||||
<polygon id="Fill-7" fill="#C30000" mask="url(#mask-2)" points="0.5635 43.4168 17.6045 0.6878 22.4075 0.6878 5.3645 43.4168"></polygon>
|
||||
</g>
|
||||
<path d="M197.3604,78.6298 L182.3444,78.6298 C182.3444,78.6298 181.3094,78.6298 180.9434,79.5438 L172.6334,104.9828 L164.3304,79.5438 C163.9644,78.6298 162.9234,78.6298 162.9234,78.6298 L134.0514,78.6298 C133.4264,78.6298 132.9024,79.1518 132.9024,79.7728 L132.9024,88.4118 C132.9024,81.5588 125.6104,78.6298 121.3404,78.6298 C111.7784,78.6298 105.3774,84.9278 103.3844,94.5028 C103.2764,88.1508 102.7484,85.8748 101.0374,83.5438 C100.2514,82.4018 99.1154,81.4418 97.8784,80.6478 C95.3314,79.1558 93.0444,78.6298 88.1294,78.6298 L82.3584,78.6298 C82.3584,78.6298 81.3154,78.6298 80.9474,79.5438 L75.6964,92.5568 L75.6964,79.7728 C75.6964,79.1518 75.1764,78.6298 74.5524,78.6298 L61.1984,78.6298 C61.1984,78.6298 60.1674,78.6298 59.7924,79.5438 L54.3334,93.0748 C54.3334,93.0748 53.7884,94.4278 55.0344,94.4278 L60.1674,94.4278 L60.1674,120.2118 C60.1674,120.8518 60.6714,121.3588 61.3144,121.3588 L74.5524,121.3588 C75.1764,121.3588 75.6964,120.8518 75.6964,120.2118 L75.6964,94.4278 L80.8564,94.4278 C83.8174,94.4278 84.4444,94.5088 85.5964,95.0458 C86.2904,95.3078 86.9154,95.8378 87.2564,96.4488 C87.9544,97.7628 88.1294,99.3408 88.1294,103.9938 L88.1294,120.2118 C88.1294,120.8518 88.6434,121.3588 89.2784,121.3588 L101.9664,121.3588 C101.9664,121.3588 103.4004,121.3588 103.9674,119.9428 L106.7794,112.9928 C110.5184,118.2298 116.6724,121.3588 124.3204,121.3588 L125.9914,121.3588 C125.9914,121.3588 127.4344,121.3588 128.0054,119.9428 L132.9024,107.8148 L132.9024,120.2118 C132.9024,120.8518 133.4264,121.3588 134.0514,121.3588 L147.0034,121.3588 C147.0034,121.3588 148.4324,121.3588 149.0064,119.9428 C149.0064,119.9428 154.1864,107.0818 154.2064,106.9848 L154.2144,106.9848 C154.4134,105.9148 153.0614,105.9148 153.0614,105.9148 L148.4384,105.9148 L148.4384,83.8468 L162.9834,119.9428 C163.5514,121.3588 164.9834,121.3588 164.9834,121.3588 L180.2844,121.3588 C180.2844,121.3588 181.7244,121.3588 182.2924,119.9428 L198.4174,80.0138 C198.9754,78.6298 197.3604,78.6298 197.3604,78.6298 L197.3604,78.6298 Z M132.9024,105.9148 L124.2024,105.9148 C120.7394,105.9148 117.9224,103.1108 117.9224,99.6438 C117.9224,96.1828 120.7394,93.3608 124.2024,93.3608 L126.6354,93.3608 C130.0894,93.3608 132.9024,96.1828 132.9024,99.6438 L132.9024,105.9148 Z" id="Fill-10" fill="#FEFEFE"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.9 KiB |
|
|
@ -1,28 +1,29 @@
|
|||
import { FileImageIcon, UploadIcon } from "@navikt/aksel-icons"
|
||||
import { Button, Heading } from "@navikt/ds-react"
|
||||
import { Button } from "@navikt/ds-react"
|
||||
|
||||
|
||||
/**
|
||||
* BildeOpplastningskomponentet brukes for å laste opp skjermbilder av en feil i Speil.
|
||||
* Komponentet er ment for å støtte både drag-and-drop og vanlig opplasting av bilder.
|
||||
* @TODO: Implementer funksjonalitet for å laste opp bildefiler -> API og backend
|
||||
* Inkluderer en knapp for opplastning i finder/explorer.
|
||||
* Inkluderer et felt for drag and drop opplastning av bilder
|
||||
* @returns `Drag and drop` komponent for filopplastning av skjermbilder
|
||||
*/
|
||||
const BildeOpplastning = () => {
|
||||
return(
|
||||
<div className="flex gap-2 flex-col">
|
||||
<Heading size="xsmall">
|
||||
Skjermbilder
|
||||
</Heading>
|
||||
<div className="h-48 p-5 bg-bg-subtle hover:bg-surface-selected border-2 border-blue-500 rounded-lg border-dashed flex flex-col items-center justify-center text-center gap-2">
|
||||
<div className="
|
||||
h-48 p-5 bg-bg-subtle hover:bg-surface-selected border-2 border-blue-500
|
||||
rounded-lg border-dashed flex flex-col items-center justify-center text-center gap-2
|
||||
">
|
||||
<FileImageIcon
|
||||
fontSize="3.5rem"
|
||||
className="text-blue-500"
|
||||
/>
|
||||
<p className="text-surface-neutral">
|
||||
Dra og slipp skjermbilder her!
|
||||
</p>
|
||||
<p className="text-surface-neutral">Dra og slipp skjermbilder her!</p>
|
||||
</div>
|
||||
<Button variant="secondary" icon={<UploadIcon />}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={<UploadIcon />}
|
||||
>
|
||||
Last opp skjermbilder
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
29
frontend/src/components/CardsContainer.tsx
Normal file
29
frontend/src/components/CardsContainer.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import FeilCard from "./FeilCard";
|
||||
import { Feilmelding } from "../interface.ts";
|
||||
|
||||
interface ICardsContainer {
|
||||
feilmeldinger: Feilmelding[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Komponent som laster inn feilmeldinger i kort fra database.
|
||||
* @returns grid med feilmeldinger
|
||||
*/
|
||||
const CardsContainer = (props: ICardsContainer) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{props.feilmeldinger.map((feilMelding) => (
|
||||
<FeilCard
|
||||
key={props.feilmeldinger.indexOf(feilMelding)}
|
||||
tittel={feilMelding.tittel}
|
||||
beskrivelse={feilMelding.beskrivelse}
|
||||
dato={new Date()}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardsContainer;
|
||||
36
frontend/src/components/FeilCard.tsx
Normal file
36
frontend/src/components/FeilCard.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import "@navikt/ds-css";
|
||||
import { ExpansionCard, Tag } from "@navikt/ds-react";
|
||||
import { IFeilmelding } from "../interface";
|
||||
|
||||
interface TagBarInterface {
|
||||
haster: boolean
|
||||
}
|
||||
|
||||
//typen på status er veldig wack heheheh, må fjerne any etterhvert men String fungerer ikke
|
||||
const TagBar = (props: TagBarInterface) => {
|
||||
return (
|
||||
<div className="flex gap-8 mt-4">
|
||||
<Tag variant="info">Jobbes med</Tag>
|
||||
{props.haster === true ? <Tag variant="warning">Haster</Tag> : <></>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const FeilCard = (props: IFeilmelding) => {
|
||||
return (
|
||||
<ExpansionCard aria-label="tekst">
|
||||
<ExpansionCard.Header>
|
||||
<ExpansionCard.Title>{props.tittel}</ExpansionCard.Title>
|
||||
<ExpansionCard.Description>
|
||||
{props.beskrivelse}
|
||||
</ExpansionCard.Description>
|
||||
<TagBar haster={true}/>
|
||||
</ExpansionCard.Header>
|
||||
<ExpansionCard.Content>
|
||||
Hællæ
|
||||
</ExpansionCard.Content>
|
||||
</ExpansionCard>
|
||||
)
|
||||
}
|
||||
|
||||
export default FeilCard;
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
import "@navikt/ds-css";
|
||||
import { Modal} from "@navikt/ds-react";
|
||||
import { IFeilmelding } from "../interface";
|
||||
import FeilModal from "./FeilModal";
|
||||
import { useEffect, useState } from "react";
|
||||
import FeilkortHeader from "./FeilkortHeader";
|
||||
import RedigeringsVerktoy from "./RedigeringsVerktoy";
|
||||
import FeilmeldingsInnhold from "./FeilmeldingsInnhold";
|
||||
|
||||
interface IFeilKort extends IFeilmelding {
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* En konteiner som inneholder all informasjon og funksjonalitet for å vise og interagere med en feilmelding.
|
||||
* Komponentet rendres på hovedsiden, og mappes ut fra en liste med feilmeldinger i KortKonteiner.
|
||||
* Du kan trykke på en feilmelding for å åpne en modal som viser mer informasjon om feilmeldingen, samt mulighet for å redigere.
|
||||
* @param id er feilmeldingens unike id
|
||||
* @param tittel
|
||||
* @param beskrivelse
|
||||
* @param dato Dato for når feilen ble meldt inn
|
||||
* @param haster Boolean som beskriver om feilen haster eller ikke.
|
||||
* @param reset funksjon som kalles når en feilmelding endres. Denne funksjonen kalles for å oppdatere feilmeldingene som vises på hovedsiden.
|
||||
*/
|
||||
const FeilKort = (props: IFeilKort) => {
|
||||
const [visModal, setVisModal] = useState<boolean>(false)
|
||||
const [redigeringsmodus, setRedigeringsmodus] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
Modal.setAppElement(document.getElementById('root'));
|
||||
}, []);
|
||||
|
||||
return(
|
||||
<>
|
||||
<div
|
||||
key={props.id}
|
||||
className="
|
||||
bg-bg-default border border-border-default p-7 rounded-lg
|
||||
hover:bg-bg-subtle hover:border-border-strong hover:shadow-md duration-100
|
||||
active:bg-surface-active"
|
||||
onClick={() => setVisModal(true)}
|
||||
>
|
||||
<FeilkortHeader
|
||||
id={props.id}
|
||||
tittel={props.tittel}
|
||||
beskrivelse={props.beskrivelse}
|
||||
dato={props.dato}
|
||||
haster={props.haster}
|
||||
arbeidsstatus={props.arbeidsstatus}
|
||||
kommentar={props.kommentar}
|
||||
/>
|
||||
</div>
|
||||
<FeilModal open={visModal} setOpen={setVisModal}>
|
||||
{redigeringsmodus ?
|
||||
<RedigeringsVerktoy
|
||||
id={props.id}
|
||||
tittel={props.tittel}
|
||||
beskrivelse={props.beskrivelse}
|
||||
dato={props.dato}
|
||||
haster={props.haster}
|
||||
arbeidsstatus={props.arbeidsstatus}
|
||||
setRedigeringsmodus={setRedigeringsmodus}
|
||||
setVisModal={setVisModal}
|
||||
reset={props.reset}
|
||||
kommentar={props.kommentar}
|
||||
aktorId={props.aktorId}
|
||||
/>
|
||||
:
|
||||
<FeilmeldingsInnhold
|
||||
id={props.id}
|
||||
tittel={props.tittel}
|
||||
beskrivelse={props.beskrivelse}
|
||||
dato={props.dato}
|
||||
haster={props.haster}
|
||||
arbeidsstatus={props.arbeidsstatus}
|
||||
setVisModal={setVisModal}
|
||||
setRedigeringsmodus={setRedigeringsmodus}
|
||||
reset={props.reset}
|
||||
kommentar={props.kommentar}
|
||||
aktorId={props.aktorId}
|
||||
>
|
||||
<p>aktorId: {props.aktorId}</p>
|
||||
</FeilmeldingsInnhold>
|
||||
}
|
||||
</FeilModal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default FeilKort
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import { Modal } from "@navikt/ds-react"
|
||||
import { Dispatch, SetStateAction } from "react"
|
||||
|
||||
|
||||
interface modalInterface {
|
||||
open: boolean
|
||||
setOpen: Dispatch<SetStateAction<boolean>>
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal som brukes til å vise feilmeldinger i fullvisningsmodus med feilinnhold og redigeringsverktøy
|
||||
* @param open boolean som beskriver om modalen skal være åpen eller ikke
|
||||
* @param setOpen setter open
|
||||
* @param children innholdet i modalen
|
||||
*/
|
||||
const FeilModal = (props: modalInterface) => {
|
||||
return(
|
||||
<Modal
|
||||
className="w-3/5 p-5"
|
||||
open={props.open}
|
||||
aria-label={" modal"}
|
||||
onClose={() => props.setOpen(false)}
|
||||
aria-labelledby="modal-heading"
|
||||
closeButton={false}
|
||||
>
|
||||
<Modal.Content>
|
||||
{props.children}
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default FeilModal;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import { Heading } from "@navikt/ds-react";
|
||||
import { IFeilmelding } from "../interface";
|
||||
import TagBar from "./TagBar";
|
||||
|
||||
/**
|
||||
* Headeren til et Feilkort, inneholder lite sensitiv informasjon som er beskrivende for feilen (tittel, beskrivelse, dato, haster, arbeidsstatus).
|
||||
* Komponentet er en del av FeilKort, og er det du kan se når du er på hovedsiden.
|
||||
*/
|
||||
export const FeilkortHeader = (props: IFeilmelding) => {
|
||||
return(
|
||||
<div className="flex justify-between flex-col">
|
||||
<div>
|
||||
<Heading size="medium">{props.tittel}</Heading>
|
||||
<p className="text-text-subtle mb-4">{props.dato.toDateString()}</p>
|
||||
<p>{props.beskrivelse}</p>
|
||||
</div>
|
||||
<TagBar haster={props.haster} arbeidsstatus={props.arbeidsstatus}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default FeilkortHeader;
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import { PencilIcon, XMarkIcon } from "@navikt/aksel-icons"
|
||||
import { Button } from "@navikt/ds-react"
|
||||
import { FeilmeldingsInnholdInterface } from "../interface"
|
||||
import FeilkortHeader from "./FeilkortHeader"
|
||||
import { useState } from "react"
|
||||
import Skillelinje from "./Skillelinje"
|
||||
import axios from "axios"
|
||||
import { Kommentar } from "./Kommentar"
|
||||
|
||||
|
||||
/**
|
||||
* FeilmeldingsInnhold er et komponent som viser det fulle innholdet til en feilmelding.
|
||||
* Komponentet er en del av FeilKort, og er det du kan se når du trykker på et Feilkort.
|
||||
* Tilgangen til å vise FeilmeldingsInnhold er skal begrenses til saksbehandlere, utviklere og fagfolk med tjenestlig behov.
|
||||
*/
|
||||
const FeilmeldingsInnhold = (props: FeilmeldingsInnholdInterface) => {
|
||||
//kommentar kan være null eller undefined når den kommer fra databasen, derfor må den sjekkes og omgjøres til en tom string om det er tilfellet
|
||||
const [kommentar, setKommentar] = useState(props.kommentar != (null || undefined) ? props.kommentar : "")
|
||||
const [kommentarfelt, setKommentarfelt] = useState("")
|
||||
|
||||
/**
|
||||
* Endrer Feilmeldingsobjektet i databasen og setter en ny kommentar på den
|
||||
*/
|
||||
const oppdaterkommentar = async() => {
|
||||
const payload = {
|
||||
id: props.id,
|
||||
kommentar: kommentarfelt,
|
||||
}
|
||||
await axios.put("/api/oppdaterkommentar", payload, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then((response) => {
|
||||
console.log(response);
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
//TODO: fiks så kommentar oppdateres uten å måtte skjule modalen.
|
||||
props.setVisModal(false)
|
||||
props.reset()
|
||||
}
|
||||
|
||||
const fullUpdate = async() => {
|
||||
setKommentar(kommentarfelt)
|
||||
oppdaterkommentar()
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<div className="flex justify-between ">
|
||||
<FeilkortHeader
|
||||
id={props.id}
|
||||
tittel={props.tittel}
|
||||
beskrivelse={props.beskrivelse}
|
||||
dato={props.dato}
|
||||
haster={props.haster}
|
||||
arbeidsstatus={props.arbeidsstatus}
|
||||
kommentar={props.kommentar}
|
||||
/>
|
||||
<div className="flex gap-4 items-start">
|
||||
<Button
|
||||
variant="tertiary"
|
||||
icon={<PencilIcon />}
|
||||
onClick={() => props.setRedigeringsmodus(true)}
|
||||
>
|
||||
Rediger
|
||||
</Button>
|
||||
<Button
|
||||
icon={<XMarkIcon />}
|
||||
onClick={() => {
|
||||
props.setVisModal(false)
|
||||
props.setRedigeringsmodus(false)
|
||||
}}
|
||||
>
|
||||
Lukk
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Skillelinje/>
|
||||
{props.children}
|
||||
|
||||
<Kommentar
|
||||
tekst={kommentar}
|
||||
kommentarfelt={kommentarfelt}
|
||||
setKommentarfelt={setKommentarfelt}
|
||||
oppdaterKommentar={fullUpdate}
|
||||
/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default FeilmeldingsInnhold;
|
||||
|
|
@ -1,70 +1,14 @@
|
|||
import { Accordion, Checkbox, CheckboxGroup, Radio, RadioGroup } from "@navikt/ds-react"
|
||||
import React, { useState } from "react"
|
||||
import { useState } from "react"
|
||||
|
||||
/**
|
||||
* Filtermenyen er en komponent som inneholder alle filterene som kan brukes for å filtrere feil.
|
||||
* Komponentet rendres på hovedsiden.
|
||||
* Foreløpig holder den filter for kategorier, status, prioritet og mine innmeldinger.
|
||||
*/
|
||||
const Filtermeny = () => {
|
||||
const [visningstype, settVisningstype] = useState(false)
|
||||
const [prioritet, settPrioritet] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="bg-bg-default w-500">
|
||||
<Accordion>
|
||||
<FilterModul
|
||||
tittel="Kategorier"
|
||||
beskrivelse="Denne løsningen er litt mer avansert enn den andre filtreringen. UFERDIG!!!!!!!!!!"
|
||||
>
|
||||
|
||||
</FilterModul>
|
||||
|
||||
<FilterModul
|
||||
tittel="Status"
|
||||
beskrivelse="
|
||||
Ved å filtrere etter status på forskjellig innmeldte feil
|
||||
kan du enkelt få oversikt over hvilke feil som ikke er påbegynte,
|
||||
hvilke som utredes av utviklingsteamet og løste feil."
|
||||
>
|
||||
<CheckboxGroup legend="Hvilke statusflagg ønsker du å vise?">
|
||||
<Checkbox value="Ikke påbegynt">Velg alle</Checkbox>
|
||||
<Checkbox value="Ikke påbegynt">Ikke påbegynt</Checkbox>
|
||||
<Checkbox value="Jobbes med">Jobbes med</Checkbox>
|
||||
<Checkbox value="Ferdig med">Ferdig med</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</FilterModul>
|
||||
|
||||
<FilterModul
|
||||
tittel="Prioritet"
|
||||
beskrivelse="
|
||||
Saker som haster å løse kan merkes med et haster flagg.
|
||||
For å raskt finne ut av hvilke saker som må løses raskt,
|
||||
kan man velge å kun vise hastesaker."
|
||||
>
|
||||
<RadioGroup
|
||||
legend="Velg visningstype"
|
||||
value={prioritet}
|
||||
onChange={(nyPrioritet: any) => settPrioritet(nyPrioritet)}
|
||||
>
|
||||
<Radio value={false}>Alle feil</Radio>
|
||||
<Radio value={true}>Kun feil som haster</Radio>
|
||||
</RadioGroup>
|
||||
</FilterModul>
|
||||
|
||||
<FilterModul
|
||||
tittel="Mine innmeldinger"
|
||||
beskrivelse="Som saksbehandler kan det være nyttig å finne tilbake til feil man har meldt inn for å sjekke status eller konklusjon."
|
||||
>
|
||||
<RadioGroup
|
||||
legend="Velg visningstype"
|
||||
value={visningstype}
|
||||
onChange={(nyVisningstype: any) => settVisningstype(nyVisningstype)}
|
||||
>
|
||||
<Radio value={false}>Alle feil</Radio>
|
||||
<Radio value={true}>Kun egne feil</Radio>
|
||||
</RadioGroup>
|
||||
</FilterModul>
|
||||
<KategoriFilter/>
|
||||
<StatusFilter/>
|
||||
<PrioritetFilter/>
|
||||
<MineInnmeldinger/>
|
||||
</Accordion>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -72,31 +16,99 @@ const Filtermeny = () => {
|
|||
export default Filtermeny
|
||||
|
||||
|
||||
/**
|
||||
* Filtermodul utgjør en modul for de forskjellige filterene som kan brukes i Filtermenyen.
|
||||
* Komponentet bygger på aksel sin Accordion komponent og enkelt elementer i denne.
|
||||
* Komponentet kan derfor ikke brukes utenfor en Accordion.
|
||||
* @param tittel Tittelen på filteret
|
||||
* @param beskrivelse Beskrivelse av hvordan kan brukes
|
||||
* @param children Innholdet i en Filtermodul, som er kontrollkomponenter for filteret
|
||||
* @returns
|
||||
*/
|
||||
const FilterModul = (props: ItemInterface) => {
|
||||
return(
|
||||
const KategoriFilter = () => {
|
||||
return (
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>
|
||||
{props.tittel}
|
||||
Kategori
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<p>{props.beskrivelse}</p>
|
||||
<br/>
|
||||
{props.children}
|
||||
<p>
|
||||
Denne løsningen er litt mer avansert enn den andre filtreringen. UFERDIG!!!!!!!!!!!
|
||||
</p>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)
|
||||
}
|
||||
interface ItemInterface {
|
||||
tittel: string
|
||||
beskrivelse: string
|
||||
children: React.ReactNode
|
||||
|
||||
|
||||
const StatusFilter = () => {
|
||||
return(
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>
|
||||
Status
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<p>
|
||||
Ved å filtrere etter status på forskjellig innmeldte feil
|
||||
kan du enkelt få oversikt over hvilke feil som ikke er påbegynte,
|
||||
hvilke som utredes av utviklingsteamet og løste feil.
|
||||
</p>
|
||||
<br/>
|
||||
<CheckboxGroup
|
||||
legend="Hvilke statusflagg ønsker du å vise?"
|
||||
>
|
||||
<Checkbox value="Ikke påbegynt">Velg alle</Checkbox>
|
||||
<Checkbox value="Ikke påbegynt">Ikke påbegynt</Checkbox>
|
||||
<Checkbox value="Jobbes med">Jobbes med</Checkbox>
|
||||
<Checkbox value="Ferdig med">Ferdig med</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const PrioritetFilter = () => {
|
||||
const [verdi, settVerdi] = useState(false)
|
||||
|
||||
return(
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>
|
||||
Prioritet
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<p>
|
||||
Saker som haster å løse kan merkes med et haster flagg.
|
||||
For å raskt finne ut av hvilke saker som må løses raskt,
|
||||
kan man velge å kun vise hastesaker.
|
||||
</p>
|
||||
<br/>
|
||||
<RadioGroup
|
||||
legend="Velg visningstype"
|
||||
value={verdi}
|
||||
onChange={(nyVerdi: any) => settVerdi(nyVerdi)}
|
||||
>
|
||||
<Radio value={false}>Alle feil</Radio>
|
||||
<Radio value={true}>Kun feil som haster</Radio>
|
||||
</RadioGroup>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)
|
||||
}
|
||||
|
||||
const MineInnmeldinger = () => {
|
||||
const [verdi, settVerdi] = useState(false)
|
||||
|
||||
return(
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>
|
||||
Mine innmeldinger
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
<p>
|
||||
Som saksbehandler kan det være nyttig å finne tilbake til feil man har meldt inn for å sjekke status eller konklusjon.
|
||||
</p>
|
||||
<br/>
|
||||
<RadioGroup
|
||||
legend="Velg visningstype"
|
||||
value={verdi}
|
||||
onChange={(nyVerdi: any) => settVerdi(nyVerdi)}
|
||||
>
|
||||
<Radio value={false}>Alle feil</Radio>
|
||||
<Radio value={true}>Kun egne feil</Radio>
|
||||
</RadioGroup>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,14 +1,20 @@
|
|||
import { InternalHeader } from "@navikt/ds-react"
|
||||
import { MenuGridIcon } from "@navikt/aksel-icons"
|
||||
import { InternalHeader, Dropdown } from "@navikt/ds-react"
|
||||
|
||||
/**
|
||||
* Headeren til applikasjonen, inneholder logo og lenke til hovedsiden.
|
||||
*/
|
||||
const Header = () => {
|
||||
return(
|
||||
<InternalHeader>
|
||||
<InternalHeader.Title href="/#home">
|
||||
Sprik
|
||||
</InternalHeader.Title>
|
||||
<Dropdown>
|
||||
<InternalHeader.Button
|
||||
as={Dropdown.Toggle}
|
||||
>
|
||||
<MenuGridIcon title="MenuGridIconer og oppslagsverk" />
|
||||
</InternalHeader.Button>
|
||||
{/* <Dropdown.Menu /> */}
|
||||
</Dropdown>
|
||||
</InternalHeader>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
import { ChatElipsisIcon, PencilIcon } from "@navikt/aksel-icons"
|
||||
import { TextField, Button, Heading } from "@navikt/ds-react"
|
||||
import Skillelinje from "./Skillelinje"
|
||||
import { useState } from "react"
|
||||
|
||||
interface kommentarInterface {
|
||||
kommentarfelt: string,
|
||||
setKommentarfelt: (val: string) => void
|
||||
oppdaterKommentar: () => void
|
||||
tekst: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Kommentartekstfeltet er et tekstfelt med en knapp som poster en kommentar til en feil.
|
||||
*/
|
||||
export const KommentarTekstfelt = (props: kommentarInterface) => {
|
||||
return (
|
||||
<div className="flex items-end gap-12 w-full mt-4 h-fit">
|
||||
<TextField
|
||||
className="grow"
|
||||
label="Skriv inn din kommentar til feilen"
|
||||
value={props.kommentarfelt}
|
||||
onChange={e => props.setKommentarfelt(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={<ChatElipsisIcon />}
|
||||
onClick={() => props.oppdaterKommentar()}
|
||||
>
|
||||
Legg til kommentar
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Kommentar er en komponent som viser en kommentar til en feil.
|
||||
* Komentaren kan beskrive konklusjonen til en feil, eller være en oppdatering på statusen til en feil.
|
||||
* @param tekst
|
||||
*/
|
||||
export const Kommentar = (props: kommentarInterface) => {
|
||||
const [redigerKommentar, setRedigerKommentar] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Skillelinje />
|
||||
{props.tekst.length === 0 || redigerKommentar ?
|
||||
<KommentarTekstfelt
|
||||
kommentarfelt={props.kommentarfelt}
|
||||
setKommentarfelt={props.setKommentarfelt}
|
||||
oppdaterKommentar={props.oppdaterKommentar}
|
||||
tekst={props.tekst}
|
||||
/>
|
||||
:
|
||||
<div className="flex flex-col gap-3 p-5 bg-bg-subtle rounded-lg w-2/3 my-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<Heading size="medium">Kommentar</Heading>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
icon={<PencilIcon />}
|
||||
onClick={() => {
|
||||
setRedigerKommentar(true);
|
||||
console.log(redigerKommentar);
|
||||
}}
|
||||
></Button>
|
||||
</div>
|
||||
<p className="break-words">{props.tekst}</p>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import FeilKort from "./FeilKort.tsx";
|
||||
import { Feilmelding } from "../interface.ts";
|
||||
|
||||
interface IKortKonteiner {
|
||||
feilmeldinger: Feilmelding[]
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Komponent som laster inn feilmeldinger i kort fra database.
|
||||
* @returns grid med feilmeldinger
|
||||
*/
|
||||
const KortKonteiner = (props: IKortKonteiner) => {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
{props.feilmeldinger.map((feilMelding) => (
|
||||
<FeilKort
|
||||
key={props.feilmeldinger.indexOf(feilMelding)}
|
||||
id={feilMelding.id}
|
||||
tittel={feilMelding.tittel}
|
||||
beskrivelse={feilMelding.beskrivelse}
|
||||
dato={new Date(feilMelding.dato)}
|
||||
arbeidsstatus={feilMelding.arbeidsstatus}
|
||||
haster={feilMelding.haster}
|
||||
reset={props.reset}
|
||||
kommentar={feilMelding.kommentar}
|
||||
aktorId={feilMelding.aktorid}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default KortKonteiner;
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
import { FloppydiskIcon, TrashIcon, XMarkIcon } from "@navikt/aksel-icons"
|
||||
import { TextField, Textarea, RadioGroup, Radio, Button, Switch, Heading } from "@navikt/ds-react"
|
||||
import { useState } from "react"
|
||||
import { FeilmeldingsInnholdInterface } from "../interface"
|
||||
import axios from "axios"
|
||||
import Skillelinje from "./Skillelinje"
|
||||
|
||||
interface redigeringsInterface extends FeilmeldingsInnholdInterface {
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Redigeringsverktøy er et skjema som lar brukeren redigere en innmeldt feil.
|
||||
* Statusflagg som arbeidsstatus og haster flagg kan endres.
|
||||
* Tittel og beskrivelse kan også endres
|
||||
*/
|
||||
const RedigeringsVerktoy = (props: redigeringsInterface) => {
|
||||
const [tittel, setTittel] = useState(props.tittel)
|
||||
const [beskrivelse, setBeskrivelse] = useState(props.beskrivelse)
|
||||
const [arbeidsstatus, setArbeidsstatus] = useState(props.arbeidsstatus)
|
||||
const [haster, setHaster] = useState(props.haster)
|
||||
|
||||
|
||||
const lagreEndringer = async() => {
|
||||
props.setVisModal(false)
|
||||
props.setRedigeringsmodus(false)
|
||||
|
||||
const payload = {
|
||||
id: props.id,
|
||||
tittel: tittel,
|
||||
beskrivelse: beskrivelse,
|
||||
dato: props.dato.toISOString().replace('Z', ''),
|
||||
arbeidsstatus: arbeidsstatus,
|
||||
haster: haster,
|
||||
kommentar: props.kommentar,
|
||||
aktorid: props.aktorId
|
||||
}
|
||||
|
||||
await axios.put(`/api/oppdaterfeil`, payload, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then((response) => {
|
||||
console.log(response);
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
|
||||
props.reset()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-12 items-center px-12">
|
||||
<div className="flex flex-col gap-6 w-full">
|
||||
<Heading className="" size="large">
|
||||
Rediger feil
|
||||
</Heading>
|
||||
<TextField
|
||||
label="Tittel"
|
||||
value={tittel}
|
||||
onChange={e => setTittel(e.target.value)}
|
||||
/>
|
||||
<Textarea
|
||||
label="Beskrivelse"
|
||||
value={beskrivelse}
|
||||
onChange={e => setBeskrivelse(e.target.value)}
|
||||
/>
|
||||
<Skillelinje/>
|
||||
<RadioGroup
|
||||
legend="Velg arbeidsstatus for feil"
|
||||
onChange={(arbeidsstatus: number) => {setArbeidsstatus(arbeidsstatus)}}
|
||||
value={arbeidsstatus}
|
||||
>
|
||||
<Radio value={0}>Ikke påbegynt</Radio>
|
||||
<Radio value={1}>Feilen jobbes med</Radio>
|
||||
<Radio value={2}>Feilen er fikset</Radio>
|
||||
</RadioGroup>
|
||||
<Skillelinje/>
|
||||
<div>
|
||||
<Heading size="xsmall">
|
||||
Haster det å fikse feilen?
|
||||
</Heading>
|
||||
<Switch checked={haster} onClick={() => setHaster(!haster)}>
|
||||
Feilen haster
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4 items-start w-full">
|
||||
<Button
|
||||
variant="primary"
|
||||
icon={<FloppydiskIcon/>}
|
||||
onClick={() => lagreEndringer()}
|
||||
>
|
||||
Lagre
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
icon={<XMarkIcon/>}
|
||||
onClick={() => {
|
||||
props.setRedigeringsmodus(false)
|
||||
}}
|
||||
>
|
||||
Avbryt
|
||||
</Button>
|
||||
<SlettFeilKnapp setVisModal={props.setVisModal} reset={props.reset} id={props.id}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default RedigeringsVerktoy;
|
||||
|
||||
|
||||
const SlettFeilKnapp = (props: {
|
||||
id : number
|
||||
reset: () => void
|
||||
setVisModal: (visModal: boolean) => void
|
||||
}) => {
|
||||
const SlettFeil = async () => {
|
||||
await axios.delete(`/api/slettfeilmelding/${props.id}`)
|
||||
props.reset()
|
||||
props.setVisModal(false)
|
||||
}
|
||||
|
||||
return(
|
||||
<Button
|
||||
variant="danger"
|
||||
icon={<TrashIcon/>}
|
||||
onClick={SlettFeil}
|
||||
>
|
||||
Slett feil
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
/**
|
||||
* Skillelinjer som brukes for å dele opp innholdet i et komponent/skjema i mindre deler
|
||||
* Forbedrer lesbarheten til skjemaet
|
||||
*/
|
||||
const Skillelinje = () => {
|
||||
return (
|
||||
<div className="h-1 bg-gray-200 my-3 rounded-lg w-full"></div>
|
||||
)
|
||||
}
|
||||
export default Skillelinje
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import { Tag } from "@navikt/ds-react";
|
||||
|
||||
interface TagBarInterface {
|
||||
haster: boolean
|
||||
arbeidsstatus: number
|
||||
}
|
||||
|
||||
/**
|
||||
* @param arbeidsstatus er en kode som beskriver om feilen er fikset, jobbes med eller ikke påbegynt. må være 0, 1 eller 2.
|
||||
* @returns Tag komponent med riktig farge og tekst basert på arbeidsstatus-kode
|
||||
*/
|
||||
const toggleArbeidsstatus = (arbeidsstatus: number) => {
|
||||
switch (arbeidsstatus) {
|
||||
case 0:
|
||||
return <Tag variant="neutral">Ikke påbegynt</Tag>;
|
||||
case 1:
|
||||
return <Tag variant="info">Feilen jobbes med</Tag>;
|
||||
case 2:
|
||||
return <Tag variant="success">Feilen er fikset</Tag>;
|
||||
default:
|
||||
throw new Error("Ikke gyldig arbeidsstatus-kode. Koden må være 0, 1 eller 2");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Komponentet er en bar (vanrett linje) som inneholder to statusflagg: "arbeidsstatus" og "Haster".
|
||||
* Komponentet er en del av FeilKortHeader
|
||||
* @param haster er en boolean som beskriver om feilen haster eller ikke.
|
||||
* @param arbeidsstatus er en kode som beskriver om feilen er fikset, jobbes med eller ikke påbegynt. må være 0, 1 eller 2.
|
||||
*/
|
||||
const TagBar = (props: TagBarInterface) => {
|
||||
return (
|
||||
<div className="flex gap-3 mt-4">
|
||||
{toggleArbeidsstatus(props.arbeidsstatus)}
|
||||
{props.haster ? <Tag variant="warning">Haster</Tag> : <></>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TagBar;
|
||||
|
|
@ -1,36 +1,70 @@
|
|||
import KortKonteiner from "./components/KortKonteiner";
|
||||
import CardsContainer from "./components/CardsContainer";
|
||||
import "@navikt/ds-css";
|
||||
import { Button, Heading, Search } from "@navikt/ds-react";
|
||||
import { Alert, Button, Search } from "@navikt/ds-react";
|
||||
import Header from "./components/Header";
|
||||
import { PlusIcon } from "@navikt/aksel-icons";
|
||||
import Filtermeny from "./components/Filtermeny";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Feilmelding } from "./interface";
|
||||
import { StatusContext } from "./pages/feil";
|
||||
|
||||
/**
|
||||
* Hovedsiden til applikasjonen, viser alle innmeldte feil.
|
||||
* Tilbyr søkefelt og filtreringsmuligheter
|
||||
* Tilbyr også navigering til feilinnmeldingssiden
|
||||
*/
|
||||
export default function Home() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [feilmeldinger, setFeilmeldinger] = useState<Feilmelding[]>([]);
|
||||
|
||||
const [alert, setAlert] = useState(<></>)
|
||||
|
||||
const hentAlleFeil = async () => {
|
||||
const { data } = await axios.get("/api/hentallefeil")
|
||||
setFeilmeldinger(data)
|
||||
const status = useContext(StatusContext)
|
||||
|
||||
const toggleAlert = (status: number) => {
|
||||
if (status === 0) {
|
||||
console.log("oppdaget status var 0");
|
||||
return
|
||||
}
|
||||
else if (status === 201) {
|
||||
setAlert(<Alert variant="success">Woho</Alert>)
|
||||
} else {
|
||||
setAlert(<Alert variant="error">error</Alert>)
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
setAlert(<></>)
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
toggleAlert(status.status)
|
||||
})
|
||||
|
||||
/**
|
||||
* Henter alle feilmeldinger fra backend.
|
||||
* Bruker endepunktet /api/hentallefeil.
|
||||
*/
|
||||
const hentAlleFeil = async () => {
|
||||
await axios.get("/api/hentallefeil")
|
||||
.then(data => data.data)
|
||||
.then(feil => {
|
||||
setFeilmeldinger(
|
||||
feil.map((jsonFeilmelding: any) => new Feilmelding(jsonFeilmelding))
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
// Sørger for at hentAlleFeil() kun kjører når komponentet laster inn
|
||||
useEffect(() => {
|
||||
hentAlleFeil();
|
||||
}, [])
|
||||
|
||||
|
||||
//oppdaterer visningen av feilmeldinger når søkefeltet endres
|
||||
/**
|
||||
* Oppdaterer viste feilmeldinger ved endring i søkefelt.
|
||||
* Kontakter endepunktet /api/hentsok/.
|
||||
* @param soketekst
|
||||
*/
|
||||
const handleSearch = async (soketekst: string) => {
|
||||
// Ved tomt søkefelt hentes alle feilmeldinger
|
||||
if (soketekst === "") {
|
||||
hentAlleFeil()
|
||||
return
|
||||
|
|
@ -39,17 +73,15 @@ export default function Home() {
|
|||
setFeilmeldinger(data)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<main className="flex flex-col h-screen">
|
||||
<Header/>
|
||||
<div className="flex grow">
|
||||
<Filtermeny/>
|
||||
<div className="grow bg-bg-subtle px-32 py-8 flex flex-col gap-10">
|
||||
<Heading level="1" size="xlarge">Innmeldte feil</Heading>
|
||||
{alert}
|
||||
<div className="flex gap-12 items-end">
|
||||
<Search
|
||||
data-testid="soke-inputfelt"
|
||||
label="Søkefelt"
|
||||
description="Søk gjennom innmeldte feil (nøkkelord, tags, status)"
|
||||
hideLabel={false}
|
||||
|
|
@ -57,13 +89,13 @@ export default function Home() {
|
|||
/>
|
||||
<Button
|
||||
className="w-64 h-min"
|
||||
icon={<PlusIcon aria-label="PlusIcon"/>}
|
||||
icon={<PlusIcon/>}
|
||||
onClick={() => navigate("nyfeil")}
|
||||
>
|
||||
Meld inn feil
|
||||
</Button>
|
||||
</div>
|
||||
<KortKonteiner reset={hentAlleFeil} feilmeldinger={feilmeldinger}/>
|
||||
<CardsContainer feilmeldinger={feilmeldinger}/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -1,45 +1,29 @@
|
|||
/*
|
||||
* I denne filen kan vi legge interfaces som skal brukes over flere steder!
|
||||
*/
|
||||
|
||||
|
||||
export interface IFeilmelding {
|
||||
id: number,
|
||||
tittel: string,
|
||||
beskrivelse: string
|
||||
// haster: boolean
|
||||
dato: Date
|
||||
arbeidsstatus: number
|
||||
haster: boolean
|
||||
kommentar?: string
|
||||
aktorId?: number
|
||||
}
|
||||
|
||||
export interface FeilmeldingsInnholdInterface extends IFeilmelding {
|
||||
children?: React.ReactNode
|
||||
setRedigeringsmodus: (redigeringsmodus: boolean) => void
|
||||
setVisModal: (visModal: boolean) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* En klasse som implementerer IFeilmelding interfacet.
|
||||
* Brukes for å mappe JSON objekter til en klasse ved henting av data fra backend
|
||||
*/
|
||||
export class Feilmelding implements IFeilmelding {
|
||||
id: number = 0
|
||||
tittel: string = "default tittel"
|
||||
beskrivelse: string = "default beskrivelse"
|
||||
dato: Date = new Date()
|
||||
arbeidsstatus: number = 0
|
||||
haster: boolean = false
|
||||
kommentar?: string = undefined
|
||||
aktorid?: number = undefined
|
||||
|
||||
/**
|
||||
* Typescript 2.1 syntax som lar deg sende inn et JSON object og mappe det til class.
|
||||
* https://stackoverflow.com/questions/14142071/typescript-and-field-initializers
|
||||
*/
|
||||
public constructor(
|
||||
fields: {
|
||||
id: number
|
||||
tittel: string
|
||||
beskrivelse: string
|
||||
tittel: string,
|
||||
beskrivelse: string,
|
||||
dato: Date
|
||||
arbeidsstatus: number
|
||||
haster: boolean
|
||||
kommentar: string
|
||||
aktorId: number
|
||||
}) {
|
||||
if (fields) Object.assign(this, fields);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import './index.css'
|
|||
import Home from './index'
|
||||
import Feil from './pages/feil'
|
||||
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
|
|
|
|||
|
|
@ -1,45 +1,31 @@
|
|||
import "@navikt/ds-css";
|
||||
|
||||
import { ArrowLeftIcon, BugIcon } from "@navikt/aksel-icons";
|
||||
import { Alert, Button, Chips, Heading, Switch, TextField, Textarea } from "@navikt/ds-react";
|
||||
import { Button, Heading, TextField, Textarea } from "@navikt/ds-react";
|
||||
import axios from "axios";
|
||||
import { useState } from "react";
|
||||
import { createContext, useState } from "react";
|
||||
import BildeOpplastning from "../components/BildeOpplastning";
|
||||
import Header from "../components/Header";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Skillelinje from "../components/Skillelinje";
|
||||
|
||||
/**
|
||||
* Siden for å melde inn feil i speil.
|
||||
*/
|
||||
export const StatusContext = createContext({
|
||||
status: 404,
|
||||
setStatus: (value: number) => {}
|
||||
})
|
||||
|
||||
export default function Feil() {
|
||||
const navigate = useNavigate()
|
||||
const [tittel, setTittel] = useState("");
|
||||
const [beskrivelse, setBeskrivelse] = useState("");
|
||||
const [status, setStatus] = useState(0)
|
||||
const [haster, setHaster] = useState(false)
|
||||
const [valgteTags, setValgteTags] = useState([] as string[]);
|
||||
const [aktorid, setAktorid] = useState<number|null>(null);
|
||||
const navigate = useNavigate()
|
||||
const tags = [
|
||||
"Utbetaling",
|
||||
"Inntekt",
|
||||
"Speil",
|
||||
"Annet"
|
||||
];
|
||||
|
||||
//Sender feil til databasen
|
||||
const meldInnFeil = () => {
|
||||
|
||||
const handleSubmit = () => {
|
||||
|
||||
const payload = {
|
||||
id: null,
|
||||
tittel: tittel,
|
||||
beskrivelse: beskrivelse,
|
||||
dato: new Date().toISOString().replace('Z', ''),
|
||||
arbeidsstatus: 0,
|
||||
haster: haster,
|
||||
kommentar: null,
|
||||
aktorid: aktorid ? aktorid : null,
|
||||
//TODO: kategorier: valgteTags
|
||||
dato: new Date().toISOString().replace('Z', '')
|
||||
}
|
||||
|
||||
axios.post("/api/nyfeil", payload, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
@ -49,31 +35,23 @@ export default function Feil() {
|
|||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
|
||||
navigate("/")
|
||||
}
|
||||
|
||||
//Håndterer alerts som vises etter at feil er lagt til i databasen eller feiler i å bli lagt til
|
||||
const handleAlerts = () => {
|
||||
if (status === 201) {
|
||||
console.log("Feil lagt til i database");
|
||||
setTimeout(() =>
|
||||
{
|
||||
navigate("/");
|
||||
},
|
||||
5000);
|
||||
return <Alert variant="success">Feil er meldt inn! Du vil nå sendes tilbake til hovedmenyen om fem sekunder.</Alert>
|
||||
} else {
|
||||
console.log("Noe gikk galt, feil ikke lagt til i database!");
|
||||
return <Alert variant="error">Noe gikk galt! Prøv igjen om noen minutter.</Alert>
|
||||
}
|
||||
}
|
||||
const [status, setStatus] = useState(0)
|
||||
|
||||
const statusContextVerdi = {status, setStatus}
|
||||
|
||||
// TODO: clear data fra felter
|
||||
|
||||
return (
|
||||
<StatusContext.Provider value={statusContextVerdi}>
|
||||
<main className="flex flex-col h-screen">
|
||||
<Header/>
|
||||
<div className="flex items">
|
||||
<div className=" bg-bg-subtle grow"></div>
|
||||
|
||||
<div className="w-3/5 flex flex-col justify-center gap-8 px-16 py-8">
|
||||
<div className="flex grow">
|
||||
<div className="w-1/4 bg-bg-subtle"></div>
|
||||
<div className="flex flex-col justify-center gap-16 p-8 px-16 grow">
|
||||
<div className=" flex flex-col gap-2 justify-center">
|
||||
<BugIcon
|
||||
title="Insekts ikon"
|
||||
|
|
@ -88,65 +66,19 @@ export default function Feil() {
|
|||
</div>
|
||||
<div className="w-1/2 flex flex-col gap-4 justify-center">
|
||||
<TextField
|
||||
data-testid="tittel-inputfelt"
|
||||
label="Tittel"
|
||||
onChange={e => setTittel(e.target.value)}
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
data-testid="beskrivelse-inputfelt"
|
||||
label="Beskrivelse"
|
||||
description="Detaljert beskrivelse av problemet"
|
||||
onChange={e => setBeskrivelse(e.target.value)}
|
||||
/>
|
||||
<Skillelinje/>
|
||||
<BildeOpplastning/>
|
||||
|
||||
<Skillelinje/>
|
||||
<Heading size="xsmall">
|
||||
Haster det å fikse feilen?
|
||||
</Heading>
|
||||
<Switch
|
||||
data-testid="switch-toggle"
|
||||
onClick={() => setHaster(!haster)}
|
||||
>
|
||||
Saken Haster
|
||||
</Switch>
|
||||
|
||||
<Skillelinje/>
|
||||
<TextField
|
||||
label="Aktør-ID (valgfritt)"
|
||||
description="Legg ved aktør-ID om det er relevant"
|
||||
onChange={e => setAktorid(parseInt(e.target.value))}
|
||||
/>
|
||||
|
||||
<Skillelinje/>
|
||||
<Heading size="xsmall">
|
||||
Velg kategorier som passer
|
||||
</Heading>
|
||||
<Chips>
|
||||
{tags.map((c) => (
|
||||
<Chips.Toggle
|
||||
selected={valgteTags.includes(c)}
|
||||
key={c}
|
||||
onClick={() =>
|
||||
setValgteTags(
|
||||
valgteTags.includes(c)
|
||||
? valgteTags.filter((x) => x !== c)
|
||||
: [...valgteTags, c]
|
||||
)
|
||||
}
|
||||
>
|
||||
{c}
|
||||
</Chips.Toggle>
|
||||
))}
|
||||
</Chips>
|
||||
|
||||
</div>
|
||||
<div className="w-1/2 flex flex-col gap-2 justify-center mt-8">
|
||||
{status != 0 ? handleAlerts() : <></>}
|
||||
<div className="w-1/2 flex flex-col gap-2 justify-center">
|
||||
<Button
|
||||
onClick={meldInnFeil}
|
||||
onClick={handleSubmit}
|
||||
variant="primary"
|
||||
>
|
||||
Meld inn feil
|
||||
|
|
@ -160,9 +92,9 @@ export default function Feil() {
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className=" bg-bg-subtle grow"></div>
|
||||
<div className="w-1/4 bg-bg-subtle"></div>
|
||||
</div>
|
||||
</main>
|
||||
</StatusContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
@ -250,9 +250,9 @@
|
|||
integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==
|
||||
|
||||
"@cypress/request@^2.88.11":
|
||||
version "2.88.12"
|
||||
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.12.tgz#ba4911431738494a85e93fb04498cb38bc55d590"
|
||||
integrity sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==
|
||||
version "2.88.11"
|
||||
resolved "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz"
|
||||
integrity sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
|
|
@ -269,7 +269,7 @@
|
|||
performance-now "^2.1.0"
|
||||
qs "~6.10.3"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "^4.1.3"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^8.3.2"
|
||||
|
||||
|
|
@ -1457,19 +1457,14 @@ csstype@^3.0.2:
|
|||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
cypress-axe@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/cypress-axe/-/cypress-axe-1.4.0.tgz"
|
||||
integrity sha512-Ut7NKfzjyKm0BEbt2WxuKtLkIXmx6FD2j0RwdvO/Ykl7GmB/qRQkwbKLk3VP35+83hiIr8GKD04PDdrTK5BnyA==
|
||||
|
||||
cypress-plugin-config@^1.0.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/cypress-plugin-config/-/cypress-plugin-config-1.2.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/cypress-plugin-config/-/cypress-plugin-config-1.2.1.tgz#aa7eaa55ab5ce5e186ab7d0e37cc7e42bfb609b4"
|
||||
integrity sha512-z+bQ7oyfDKun51HiCVNBOR+g38/nYRJ7zVdCZT2/9UozzE8P4iA1zF/yc85ePZLy5NOj/0atutoUPBBR5SqjSQ==
|
||||
|
||||
cypress-slow-down@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/cypress-slow-down/-/cypress-slow-down-1.2.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/cypress-slow-down/-/cypress-slow-down-1.2.1.tgz#d10c75c2f79240812f4e58824e09d057a2d0e24d"
|
||||
integrity sha512-Pd+nESR+Ca8I+mLGbBrPVMEFvJBWxkJcEdcIUDxSBnMoWI00hiIKxzEgVqCv5c6Oap2OPpnrPLbJBwveCNKLig==
|
||||
dependencies:
|
||||
cypress-plugin-config "^1.0.0"
|
||||
|
|
@ -3035,9 +3030,9 @@ proxy-from-env@^1.1.0:
|
|||
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
psl@^1.1.33:
|
||||
psl@^1.1.28:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
|
||||
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
||||
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
|
||||
|
||||
pump@^3.0.0:
|
||||
|
|
@ -3060,11 +3055,6 @@ qs@~6.10.3:
|
|||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
querystringify@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
||||
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||
|
|
@ -3198,11 +3188,6 @@ require-from-string@^2.0.2:
|
|||
resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
|
||||
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
|
||||
|
||||
requires-port@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||
|
|
@ -3640,15 +3625,13 @@ to-regex-range@^5.0.1:
|
|||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
tough-cookie@^4.1.3:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
||||
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
dependencies:
|
||||
psl "^1.1.33"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
universalify "^0.2.0"
|
||||
url-parse "^1.5.3"
|
||||
|
||||
trim-newlines@^4.0.2:
|
||||
version "4.1.1"
|
||||
|
|
@ -3716,11 +3699,6 @@ typescript@^5.0.2:
|
|||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz"
|
||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
||||
|
||||
universalify@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
|
||||
integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
||||
|
|
@ -3746,14 +3724,6 @@ uri-js@^4.2.2:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
url-parse@^1.5.3:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
|
||||
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
|
||||
dependencies:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
use-sync-external-store@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz"
|
||||
|
|
|
|||
4
yarn.lock
Normal file
4
yarn.lock
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
Reference in a new issue