Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions apps/api/internal/domain/service/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ type Handler struct {
serviceService ServiceInterface
}

// NewHandler creates a Handler configured with the provided ServiceInterface.
// NewHandler creates a new Handler using the provided ServiceInterface.
func NewHandler(s ServiceInterface) *Handler {
return &Handler{serviceService: s}
}

// validateServiceID validates the service ID parameter from the request.
// It checks if the ID is present and has a valid UUID format.
// Returns the validated ID or an error response.
// validateServiceID validates the "id" route parameter and returns it.
// If the parameter is missing or not a valid UUID, it sends a 400 validation error response and returns a non-nil error.
func validateServiceID(c *fiber.Ctx) (string, error) {
id := c.Params("id")
if id == "" {
Expand Down Expand Up @@ -201,4 +202,4 @@ func (h *Handler) DeleteService(c *fiber.Ctx) error {
}

return utils.SuccessResponse(c, nil, "Service deleted successfully")
}
}
9 changes: 8 additions & 1 deletion apps/web/src/app/auth/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ import LocalStorageTokenService from "@/authly/lib/services/TokenService";

type LoginFormData = z.infer<typeof githubComAnvoriaAuthlyInternalDomainUserLoginRequestSchema>;

/**
* Renders the login form UI and handles user authentication plus optional OpenID Connect (OIDC) redirect flow.
*
* The component validates credentials, calls the login mutation, displays API and field errors, and upon successful login initiates an OIDC authorization redirect (including PKCE code verifier generation when needed). It also provides a link to the registration page that preserves OIDC parameters when present.
*
* @returns The JSX element for the sign-in page content
*/
function LoginPageContent() {
const searchParams = useSearchParams();
const router = useRouter();
Expand Down Expand Up @@ -172,4 +179,4 @@ export default function LoginPage() {
<LoginPageContent />
</Suspense>
);
}
}
11 changes: 10 additions & 1 deletion apps/web/src/app/authorize/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ type AuthPageState =
| { type: "consent"; client: { name: string; logo_url?: string; client_id: string }; scopes: string[] }
| { type: "redirecting" };

/**
* Render the OIDC authorization page UI and manage the authorization flow lifecycle.
*
* This component validates the incoming OIDC request, checks the IdP session, redirects to login when required,
* presents an error view for invalid requests or clients, shows a consent screen for user approval, and performs
* the confirm/deny actions that ultimately redirect back to the client application.
*
* @returns The component's UI: a loading layout during validation/redirecting or auto-approval, an error view when validation fails, a consent screen when user approval is required, or `null` if no view applies.
*/
function AuthorizePageContent() {
const searchParams = useSearchParams();
const router = useRouter();
Expand Down Expand Up @@ -260,4 +269,4 @@ export default function AuthorizePage() {
<AuthorizePageContent />
</Suspense>
);
}
}
8 changes: 7 additions & 1 deletion apps/web/src/app/dashboard/admin/services/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ interface ServicePageProps {
params: Promise<{ id: string }>;
}

/**
* Renders the admin service detail page for the service identified by the route `id`.
*
* @param params - Promise resolving to an object with the route `id` string used to load the service
* @returns The React element for the service details view, including loading and error states and tabbed content
*/
export default function ServicePage({ params }: ServicePageProps) {
const { id } = use(params);
const { data: response, isLoading, isError } = useAdminService(id);
Expand Down Expand Up @@ -113,4 +119,4 @@ export default function ServicePage({ params }: ServicePageProps) {
</Tabs>
</div>
);
}
}
4 changes: 2 additions & 2 deletions apps/web/src/app/dashboard/admin/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const PAGE_SIZE = 50;
/**
* Render the admin Users management page with a searchable, paginated list of users.
*
* The component maintains local search and page state, debounces the search input, resets to page 1 when the debounced search changes, and fetches users with page-size pagination. The UI adapts to loading, error, empty, and populated states and provides controls for searching, clearing the search, retrying failed loads, and changing pages.
* The component maintains local `search` and `page` state, applies a debounced search input for data fetching, and displays appropriate UI for loading, error, empty, and populated states. It provides controls for searching, clearing the search, retrying failed loads, and changing pages.
*
* @returns The Users management page UI as a JSX element
*/
Expand Down Expand Up @@ -99,4 +99,4 @@ export default function UsersPage() {
</div>
</div>
);
}
}
6 changes: 3 additions & 3 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export const viewport: Viewport = {
};

/**
* Provide the application's root HTML structure, apply global font variables, and wrap page content with the QueryProvider.
* Render the application's root HTML structure, apply global font variables, and wrap page content with QueryProvider and AuthProvider.
*
* @param children - The application content to render inside the layout.
* @returns The `<html>` element (lang="en") containing a `<body>` whose children are wrapped by the QueryProvider.
* @returns The `<html>` element (lang="en") whose `<body>` applies the global font variables and contains `children` wrapped by `QueryProvider` and `AuthProvider`; includes a top-right `Toaster`.
*/
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
Expand All @@ -57,4 +57,4 @@ export default function RootLayout({ children }: { children: React.ReactNode })
</body>
</html>
);
}
}
7 changes: 6 additions & 1 deletion apps/web/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import Footer from "@/authly/components/landing/Footer";
import Hero from "@/authly/components/landing/Hero";
import Navbar from "@/authly/components/landing/Navbar";

