|
73 | 73 | let requestSuccess = $state<Record<string, boolean>>({}); |
74 | 74 | let requestErrors = $state<Record<string, string>>({}); |
75 | 75 |
|
| 76 | + // Collapsible state for Required Roles section |
| 77 | + let rolesCollapsed = $state(true); |
| 78 | +
|
76 | 79 | async function handleRequestEntitlement(roleName: string) { |
77 | 80 | if (requestingRoles[roleName]) return; |
78 | 81 |
|
|
665 | 668 | <!-- Required Roles Section --> |
666 | 669 | <div class="mb-6"> |
667 | 670 | <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" |
669 | 672 | > |
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" |
714 | 706 | > |
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" |
729 | 711 | > |
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} |
738 | 734 | </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" |
744 | 740 | > |
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" |
750 | 749 | > |
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" |
756 | 753 | 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> |
766 | 765 | {: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" |
772 | 770 | > |
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> |
781 | 816 | {/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]} |
787 | 817 | </div> |
788 | 818 | {/if} |
789 | 819 | </div> |
790 | | - {/if} |
| 820 | + {/each} |
791 | 821 | </div> |
792 | | - {/each} |
793 | | - </div> |
| 822 | + </div> |
| 823 | + {/if} |
794 | 824 | </div> |
795 | 825 | </div> |
796 | 826 |
|
|
0 commit comments