Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b7adc20
Add hasPermission function
BoraIneviNMI Nov 24, 2025
f1d03f0
Add disabled buttons to field cultivations
BoraIneviNMI Nov 24, 2025
52b2059
Add disabled buttons to field fertilizer applications
BoraIneviNMI Nov 25, 2025
f66c715
Add disabled buttons to field soil analyses
BoraIneviNMI Nov 25, 2025
e9baf56
Remove remove field tab if the user has no permission
BoraIneviNMI Nov 25, 2025
4474c08
Add disabled buttons to the field table
BoraIneviNMI Nov 25, 2025
0cf89b6
Add disabled buttons to the farm overview
BoraIneviNMI Nov 25, 2025
ff417f3
Add disabled buttons to the cultivation overview
BoraIneviNMI Nov 25, 2025
8836803
Handle farm share and delete permissions properly
BoraIneviNMI Nov 25, 2025
4f62209
Add disabled buttons to the fertilizer manager
BoraIneviNMI Nov 25, 2025
3337f33
Hide add cultivation button altogether if the user can't add a cultiv…
BoraIneviNMI Nov 25, 2025
0dc22b0
Disable calendar button on disabled v1 date pickers
BoraIneviNMI Nov 25, 2025
cac548c
Remove unused permission from loader
BoraIneviNMI Nov 25, 2025
af614b3
Handle access change in fertilizer application card
BoraIneviNMI Nov 25, 2025
91c357c
Disable fieldset in cultivation form for consistency
BoraIneviNMI Nov 25, 2025
6c36805
Allow viewing the soil analysis details for users with no write permi…
BoraIneviNMI Nov 25, 2025
9dbee59
Make entire harvest form disabled
BoraIneviNMI Nov 25, 2025
9d677aa
Disable calendar button on disabled v2 date pickers
BoraIneviNMI Nov 25, 2025
07ea0de
Add some editable prop default values
BoraIneviNMI Nov 25, 2025
19a2844
Add fallback value support to hasPermission and make use of it
BoraIneviNMI Nov 25, 2025
f545dd4
Fix and improve tests
BoraIneviNMI Nov 25, 2025
fb7126b
Call hasPermission concurrently in the loader loader for field cultiv…
BoraIneviNMI Nov 25, 2025
1b0dff7
Update loader documentation for some routes
BoraIneviNMI Nov 25, 2025
8a189b4
Hide inline harvest form buttons if it is not editable
BoraIneviNMI Nov 25, 2025
fb4dfa5
Add disabled buttons to empty field and cultivation overview tables
BoraIneviNMI Nov 25, 2025
ab554d3
Remove add button altogether in the field fertilizer applications
BoraIneviNMI Nov 26, 2025
73f1436
Add disabled buttons to the farm settings properties route
BoraIneviNMI Nov 26, 2025
c3616f2
Merge branch 'development' into FDM321-fdm-app
BoraIneviNMI Nov 26, 2025
84e8095
Do not hide any buttons in the farm overview
BoraIneviNMI Nov 26, 2025
09688e6
Add disabled buttons to the farm derogation
BoraIneviNMI Nov 26, 2025
3da135d
Add disabled buttons to the farm bio-certificate settings
BoraIneviNMI Nov 26, 2025
ca3826d
Fix flaky getRolesOfPrincipalForResource test
BoraIneviNMI Nov 26, 2025
2ad7030
Add missing effect dependencies in fertilizer application card
BoraIneviNMI Nov 26, 2025
24ac7ab
Update documentation for hasPermission
BoraIneviNMI Nov 26, 2025
6f464a1
Add disabled buttons to the farm grazing intention settings
BoraIneviNMI Nov 26, 2025
bcc2f04
Improve derogation text
BoraIneviNMI Nov 26, 2025
de0ae02
Add missing fallback true
BoraIneviNMI Nov 26, 2025
05ecb4a
Fix various issues about the field harvests
BoraIneviNMI Nov 26, 2025
0dca996
Fix import in farm.tsx
BoraIneviNMI Nov 26, 2025
d8dcd23
Add changeset
BoraIneviNMI Nov 26, 2025
f4c2b6f
Add disabled buttons to the single field overview page
BoraIneviNMI Nov 26, 2025
b888e92
Get rid of the hasPermission function
BoraIneviNMI Nov 26, 2025
4c8a4f0
Use the extended checkPermission function in loaders
BoraIneviNMI Nov 27, 2025
0eec169
Make use of display: none and visibility: hidden for consistency
BoraIneviNMI Nov 27, 2025
c042651
Merge branch 'development' into FDM321-fdm-app
BoraIneviNMI Nov 27, 2025
1757574
Update changeset
BoraIneviNMI Nov 27, 2025
d975484
Fix typo
BoraIneviNMI Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dark-wombats-slide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@svenvw/fdm-core": minor
---

