162 lines
8.7 KiB
Plaintext
162 lines
8.7 KiB
Plaintext
<%= form_with(model: [:admin, application], class: "space-y-6") do |form| %>
|
|
<% if application.errors.any? %>
|
|
<div class="rounded-md bg-red-50 p-4">
|
|
<div class="flex">
|
|
<div class="ml-3">
|
|
<h3 class="text-sm font-medium text-red-800">
|
|
<%= pluralize(application.errors.count, "error") %> prohibited this application from being saved:
|
|
</h3>
|
|
<div class="mt-2 text-sm text-red-700">
|
|
<ul class="list-disc pl-5 space-y-1">
|
|
<% application.errors.full_messages.each do |message| %>
|
|
<li><%= message %></li>
|
|
<% end %>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div>
|
|
<%= form.label :name, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_field :name, required: true, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "My Application" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= form.label :slug, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_field :slug, required: true, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm font-mono", placeholder: "my-app" %>
|
|
<p class="mt-1 text-sm text-gray-500">Lowercase letters, numbers, and hyphens only. Used in URLs and API calls.</p>
|
|
</div>
|
|
|
|
<div>
|
|
<%= form.label :description, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_area :description, rows: 3, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "Optional description of this application" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= form.label :app_type, "Application Type", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.select :app_type, [["OpenID Connect (OIDC)", "oidc"], ["SAML (Coming Soon)", "saml", { disabled: true }]], {}, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", disabled: application.persisted? %>
|
|
<% if application.persisted? %>
|
|
<p class="mt-1 text-sm text-gray-500">Application type cannot be changed after creation.</p>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- OIDC-specific fields -->
|
|
<div id="oidc-fields" class="space-y-6 border-t border-gray-200 pt-6" style="<%= 'display: none;' unless application.oidc? || !application.persisted? %>">
|
|
<h3 class="text-base font-semibold text-gray-900">OIDC Configuration</h3>
|
|
|
|
<div>
|
|
<%= form.label :redirect_uris, "Redirect URIs", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_area :redirect_uris, rows: 4, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm font-mono", placeholder: "https://example.com/callback\nhttps://app.example.com/auth/callback" %>
|
|
<p class="mt-1 text-sm text-gray-500">One URI per line. These are the allowed callback URLs for your application.</p>
|
|
</div>
|
|
|
|
<!-- Role Mapping Configuration -->
|
|
<div class="border-t border-gray-200 pt-6">
|
|
<h4 class="text-base font-semibold text-gray-900 mb-4">Role Mapping Configuration</h4>
|
|
|
|
<div>
|
|
<%= form.label :role_mapping_mode, "Role Mapping Mode", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.select :role_mapping_mode,
|
|
options_for_select([
|
|
["Disabled", "disabled"],
|
|
["OIDC Managed", "oidc_managed"],
|
|
["Hybrid (Groups + Roles)", "hybrid"]
|
|
], application.role_mapping_mode || "disabled"),
|
|
{},
|
|
{ class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" } %>
|
|
<p class="mt-1 text-sm text-gray-500">Controls how external roles are mapped and synchronized.</p>
|
|
</div>
|
|
|
|
<div id="role-mapping-advanced" class="mt-4 space-y-4 border-t border-gray-200 pt-4" style="<%= 'display: none;' unless application.role_mapping_enabled? %>">
|
|
<div>
|
|
<%= form.label :role_claim_name, "Role Claim Name", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_field :role_claim_name, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "roles" %>
|
|
<p class="mt-1 text-sm text-gray-500">Name of the claim that contains role information (default: 'roles').</p>
|
|
</div>
|
|
|
|
<div>
|
|
<%= form.label :role_prefix, "Role Prefix (Optional)", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= form.text_field :role_prefix, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm", placeholder: "app-" %>
|
|
<p class="mt-1 text-sm text-gray-500">Only roles starting with this prefix will be mapped. Useful for multi-tenant scenarios.</p>
|
|
</div>
|
|
|
|
<div class="space-y-3">
|
|
<label class="block text-sm font-medium text-gray-700">Managed Permissions</label>
|
|
|
|
<div class="flex items-center">
|
|
<%= form.check_box :managed_permissions, { multiple: true, class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" }, "include_permissions", "" %>
|
|
<%= form.label :managed_permissions_include_permissions, "Include role permissions in tokens", class: "ml-2 block text-sm text-gray-900" %>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<%= form.check_box :managed_permissions, { multiple: true, class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" }, "include_metadata", "" %>
|
|
<%= form.label :managed_permissions_include_metadata, "Include role metadata in tokens", class: "ml-2 block text-sm text-gray-900" %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<%= form.label :group_ids, "Allowed Groups (Optional)", class: "block text-sm font-medium text-gray-700" %>
|
|
<div class="mt-2 space-y-2 max-h-48 overflow-y-auto border border-gray-200 rounded-md p-3">
|
|
<% if @available_groups.any? %>
|
|
<% @available_groups.each do |group| %>
|
|
<div class="flex items-center">
|
|
<%= check_box_tag "application[group_ids][]", group.id, application.allowed_groups.include?(group), class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" %>
|
|
<%= label_tag "application_group_ids_#{group.id}", group.name, class: "ml-2 text-sm text-gray-900" %>
|
|
<span class="ml-2 text-xs text-gray-500">(<%= pluralize(group.users.count, "member") %>)</span>
|
|
</div>
|
|
<% end %>
|
|
<% else %>
|
|
<p class="text-sm text-gray-500">No groups available. Create groups first to restrict access.</p>
|
|
<% end %>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500">If no groups are selected, all active users can access this application.</p>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<%= form.check_box :active, class: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" %>
|
|
<%= form.label :active, "Active", class: "ml-2 block text-sm text-gray-900" %>
|
|
</div>
|
|
|
|
<div class="flex gap-3">
|
|
<%= form.submit application.persisted? ? "Update Application" : "Create Application", class: "rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" %>
|
|
<%= link_to "Cancel", admin_applications_path, class: "rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" %>
|
|
</div>
|
|
<% end %>
|
|
|
|
<script>
|
|
// Show/hide OIDC fields based on app type selection
|
|
const appTypeSelect = document.querySelector('#application_app_type');
|
|
const oidcFields = document.querySelector('#oidc-fields');
|
|
const roleMappingMode = document.querySelector('#application_role_mapping_mode');
|
|
const roleMappingAdvanced = document.querySelector('#role-mapping-advanced');
|
|
|
|
function updateFieldVisibility() {
|
|
const isOidc = appTypeSelect.value === 'oidc';
|
|
const roleMappingEnabled = roleMappingMode && ['oidc_managed', 'hybrid'].includes(roleMappingMode.value);
|
|
|
|
if (oidcFields) {
|
|
oidcFields.style.display = isOidc ? 'block' : 'none';
|
|
}
|
|
|
|
if (roleMappingAdvanced) {
|
|
roleMappingAdvanced.style.display = isOidc && roleMappingEnabled ? 'block' : 'none';
|
|
}
|
|
}
|
|
|
|
if (appTypeSelect && oidcFields) {
|
|
appTypeSelect.addEventListener('change', updateFieldVisibility);
|
|
}
|
|
|
|
if (roleMappingMode) {
|
|
roleMappingMode.addEventListener('change', updateFieldVisibility);
|
|
}
|
|
|
|
// Initialize visibility on page load
|
|
updateFieldVisibility();
|
|
</script>
|