Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update rules feature with readonly support and missing resource alert messaging #7454

Merged
merged 20 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
269371a
Improve rule component with readonly support + reource missing check …
jeradrutnam Jan 30, 2025
75a5ede
Remove duplicate use-get-resource api hook
jeradrutnam Jan 30, 2025
2dd73d5
Merge branch 'master' of https://github.com/wso2/identity-apps into r…
jeradrutnam Jan 30, 2025
3205746
Add apiRoot to store.reducer.endpoints
jeradrutnam Jan 30, 2025
5f74a67
🦋 Add changeset
jeradrutnam Jan 30, 2025
cb261d6
Fix alert message not showing properly issue in rules component
jeradrutnam Jan 30, 2025
2c43412
Fix use-get-resource-list module import in rule component
jeradrutnam Jan 30, 2025
93c635f
Update resource not found messaging in rule component
jeradrutnam Jan 30, 2025
28f4754
Fix deleted resource detail caching issue in rules component
jeradrutnam Jan 31, 2025
33a0fd0
Add missing data-componentid rule conditions component
jeradrutnam Jan 31, 2025
8f997df
Add some missing doc comments in rules component utils
jeradrutnam Jan 31, 2025
f2a355b
Fix some type declarions in rules conditions component
jeradrutnam Jan 31, 2025
67013b5
Add null check for findMetaValuesAgainst in rules condition component
jeradrutnam Jan 31, 2025
aa40b36
Fix alert flicker issue on saving in rule component
jeradrutnam Jan 31, 2025
27c67a6
Fix wrong module version bump in changeset
jeradrutnam Jan 31, 2025
45d4d42
Address some comments in pre-issue-access-token component
jeradrutnam Jan 31, 2025
319b75f
Change useGetResourceListOrResourceDetails hook file namein rules com…
jeradrutnam Jan 31, 2025
f09ee88
Delete use-get-resource-list file in rules component
jeradrutnam Jan 31, 2025
e0fb4e7
Fix an issue in rules component
jeradrutnam Jan 31, 2025
35dddfb
Improve readonly view in rules component
jeradrutnam Jan 31, 2025
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
8 changes: 8 additions & 0 deletions .changeset/smart-grapes-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@wso2is/admin.rules.v1": minor
"@wso2is/admin.core.v1": minor
"@wso2is/i18n": minor
"@wso2is/admin.actions.v1": patch
---

Add readonly view and missing resource alert support to the rules component
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ const PreIssueAccessTokenActionConfigForm: FunctionComponent<PreIssueAccessToken

const {
data: actionData,
mutate: mutateAction
isLoading: isActionLoading,
mutate: mutateAction,
error: actionError
} = useGetActionById(actionTypeApiPath, initialValues?.id);

