Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 8b6395a

Browse files
committed
Required Roles collapsable on Dynamic Entity CRUD
1 parent e6c3659 commit 8b6395a

1 file changed

Lines changed: 142 additions & 112 deletions

File tree

  • src/routes/(protected)/dynamic-entities/system/[id]/crud

‎src/routes/(protected)/dynamic-entities/system/[id]/crud/+page.svelte‎

Lines changed: 142 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@
7373
let requestSuccess = $state<Record<string, boolean>>({});
7474
let requestErrors = $state<Record<string, string>>({});
7575
76+
// Collapsible state for Required Roles section
77+
let rolesCollapsed = $state(true);
78+
7679
async function handleRequestEntitlement(roleName: string) {
7780
if (requestingRoles[roleName]) return;
7881
@@ -665,132 +668,159 @@
665668
<!-- Required Roles Section -->
666669
<div class="mb-6">
667670
<div
668-
class="rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800"
671+
class="rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
669672
>
670-
<h2 class="mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100">
671-
Required Roles for CRUD Operations
672-
</h2>
673-
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400">
674-
These roles are required to perform operations on {entityName} records:
675-
</p>
676-
<div class="space-y-3">
677-
{#each requiredRoles as roleReq}
678-
<div
679-
class="flex items-center justify-between rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900"
680-
>
681-
<div class="flex-1">
682-
<div class="flex items-center gap-2">
683-
<span
684-
class="text-sm font-semibold text-gray-900 dark:text-gray-100"
685-
>
686-
{roleReq.operation}
687-
</span>
688-
{#if userHasRole(roleReq.role)}
689-
<span
690-
class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300"
691-
>
692-
<svg
693-
class="h-3 w-3"
694-
fill="none"
695-
stroke="currentColor"
696-
viewBox="0 0 24 24"
697-
>
698-
<path
699-
stroke-linecap="round"
700-
stroke-linejoin="round"
701-
stroke-width="2"
702-
d="M5 13l4 4L19 7"
703-
/>
704-
</svg>
705-
You have this role
706-
</span>
707-
{/if}
708-
</div>
709-
<p class="mt-1 text-xs text-gray-600 dark:text-gray-400">
710-
{roleReq.description}
711-
</p>
712-
<p
713-
class="mt-1 font-mono text-xs text-gray-500 dark:text-gray-500"
673+
<button
674+
onclick={() => (rolesCollapsed = !rolesCollapsed)}
675+
class="flex w-full items-center justify-between p-6 text-left transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/50"
676+
>
677+
<div>
678+
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
679+
Required Roles for CRUD Operations
680+
</h2>
681+
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
682+
These roles are required to perform operations on {entityName} records
683+
</p>
684+
</div>
685+
<svg
686+
class="h-5 w-5 text-gray-500 transition-transform dark:text-gray-400"
687+
class:rotate-180={!rolesCollapsed}
688+
fill="none"
689+
stroke="currentColor"
690+
viewBox="0 0 24 24"
691+
>
692+
<path
693+
stroke-linecap="round"
694+
stroke-linejoin="round"
695+
stroke-width="2"
696+
d="M19 9l-7 7-7-7"
697+
/>
698+
</svg>
699+
</button>
700+
{#if !rolesCollapsed}
701+
<div class="border-t border-gray-200 p-6 dark:border-gray-700">
702+
<div class="space-y-3">
703+
{#each requiredRoles as roleReq}
704+
<div
705+
class="flex items-center justify-between rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900"
714706
>
715-
{roleReq.role}
716-
</p>
717-
</div>
718-
{#if !userHasRole(roleReq.role)}
719-
<div class="ml-4 flex flex-col items-end gap-1">
720-
{#if requestSuccess[roleReq.role]}
721-
<div
722-
class="flex items-center gap-1 rounded-lg bg-green-100 px-3 py-2 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300"
723-
>
724-
<svg
725-
class="h-3 w-3"
726-
fill="none"
727-
stroke="currentColor"
728-
viewBox="0 0 24 24"
707+
<div class="flex-1">
708+
<div class="flex items-center gap-2">
709+
<span
710+
class="text-sm font-semibold text-gray-900 dark:text-gray-100"
729711
>
730-
<path
731-
stroke-linecap="round"
732-
stroke-linejoin="round"
733-
stroke-width="2"
734-
d="M5 13l4 4L19 7"
735-
/>
736-
</svg>
737-
Request Submitted
712+
{roleReq.operation}
713+
</span>
714+
{#if userHasRole(roleReq.role)}
715+
<span
716+
class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300"
717+
>
718+
<svg
719+
class="h-3 w-3"
720+
fill="none"
721+
stroke="currentColor"
722+
viewBox="0 0 24 24"
723+
>
724+
<path
725+
stroke-linecap="round"
726+
stroke-linejoin="round"
727+
stroke-width="2"
728+
d="M5 13l4 4L19 7"
729+
/>
730+
</svg>
731+
You have this role
732+
</span>
733+
{/if}
738734
</div>
739-
{:else}
740-
<button
741-
onclick={() => handleRequestEntitlement(roleReq.role)}
742-
disabled={requestingRoles[roleReq.role]}
743-
class="inline-flex items-center gap-1 rounded-lg bg-blue-600 px-3 py-2 text-xs font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-blue-500 dark:hover:bg-blue-600"
735+
<p class="mt-1 text-xs text-gray-600 dark:text-gray-400">
736+
{roleReq.description}
737+
</p>
738+
<p
739+
class="mt-1 font-mono text-xs text-gray-500 dark:text-gray-500"
744740
>
745-
{#if requestingRoles[roleReq.role]}
746-
<svg
747-
class="h-3 w-3 animate-spin"
748-
fill="none"
749-
viewBox="0 0 24 24"
741+
{roleReq.role}
742+
</p>
743+
</div>
744+
{#if !userHasRole(roleReq.role)}
745+
<div class="ml-4 flex flex-col items-end gap-1">
746+
{#if requestSuccess[roleReq.role]}
747+
<div
748+
class="flex items-center gap-1 rounded-lg bg-green-100 px-3 py-2 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300"
750749
>
751-
<circle
752-
class="opacity-25"
753-
cx="12"
754-
cy="12"
755-
r="10"
750+
<svg
751+
class="h-3 w-3"
752+
fill="none"
756753
stroke="currentColor"
757-
stroke-width="4"
758-
/>
759-
<path
760-
class="opacity-75"
761-
fill="currentColor"
762-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
763-
/>
764-
</svg>
765-
Requesting...
754+
viewBox="0 0 24 24"
755+
>
756+
<path
757+
stroke-linecap="round"
758+
stroke-linejoin="round"
759+
stroke-width="2"
760+
d="M5 13l4 4L19 7"
761+
/>
762+
</svg>
763+
Request Submitted
764+
</div>
766765
{:else}
767-
<svg
768-
class="h-3 w-3"
769-
fill="none"
770-
stroke="currentColor"
771-
viewBox="0 0 24 24"
766+
<button
767+
onclick={() => handleRequestEntitlement(roleReq.role)}
768+
disabled={requestingRoles[roleReq.role]}
769+
class="inline-flex items-center gap-1 rounded-lg bg-blue-600 px-3 py-2 text-xs font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-blue-500 dark:hover:bg-blue-600"
772770
>
773-
<path
774-
stroke-linecap="round"
775-
stroke-linejoin="round"
776-
stroke-width="2"
777-
d="M12 4v16m8-8H4"
778-
/>
779-
</svg>
780-
Request Entitlement
771+
{#if requestingRoles[roleReq.role]}
772+
<svg
773+
class="h-3 w-3 animate-spin"
774+
fill="none"
775+
viewBox="0 0 24 24"
776+
>
777+
<circle
778+
class="opacity-25"
779+
cx="12"
780+
cy="12"
781+
r="10"
782+
stroke="currentColor"
783+
stroke-width="4"
784+
/>
785+
<path
786+
class="opacity-75"
787+
fill="currentColor"
788+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
789+
/>
790+
</svg>
791+
Requesting...
792+
{:else}
793+
<svg
794+
class="h-3 w-3"
795+
fill="none"
796+
stroke="currentColor"
797+
viewBox="0 0 24 24"
798+
>
799+
<path
800+
stroke-linecap="round"
801+
stroke-linejoin="round"
802+
stroke-width="2"
803+
d="M12 4v16m8-8H4"
804+
/>
805+
</svg>
806+
Request Entitlement
807+
{/if}
808+
</button>
809+
{/if}
810+
{#if requestErrors[roleReq.role]}
811+
<div
812+
class="max-w-xs text-xs text-red-600 dark:text-red-400"
813+
>
814+
{requestErrors[roleReq.role]}
815+
</div>
781816
{/if}
782-
</button>
783-
{/if}
784-
{#if requestErrors[roleReq.role]}
785-
<div class="max-w-xs text-xs text-red-600 dark:text-red-400">
786-
{requestErrors[roleReq.role]}
787817
</div>
788818
{/if}
789819
</div>
790-
{/if}
820+
{/each}
791821
</div>
792-
{/each}
793-
</div>
822+
</div>
823+
{/if}
794824
</div>
795825
</div>
796826

0 commit comments

Comments
 (0)