Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
* The secret associated with the agent.
*/
agentSecret?: string;
/**
* The client ID of the application created alongside the agent.
*/
applicationClientId?: string;
/**
* Whether this is a user-serving agent (has an associated OAuth application).
*/
isUserServingAgent?: boolean;
/**
* Whether the application client ID is currently being fetched.
*/
isFetchingClientId?: boolean;
/**
* Flag indicating whether the modal is open.
*/
Expand All @@ -64,6 +76,9 @@
title,
agentId,
agentSecret,
applicationClientId,
isUserServingAgent,
isFetchingClientId,
isOpen,
onClose,
isForSecretRegeneration,
Expand Down Expand Up @@ -171,6 +186,20 @@
data-componentid={ "agent-secret-readonly-input" }
/>
</div>
{ !isForSecretRegeneration && isUserServingAgent && (
<>
<div style={ { marginTop: "2%" } }></div>
<label>OAuth Client ID</label>
<div style={ { marginTop: "1%" } }>
{/* Show loading state while fetching the client ID from the backend */}

Check warning on line 194 in features/admin.agents.v1/components/edit/agent-secret-show-modal.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

A space is required before '}'

Check warning on line 194 in features/admin.agents.v1/components/edit/agent-secret-show-modal.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

A space is required after '{'
<CopyInputField
className="agent-application-client-id-input"
value={ isFetchingClientId ? "Loading..." : (applicationClientId || "") }
data-componentid="agent-application-client-id-readonly-input"
/>
</div>
</>
) }
</>)
}
</Modal.Content>
Expand Down
250 changes: 165 additions & 85 deletions features/admin.agents.v1/components/wizards/add-agent-wizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import { AppState } from "@wso2is/admin.core.v1/store";
import { AlertLevels, IdentifiableComponentInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import { FinalForm, FinalFormField, FormRenderProps, TextFieldAdapter } from "@wso2is/form/src";
import { FinalForm, FinalFormField, FormRenderProps, TextFieldAdapter, CheckboxFieldAdapter } from "@wso2is/form/src";

Check warning on line 23 in features/admin.agents.v1/components/wizards/add-agent-wizard.tsx

View workflow job for this annotation

GitHub Actions / ⬣ ESLint (STATIC ANALYSIS) (lts/*, 8.7.4)

Member 'CheckboxFieldAdapter' of the import declaration should be sorted alphabetically
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if importing from `@wso2is/form/src` is a pattern used elsewhere
rg "from ['\"]@wso2is/form" --type ts --type tsx -A 0 | head -50

Repository: wso2/identity-apps

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Search for `@wso2is/form` imports without file type restrictions
rg "@wso2is/form" --glob "*.ts" --glob "*.tsx" -A 0 | head -100

Repository: wso2/identity-apps

Length of output: 13171


🏁 Script executed:

#!/bin/bash
# Check the exact file mentioned in the review comment
head -30 features/admin.agents.v1/components/wizards/add-agent-wizard.tsx | grep -n "import"

Repository: wso2/identity-apps

Length of output: 752


Change import path from @wso2is/form/src to @wso2is/form.

Importing from /src bypasses the package's public exports and can cause issues in production builds. Use the public entry point instead.

- import { FinalForm, FinalFormField, FormRenderProps, TextFieldAdapter, CheckboxFieldAdapter } from "@wso2is/form/src";
+ import { FinalForm, FinalFormField, FormRenderProps, TextFieldAdapter, CheckboxFieldAdapter } from "@wso2is/form";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/admin.agents.v1/components/wizards/add-agent-wizard.tsx` at line 23,
The import currently pulls FinalForm, FinalFormField, FormRenderProps,
TextFieldAdapter, and CheckboxFieldAdapter from the package's internal path
"@wso2is/form/src"; change the import to use the package's public entry
"@wso2is/form" so the components use the official public exports and avoid
production build issues—update the import statement that references FinalForm,
FinalFormField, FormRenderProps, TextFieldAdapter, CheckboxFieldAdapter
accordingly.

import { Button } from "@wso2is/react-components";
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
Expand All @@ -42,6 +42,68 @@

const authenticatedUserInfo: AuthenticatedUserInfo = useSelector((state: AppState) => state?.auth);
const [ isNewAgentFormSubmitting, setIsNewAgentFormSubmitting ] = useState<boolean>(false);
const [ currentStep, setCurrentStep ] = useState<number>(0);
const [ stepOneValues, setStepOneValues ] = useState<{ name?: string; description?: string }>({});
const [ stepOneErrors, setStepOneErrors ] = useState<{ name?: string }>({});

const handleClose = () => {
setCurrentStep(0);
setStepOneValues({});
setStepOneErrors({});
onClose(null);
};

const handleNext = (values: any) => {
if (!values?.name) {
setStepOneErrors({ name: "Agent name is required." });

return;
}

setStepOneErrors({});
setStepOneValues({ description: values?.description, name: values?.name });
setCurrentStep(1);
};

const handleBack = () => {
setCurrentStep(0);
};

const handleCreate = (values: any) => {
setIsNewAgentFormSubmitting(true);

// Capture the checkbox value here — the backend response does NOT return
// IsUserServingAgent, so we must carry this value forward ourselves.
const isUserServing: boolean = values?.isUserServingAgent || false;

const addAgentPayload: AgentScimSchema = {
"urn:scim:wso2:agent:schema": {
Description: stepOneValues?.description,
DisplayName: stepOneValues?.name,
IsUserServingAgent: isUserServing,
Owner: authenticatedUserInfo?.username
}
};

addAgent(addAgentPayload)
.then((response: AgentScimSchema) => {
// Attach isUserServingAgent to the response so the parent (agents.tsx)
// knows which value the user selected, without relying on the backend
// to echo it back.
onClose({ ...response, isUserServingAgent: isUserServing });
})
.catch((_err: unknown) => {
dispatch(
addAlert({
description: "Creating agent failed",
level: AlertLevels.ERROR,
message: "Something went wrong"
})
);
}).finally(() => {
setIsNewAgentFormSubmitting(false);
});
};

return (
<Modal
Expand All @@ -51,97 +113,115 @@
className="wizard"
dimmer="blurring"
size="tiny"
onClose={ onClose }
onClose={ handleClose }
closeOnDimmerClick={ false }
closeOnEscape
>
<Modal.Header>New Agent</Modal.Header>
<Modal.Content>
<FinalForm
onSubmit={ (values: any) => {
if (!values?.name) {
return;
}

setIsNewAgentFormSubmitting(true);

const addAgentPayload: AgentScimSchema = {
"urn:scim:wso2:agent:schema": {
Description: values?.description,
DisplayName: values?.name,
Owner: authenticatedUserInfo?.username
}
};

addAgent(addAgentPayload)
.then((response: AgentScimSchema) => {
onClose(response);
})
.catch((_err: unknown) => {
dispatch(
addAlert({
description: "Creating agent failed",
level: AlertLevels.ERROR,
message: "Something went wrong"
})

{ currentStep === 0 && (
<>
<Modal.Content>
<FinalForm
onSubmit={ handleNext }
initialValues={ stepOneValues }
render={ ({ handleSubmit }: FormRenderProps) => {
return (
<form id="addAgentStepOneForm" onSubmit={ handleSubmit }>
<FinalFormField
name="name"
label="Name"
required={ true }
autoComplete="new-password"
component={ TextFieldAdapter }
error={ stepOneErrors?.name }
/>
<FinalFormField
label="Description"
name="description"
className="mt-3"
multiline
rows={ 4 }
maxRows={ 4 }
autoComplete="new-password"
placeholder="Enter a description for the agent"
component={ TextFieldAdapter }
/>
</form>
);
}).finally(() => {
setIsNewAgentFormSubmitting(false);
});
} }
render={ ({ handleSubmit }: FormRenderProps) => {
return (
<form id="addAgentForm" onSubmit={ handleSubmit }>
<FinalFormField
name="name"
label="Name"
required={ true }
autoComplete="new-password"
component={ TextFieldAdapter }
/>
<FinalFormField
label="Description"
name="description"
className="mt-3"
multiline
rows={ 4 }
maxRows={ 4 }
autoComplete="new-password"
placeholder="Enter a description for the agent"
component={ TextFieldAdapter }
/>
</form>
);
} }
/>

</Modal.Content>

<Modal.Actions>
<Button
className="link-button"
basic
primary
onClick={ () => onClose(null) }
data-testid={ `${componentId}-confirmation-modal-actions-cancel-button` }
>
} }
/>
</Modal.Content>
<Modal.Actions>
<Button
className="link-button"
basic
primary
onClick={ handleClose }
data-testid={ `${componentId}-step-one-cancel-button` }
>
Cancel
</Button>
<Button
primary={ true }
type="submit"
disabled={ isNewAgentFormSubmitting }
loading={ isNewAgentFormSubmitting }
onClick={ () => {
document
.getElementById("addAgentForm")
.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
} }
data-testid={ `${componentId}-confirmation-modal-actions-continue-button` }
>
</Button>
<Button
primary={ true }
onClick={ () => {
document
.getElementById("addAgentStepOneForm")
.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
} }
data-testid={ `${componentId}-step-one-next-button` }
>
Next
</Button>
</Modal.Actions>
</>
) }

{ currentStep === 1 && (
<>
<Modal.Content>
<FinalForm
onSubmit={ handleCreate }
render={ ({ handleSubmit }: FormRenderProps) => {
return (
<form id="addAgentStepTwoForm" onSubmit={ handleSubmit }>
<FinalFormField
name="isUserServingAgent"
label="Is this a user-serving agent?"
component={ CheckboxFieldAdapter }
/>
</form>
);
} }
/>
</Modal.Content>
<Modal.Actions>
<Button
className="link-button"
basic
primary
onClick={ handleBack }
data-testid={ `${componentId}-step-two-back-button` }
>
Back
</Button>
<Button
primary={ true }
type="submit"
disabled={ isNewAgentFormSubmitting }
loading={ isNewAgentFormSubmitting }
onClick={ () => {
document
.getElementById("addAgentStepTwoForm")
.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
} }
data-testid={ `${componentId}-step-two-create-button` }
>
Create
</Button>
</Modal.Actions>
</Button>
</Modal.Actions>
</>
) }
</Modal>
);
}
2 changes: 2 additions & 0 deletions features/admin.agents.v1/models/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ export interface AgentSchema {
Url?: string;
Description?: string;
DisplayName?: string;
IsUserServingAgent?: boolean;
[key: string]: any;
}

export interface AgentScimSchema {
id?: string;
userName?: string;
password?: string;
applicationClientId?: string;
"urn:scim:wso2:agent:schema"?: AgentSchema;
}
Loading
Loading