/**
* Top-level home page component that composes the landing page layout.
*
* @returns The page's root JSX element containing Navbar, Hero, Features, CodeExamples, and Footer arranged vertically within a main container.
*/
export default function Home() {
return (
<main className="flex min-h-screen flex-col bg-black text-white font-display">
Expand All @@ -18,4 +23,4 @@ export default function Home() {
<Footer />
</main>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ interface OverviewTabProps {
serviceId: string;
}

/**
* Renders the overview tab for an admin service: loads service data, handles loading and error states, and presents an editable ServiceForm.
*
* Shows an error toast when the service fails to load.
*
* @param serviceId - The ID of the service to load and edit.
* @returns The OverviewTab React element.
*/
export function OverviewTab({ serviceId }: OverviewTabProps) {
const { data: response, isLoading, isError } = useAdminService(serviceId);
const { mutate: updateService, isPending: isUpdating } = useUpdateService();
Expand Down Expand Up @@ -38,4 +46,4 @@ export function OverviewTab({ serviceId }: OverviewTabProps) {
isUpdating={isUpdating}
/>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ interface AuthenticationSectionProps {
disabled?: boolean;
}

/**
* Render the Authentication section of the client settings UI, showing and managing redirect URIs and allowed scopes.
*
* Renders an animated list of `redirectURIs` with optional remove buttons, an input and Add control for new redirect URIs (Enter key triggers add), and a TagInput for `allowedScopes`.
*
* @param redirectURIs - List of redirect URIs to display
* @param allowedScopes - Current allowed OAuth scopes
* @param newRedirectURI - Current value of the new redirect URI input
* @param onAllowedScopesChange - Called with the updated scopes when the TagInput changes
* @param onNewRedirectURIChange - Called with the input value when the new redirect URI changes
* @param onAddRedirect - Called to add the value from `newRedirectURI` to the list
* @param onRemoveRedirect - Called with the index of a redirect URI to remove
* @param disabled - When true, disables inputs and hides remove controls (default: false)
* @returns The React element for the Authentication section
*/
export function AuthenticationSection({
redirectURIs,
allowedScopes,
Expand Down Expand Up @@ -108,4 +123,4 @@ export function AuthenticationSection({
</div>
</section>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ interface BasicDetailsSectionProps {
disabled?: boolean;
}

/**
* Render the Basic Details form section for editing a service's name, description, and primary domain.
*
* @param name - The current service name displayed in the Service Name input.
* @param description - The current service description displayed in the Description input.
* @param domain - The current primary domain displayed in the Primary Domain input.
* @param onNameChange - Callback invoked with the updated name when the Service Name input changes.
* @param onDescriptionChange - Callback invoked with the updated description when the Description input changes.
* @param onDomainChange - Callback invoked with the updated domain when the Primary Domain input changes.
* @param disabled - When `true`, disables all inputs (defaults to `false`).
* @returns A React element containing the titled section with three labeled inputs and associated hints/icons.
*/
export function BasicDetailsSection({
name,
description,
Expand Down Expand Up @@ -61,4 +73,4 @@ export function BasicDetailsSection({
</div>
</section>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ interface CredentialsCardProps {
clientSecret: string | null;
}

/**
* Render a credentials card showing the client ID and client secret with optional copy controls.
*
* The client ID is shown in plain text with a copy button. The client secret, when provided, is displayed masked and includes a copy button; when `null`, the card indicates the client is public.
*
* @param clientId - The client identifier to display and copy
* @param clientSecret - The client secret to display (masked) and copy, or `null` to indicate a public client
* @returns The JSX element representing the credentials card
*/
export function CredentialsCard({ clientId, clientSecret }: CredentialsCardProps) {
return (
<div className="p-5 rounded-xl bg-white/5 border border-white/10 space-y-4">
Expand Down Expand Up @@ -45,4 +54,4 @@ export function CredentialsCard({ clientId, clientSecret }: CredentialsCardProps
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ interface MetadataCardProps {
serviceId: string;
}

/**
* Render a compact metadata panel showing creation time, last update, and the service identifier with a copy control.
*
* Created and updated timestamps are parsed with the `Date` constructor and displayed using the runtime locale.
*
* @param createdAt - Timestamp string for when the resource was created; displayed as a localized date/time string
* @param updatedAt - Timestamp string for the last update; displayed as a localized date/time string
* @param serviceId - Service identifier shown in a truncated field with a button to copy the value
* @returns A React element that renders the metadata card UI
*/
export function MetadataCard({ createdAt, updatedAt, serviceId }: MetadataCardProps) {
return (
<div className="p-5 rounded-xl bg-white/5 border border-white/10 space-y-4">
Expand Down Expand Up @@ -37,4 +47,4 @@ export function MetadataCard({ createdAt, updatedAt, serviceId }: MetadataCardPr
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ interface SaveActionsProps {
disabled?: boolean;
}

/**
* Render an action bar that displays an unsaved changes indicator and a save button.
*
* @param hasChanges - Whether there are unsaved changes to save
* @param isSaving - Whether a save operation is currently in progress
* @param onSave - Handler invoked when the save button is clicked (receives the form event)
* @param disabled - If true, disables the save button regardless of change or saving state
* @returns A JSX element containing the save actions bar
*/
export function SaveActions({ hasChanges, isSaving, onSave, disabled = false }: SaveActionsProps) {
return (
<div className="pt-6 flex items-center justify-between border-t border-white/10">
Expand Down Expand Up @@ -40,4 +49,4 @@ export function SaveActions({ hasChanges, isSaving, onSave, disabled = false }:
</Button>
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ interface ServiceFormProps {
isUpdating: boolean;
}

/**
* Renders a form for viewing and editing a service's details in the admin UI.
*
* The form initializes fields from `service`, allows adding/removing redirect URIs (with URL format and duplicate validation),
* and submits changes via the provided `updateService` mutation. It disables editing and prevents updates for the default Authly service
* and surfaces success and API error messages via toasts.
*
* @param service - The service object providing initial field values and metadata.
* @param serviceId - The identifier used when submitting updates for the service.
* @param updateService - Mutation function used to persist changes to the service.
* @param isUpdating - Whether an update request is in progress; disables save actions while true.
*
* @returns The React element for the service edit form.
*/
export function ServiceForm({ service, serviceId, updateService, isUpdating }: ServiceFormProps) {
const isDefaultService = isDefaultAuthlyService(service.id) || isDefaultAuthlyService(service.client_id);

Expand Down Expand Up @@ -179,4 +193,4 @@ export function ServiceForm({ service, serviceId, updateService, isUpdating }: S
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ interface StatusCardProps {
disabled?: boolean;
}

/**
* Renders a status card with a label and a toggle switch for activating or deactivating a service.
*
* @param isActive - Whether the service is currently active
* @param onToggle - Callback invoked when the switch is toggled
* @param disabled - If true, disables user interaction with the switch
* @returns The rendered React element for the status card
*/
export function StatusCard({ isActive, onToggle, disabled = false }: StatusCardProps) {
return (
<div className="p-5 rounded-xl bg-white/5 border border-white/10 space-y-4">
Expand All @@ -27,4 +35,4 @@ export function StatusCard({ isActive, onToggle, disabled = false }: StatusCardP
</div>
</div>
);
}
}
15 changes: 7 additions & 8 deletions apps/web/src/components/dashboard/admin/users/EditUserModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ interface EditUserModalProps {
}

/**
* Renders a modal containing a form to edit a user's username, email, and active status.
* Render a modal form for editing a user's username, email, and active status.
*
* Validates input with the updateUserRequestSchema, displays field-level validation messages
* and server update errors, and submits changes via the useUpdateUser hook. Calls `onClose`
* when the update succeeds or when the Cancel button is clicked.
* Validates input, displays field-level and global update errors, submits changes,
* and closes the modal on successful update or when the Cancel button is clicked.
*
* @param user - The user object to edit (pre-fills the form).
* @param onClose - Callback invoked to close the modal.
* @returns The modal content element for editing the user.
* @param user - The user to edit; used to pre-fill form fields
* @param onClose - Callback invoked to close the modal
* @returns The modal content element for editing the user
*/
export function EditUserModalContent({ user, onClose }: EditUserModalProps) {
const { mutate: updateUser, isPending, error: updateError } = useUpdateUser();
Expand Down Expand Up @@ -129,4 +128,4 @@ export function EditUserModalContent({ user, onClose }: EditUserModalProps) {
</ModalFooter>
</ModalContent>
);
}
}
11 changes: 10 additions & 1 deletion apps/web/src/components/ui/CopyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ interface CopyButtonProps {
className?: string;
}

/**
* Renders a button that copies a provided string to the clipboard and shows a success toast.
*
* @param value - The string to copy to the clipboard when the button is activated.
* @param ariaLabel - Accessible label used for the button and the success message.
* @param onCopy - Optional callback invoked after a successful copy.
* @param className - Optional CSS class(es) applied to the button element.
* @returns A button element that copies `value` when activated and updates its icon and aria-label to reflect the copied state.
*/
export function CopyButton({ value, ariaLabel, onCopy, className }: CopyButtonProps) {
const [copied, copy] = useCopyToClipboard();

Expand All @@ -35,4 +44,4 @@ export function CopyButton({ value, ariaLabel, onCopy, className }: CopyButtonPr
/>
</button>
);
}
}
Loading