const {
Expand Down Expand Up @@ -270,6 +272,7 @@ const PreIssueAccessTokenActionConfigForm: FunctionComponent<PreIssueAccessToken
} }/>
{ (RuleExpressionsMetaData && showRuleComponent) && (
<RuleConfigForm
readonly={ getFieldDisabledStatus() }
rule={ rule }
setRule={ setRule }
isHasRule={ isHasRule }
Expand All @@ -281,113 +284,117 @@ const PreIssueAccessTokenActionConfigForm: FunctionComponent<PreIssueAccessToken
};

return (
<RulesProvider
conditionExpressionsMetaData={ RuleExpressionsMetaData }
initialData={ actionData?.rule }
>
<FinalForm
onSubmit={ (values: ActionConfigFormPropertyInterface, form: any) => {
handleSubmit(values, form.getState().dirtyFields); }
}
validate={ validateForm }
initialValues={ initialValues }
render={ ({ handleSubmit, form }: FormRenderProps) => (
<form onSubmit={ handleSubmit }>
<EmphasizedSegment
className="form-wrapper"
padded={ "very" }
data-componentid={ `${ _componentId }-section` }
>
<div className="form-container with-max-width">
{ renderFormFields() }
{ !isLoading && (
<Button
size="medium"
variant="contained"
onClick={ handleSubmit }
className={ "button-container" }
data-componentid={ `${ _componentId }-primary-button` }
loading={ isSubmitting }
disabled={ getFieldDisabledStatus() }
>
{
isCreateFormState
? t("actions:buttons.create")
: t("actions:buttons.update")
<>
{ !isActionLoading && !actionError && actionData && (
<RulesProvider
conditionExpressionsMetaData={ RuleExpressionsMetaData }
initialData={ actionData?.rule }
>
<FinalForm
onSubmit={ (values: ActionConfigFormPropertyInterface, form: any) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

import type { FormApi } from "final-form";
Suggested change
onSubmit={ (values: ActionConfigFormPropertyInterface, form: any) => {
onSubmit={ (values: ActionConfigFormPropertyInterface, form: FormApi<ActionConfigFormPropertyInterface>) => {

handleSubmit(values, form.getState().dirtyFields); }
}
validate={ validateForm }
initialValues={ initialValues }
render={ ({ handleSubmit, form }: FormRenderProps) => (
<form onSubmit={ handleSubmit }>
<EmphasizedSegment
className="form-wrapper"
padded="very"
data-componentid={ `${ _componentId }-section` }
>
<div className="form-container with-max-width">
{ renderFormFields() }
{ !isLoading && (
<Button
size="medium"
variant="contained"
onClick={ handleSubmit }
className={ "button-container" }
data-componentid={ `${ _componentId }-primary-button` }
loading={ isSubmitting }
disabled={ getFieldDisabledStatus() }
>
{
isCreateFormState
? t("actions:buttons.create")
: t("actions:buttons.update")
}
</Button>
) }
</div>
</EmphasizedSegment>
<FormSpy
subscription={ { values: true } }
>
{ ({ values }: { values: ActionConfigFormPropertyInterface }) => {
if (!isAuthenticationUpdateFormState) {
form.change("authenticationType",
initialValues?.authenticationType);
switch (authenticationType) {
case AuthenticationType.BASIC:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;

break;
case AuthenticationType.BEARER:
delete values.accessTokenAuthProperty;

break;
case AuthenticationType.API_KEY:
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
default:
break;
}
}
</Button>
) }
</div>
</EmphasizedSegment>
<FormSpy
subscription={ { values: true } }
>
{ ({ values }: { values: ActionConfigFormPropertyInterface }) => {
if (!isAuthenticationUpdateFormState) {
form.change("authenticationType",
initialValues?.authenticationType);
switch (authenticationType) {
case AuthenticationType.BASIC:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;

break;
case AuthenticationType.BEARER:
delete values.accessTokenAuthProperty;

break;
case AuthenticationType.API_KEY:
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
default:
break;
}
}

// Clear inputs of property field values of other authentication types.
switch (authenticationType) {
case AuthenticationType.BASIC:
delete values.accessTokenAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
case AuthenticationType.BEARER:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
case AuthenticationType.API_KEY:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.accessTokenAuthProperty;

break;
case AuthenticationType.NONE:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;
delete values.accessTokenAuthProperty;

break;
default:

break;
}

return null;
} }
</FormSpy>
</form>
) }
>
</FinalForm>
</RulesProvider>

// Clear inputs of property field values of other authentication types.
switch (authenticationType) {
case AuthenticationType.BASIC:
delete values.accessTokenAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
case AuthenticationType.BEARER:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;

break;
case AuthenticationType.API_KEY:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.accessTokenAuthProperty;

break;
case AuthenticationType.NONE:
delete values.usernameAuthProperty;
delete values.passwordAuthProperty;
delete values.headerAuthProperty;
delete values.valueAuthProperty;
delete values.accessTokenAuthProperty;

break;
default:

break;
}

return null;
} }
</FormSpy>
</form>
) }
>
</FinalForm>
</RulesProvider>
) }
</>
);
};

Expand Down
34 changes: 19 additions & 15 deletions features/admin.actions.v1/components/rule-config-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ import React, { Dispatch, FunctionComponent, ReactElement, useEffect } from "rea
import { Trans, useTranslation } from "react-i18next";

interface RuleConfigFormInterface extends IdentifiableComponentInterface {
readonly: boolean;
rule: RuleWithoutIdInterface;
isHasRule : boolean;
setIsHasRule: (value: boolean) => void;
setRule: Dispatch<React.SetStateAction<RuleWithoutIdInterface>>;
}

const RuleConfigForm: FunctionComponent<RuleConfigFormInterface> = ({
readonly,
rule,
isHasRule,
setIsHasRule,
Expand Down Expand Up @@ -69,37 +71,39 @@ const RuleConfigForm: FunctionComponent<RuleConfigFormInterface> = ({
<Divider className="divider-container" />
<Heading className="heading-container" as="h5">
<Trans i18nKey={ t("actions:fields.rules.label") }>
Execution Rule
Execution Rule
</Trans>
</Heading>
{ isHasRule ? (
<Rules disableLastRuleDelete={ false } />
<Rules disableLastRuleDelete={ false } readonly={ readonly } />
) : (
<Alert className="alert-nutral" icon={ false }>
<AlertTitle
className="alert-title"
data-componentid={ `${ _componentId }-rule-info-box-title` }
>
<Trans i18nKey={ t("actions:fields.rules.info.title") }>
No execution rule is configured.
No execution rule is configured.
</Trans>
</AlertTitle>
<Trans
i18nKey={ t("actions:fields.authentication.info.message") }
>
This action will be executed without any conditions.
This action will be executed without any conditions.
</Trans>
<div>
<Button
onClick={ () => setIsHasRule(true) }
variant="outlined"
size="small"
className={ "secondary-button" }
data-componentid={ `${ _componentId }-configure-rule-button` }
>
{ t("actions:fields.rules.button") }
</Button>
</div>
{ !readonly && (
<div>
<Button
onClick={ () => setIsHasRule(true) }
variant="outlined"
size="small"
className={ "secondary-button" }
data-componentid={ `${ _componentId }-configure-rule-button` }
>
{ t("actions:fields.rules.button") }
</Button>
</div>
) }
</Alert>
) }
</>
Expand Down
1 change: 1 addition & 0 deletions features/admin.core.v1/store/reducers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const commonConfigReducerInitialState: CommonConfigReducerStateInterface<
accountRecovery: "",
actions: "",
adminAdvisoryBanner: "",
apiRoot: "",
applicationTemplate: "",
applicationTemplateMetadata: "",
applications: "",
Expand Down
3 changes: 2 additions & 1 deletion features/admin.rules.v1/__tests__/__mocks__/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import { ConditionExpressionsMetaDataInterface, RuleExecutionMetaDataInterface } from "../../models/meta";
import { ResourceListInterface } from "../../models/resource";
import { RuleExecuteCollectionInterface, RuleInterface } from "../../models/rules";

export const sampleRuleExecuteInstance: RuleInterface = {
Expand Down Expand Up @@ -83,7 +84,7 @@ export const sampleRuleExecuteInstances: RuleExecuteCollectionInterface = {
]
};

export const sampleApplicationList: any = {
export const sampleApplicationList: ResourceListInterface = {
applications: [
{
access: "READ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
* under the License.
*/

import { Config } from "@wso2is/admin.core.v1/configs/app";
import useRequest, {
RequestConfigInterface,
RequestErrorInterface,
RequestResultInterface
} from "@wso2is/admin.core.v1/hooks/use-request";
import { store } from "@wso2is/admin.core.v1/store";
import { HttpMethods } from "@wso2is/core/models";

/**
Expand All @@ -34,7 +34,7 @@ import { HttpMethods } from "@wso2is/core/models";
* @param shouldFetch - Should fetch the data.
* @returns SWR response object containing the data, error, isLoading, isValidating, mutate.
*/
const useGetResourcesList = <Data = any, Error = RequestErrorInterface>(
const useGetResourceListOrResourceDetails = <Data = any, Error = RequestErrorInterface>(
endpointPath: string,
shouldFetch: boolean = true
): RequestResultInterface<Data, Error> => {
Expand All @@ -44,7 +44,7 @@ const useGetResourcesList = <Data = any, Error = RequestErrorInterface>(
"Content-Type": "application/json"
},
method: HttpMethods.GET,
url: Config.resolveServerHost() + `/api/server/v1${endpointPath}`
url: store.getState().config.endpoints.apiRoot + endpointPath
};

const { data, error, isLoading, isValidating, mutate } = useRequest<Data, Error>(
Expand All @@ -60,4 +60,4 @@ const useGetResourcesList = <Data = any, Error = RequestErrorInterface>(
};
};

export default useGetResourcesList;
export default useGetResourceListOrResourceDetails;
Loading
Loading