Added the optional `strict` parameter to the `checkPermission` function, which, when specified as false, disables audit logging, and throwing an exception if the principal has no permission.
5 changes: 5 additions & 0 deletions .changeset/jolly-pens-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@svenvw/fdm-app": minor
---

Various UI elements are now hidden or grayed out if the current logged-in user doesn't have permission to perform the actions that they represent.
19 changes: 16 additions & 3 deletions fdm-app/app/components/blocks/cultivation/card-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SelectTrigger,
SelectValue,
} from "~/components/ui/select"
import { cn } from "~/lib/utils"
import {
CultivationDetailsFormSchema,
type CultivationDetailsFormSchemaType,
Expand All @@ -30,9 +31,11 @@ import {
export function CultivationDetailsCard({
cultivation,
b_lu_variety_options,
editable = true,
}: {
cultivation: Cultivation
b_lu_variety_options: { value: string; label: string }[]
editable?: boolean
}) {
const fetcher = useFetcher()
const form = useRemixForm<CultivationDetailsFormSchemaType>({
Expand Down Expand Up @@ -72,7 +75,7 @@ export function CultivationDetailsCard({
<CardTitle className="text-xl font-semibold tracking-tight text-gray-900">
{cultivation.b_lu_name}
</CardTitle>
{!isCreateWizard ? (
{!isCreateWizard && editable ? (
<div className="flex justify-between">
<Button
variant="destructive"
Expand All @@ -98,6 +101,7 @@ export function CultivationDetailsCard({
<Form onSubmit={form.handleSubmit} method="post">
<fieldset
disabled={
!editable ||
form.formState.isSubmitting ||
fetcher.state === "submitting"
}
Expand All @@ -109,12 +113,14 @@ export function CultivationDetailsCard({
name="b_lu_start"
label="Zaaidatum"
description=""
disabled={!editable}
/>
<DatePicker
form={form}
name="b_lu_end"
label="Einddatum"
description=""
disabled={!editable}
/>
</div>
<div className="grid lg:grid-cols-2 gap-4 items-end">
Expand All @@ -132,6 +138,7 @@ export function CultivationDetailsCard({
field.onChange
}
disabled={
!editable ||
form.formState
.isSubmitting ||
fetcher.state ===
Expand All @@ -158,8 +165,9 @@ export function CultivationDetailsCard({
onValueChange={field.onChange}
value={field.value ?? undefined}
disabled={
!editable ||
b_lu_variety_options.length ===
0
0
}
>
<FormControl>
Expand Down Expand Up @@ -196,7 +204,12 @@ export function CultivationDetailsCard({
)}
/>
</div>
<div className="flex justify-end">
<div
className={cn(
"flex justify-end",
!editable ? "invisible" : "",
)}
>
<Button
type="submit"
disabled={
Expand Down
32 changes: 19 additions & 13 deletions fdm-app/app/components/blocks/cultivation/card-harvests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ export function CultivationHarvestsCard({
harvests,
b_lu_harvestable,
harvestParameters,
editable = true,
}: {
harvests: Harvest[]
b_lu_harvestable: HarvestableType
harvestParameters: HarvestParameters
editable?: boolean
}) {
let canAddHarvest = false
if (b_lu_harvestable === "once" && harvests.length === 0) {
Expand All @@ -22,6 +24,7 @@ export function CultivationHarvestsCard({
if (b_lu_harvestable === "multiple") {
canAddHarvest = true
}
canAddHarvest &&= editable

return (
<Card>
Expand All @@ -30,22 +33,25 @@ export function CultivationHarvestsCard({
{b_lu_harvestable === "multiple" ? "Oogsten" : "Oogst"}
</CardTitle>
<div className="flex justify-between">
<NavLink
to="./harvest/new"
onClick={(e) => {
if (!canAddHarvest) {
e.preventDefault()
}
}}
className={!canAddHarvest ? "cursor-not-allowed" : ""}
<Button
asChild
variant="default"
className={cn(!canAddHarvest ? "hidden" : "")}
>
<Button
variant="default"
className={cn(!canAddHarvest ? "hidden" : "")}
<NavLink
to="./harvest/new"
onClick={(e) => {
if (!canAddHarvest) {
e.preventDefault()
}
}}
className={
!canAddHarvest ? "cursor-not-allowed" : ""
}
>
Oogst toevoegen
</Button>
</NavLink>
</NavLink>
</Button>
</div>
</CardHeader>
<CardContent className="space-y-6">
Expand Down
4 changes: 3 additions & 1 deletion fdm-app/app/components/blocks/cultivation/card-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ export function CultivationListCard({
cultivationsCatalogueOptions,
cultivations,
harvests,
editable = true,
}: {
cultivationsCatalogueOptions: CultivationOption[]
cultivations: Cultivation[]
harvests: Harvest[]
editable?: boolean
}) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle className="text-xl font-semibold tracking-tight text-gray-900">
Gewassen
</CardTitle>
{cultivations.length !== 0 ? (
{cultivations.length !== 0 && editable ? (
<CultivationAddFormDialog
options={cultivationsCatalogueOptions}
/>
Expand Down
9 changes: 6 additions & 3 deletions fdm-app/app/components/blocks/cultivation/form-add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import {
import { CultivationAddFormSchema } from "./schema"
import type { CultivationsFormProps } from "./types"

export function CultivationAddFormDialog({ options }: CultivationsFormProps) {
export function CultivationAddFormDialog({
options,
}: CultivationsFormProps) {
const [isOpen, setIsOpen] = useState(false)

return (
Expand All @@ -41,7 +43,8 @@ export function CultivationAddFormDialog({ options }: CultivationsFormProps) {
function CultivationAddForm({
options,
onSuccess,
}: CultivationsFormProps & { onSuccess?: () => void }) {
editable = true,
}: CultivationsFormProps & { editable?: boolean; onSuccess?: () => void }) {
const form = useRemixForm<z.infer<typeof CultivationAddFormSchema>>({
mode: "onTouched",
resolver: zodResolver(CultivationAddFormSchema),
Expand Down Expand Up @@ -70,7 +73,7 @@ function CultivationAddForm({
onSubmit={form.handleSubmit}
method="post"
>
<fieldset disabled={form.formState.isSubmitting}>
<fieldset disabled={!editable || form.formState.isSubmitting}>
<div className="grid gap-4">
<div className="col-span-1">
<Combobox
Expand Down
34 changes: 30 additions & 4 deletions fdm-app/app/components/blocks/fertilizer-applications/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog"
import { cn } from "~/lib/utils"
import { FertilizerApplicationForm } from "./form"
import { FertilizerApplicationsList } from "./list"
import type { FertilizerApplication, FertilizerOption } from "./types.d"
Expand All @@ -24,6 +25,8 @@ export function FertilizerApplicationCard({
applicationMethodOptions,
fertilizers,
fertilizerOptions,
canCreateFertilizerApplication = true,
canModifyFertilizerApplication = {},
}: {
fertilizerApplications: FertilizerApplication[]
applicationMethodOptions: {
Expand All @@ -34,6 +37,8 @@ export function FertilizerApplicationCard({
fertilizerOptions: FertilizerOption[]
dose: Dose
className?: string
canCreateFertilizerApplication?: boolean
canModifyFertilizerApplication?: Record<string, boolean>
}) {
const fetcher = useFetcher()
const location = useLocation()
Expand Down Expand Up @@ -108,14 +113,26 @@ export function FertilizerApplicationCard({
if (savedFormValues && !isDialogOpen) {
if (savedFormValues.p_app_id) {
// Do not open the form if there is a risk it will create a new application
if (applicationToEdit) {
if (
applicationToEdit &&
(canModifyFertilizerApplication[
applicationToEdit.p_app_id
] ??
true)
) {
setIsDialogOpen(true)
}
} else {
} else if (canCreateFertilizerApplication) {
setIsDialogOpen(true)
}
}
}, [savedFormValues, applicationToEdit, isDialogOpen])
}, [
savedFormValues,
applicationToEdit,
isDialogOpen,
canCreateFertilizerApplication,
canModifyFertilizerApplication,
])

function handleDialogOpenChange(state: boolean) {
if (!state && params.b_id_farm && b_id_or_b_lu_catalogue) {
Expand Down Expand Up @@ -143,7 +160,13 @@ export function FertilizerApplicationCard({
onOpenChange={handleDialogOpenChange}
>
<DialogTrigger asChild>
<Button>
<Button
className={cn(
!canCreateFertilizerApplication
? "invisible"
: "",
)}
>
<Plus className="size-4" />
Toevoegen
</Button>
Expand Down Expand Up @@ -181,6 +204,9 @@ export function FertilizerApplicationCard({
fertilizers={fertilizers}
handleDelete={handleDelete}
handleEdit={handleEdit}
canModifyFertilizerApplication={
canModifyFertilizerApplication
}
/>
</CardContent>
</Card>
Expand Down
18 changes: 15 additions & 3 deletions fdm-app/app/components/blocks/fertilizer-applications/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { format } from "date-fns"
import { nl } from "date-fns/locale"
import { Circle, Diamond, Square, Trash, Triangle } from "lucide-react"
import { useFetcher } from "react-router"
import { LoadingSpinner } from "~/components/custom/loadingspinner"
import { Button } from "~/components/ui/button"
import {
Empty,
Expand All @@ -26,12 +27,13 @@ import {
TooltipProvider,
TooltipTrigger,
} from "~/components/ui/tooltip"
import { LoadingSpinner } from "../../custom/loadingspinner"
import { cn } from "~/lib/utils"

export function FertilizerApplicationsList({
fertilizerApplications,
applicationMethodOptions,
fertilizers,
canModifyFertilizerApplication = {},
handleDelete,
handleEdit,
}: {
Expand All @@ -41,6 +43,7 @@ export function FertilizerApplicationsList({
label: string
}[]
fertilizers: Fertilizer[]
canModifyFertilizerApplication?: Record<string, boolean>
handleDelete: (p_app_id: string | string[]) => void
handleEdit: (fertilizerApplication: FertilizerApplication) => () => void
}) {
Expand All @@ -57,6 +60,10 @@ export function FertilizerApplicationsList({
if (!fertilizer) {
return null
}
const editable =
canModifyFertilizerApplication[
application.p_app_id
] ?? true

return (
<div key={application.p_app_id}>
Expand All @@ -82,8 +89,9 @@ export function FertilizerApplicationsList({
variant="link"
className="p-0 mt-0"
disabled={
!editable ||
fetcher.state ===
"submitting"
"submitting"
}
onClick={handleEdit(
application,
Expand Down Expand Up @@ -117,7 +125,11 @@ export function FertilizerApplicationsList({
</p>
</ItemDescription>
</ItemContent>
<ItemActions>
<ItemActions
className={cn(
!editable ? "invisible" : "",
)}
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
Expand Down
28 changes: 15 additions & 13 deletions fdm-app/app/components/blocks/fertilizer/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SelectTrigger,
SelectValue,
} from "~/components/ui/select"
import { cn } from "~/lib/utils"

export interface FertilizerParameterDescriptionItem {
parameter: FertilizerParameters
Expand Down Expand Up @@ -258,19 +259,20 @@ export function FertilizerForm({
</Card>
))}
</div>
{editable && (
<div className="sticky bottom-0 left-0 right-0 border-t bg-background p-4">
<Button
type="submit"
className="w-full"
disabled={form.formState.isSubmitting}
>
{form.formState.isSubmitting
? "Meststof opslaan..."
: "Meststof opslaan"}
</Button>
</div>
)}
<div className="sticky bottom-0 left-0 right-0 border-t bg-background p-4">
<Button
type="submit"
className={cn(
"w-full",
!editable ? "invisible" : "",
)}
disabled={form.formState.isSubmitting}
>
{form.formState.isSubmitting
? "Meststof opslaan..."
: "Meststof opslaan"}
</Button>
</div>
</fieldset>
</Form>
</RemixFormProvider>
Expand Down
Loading