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

Assign policy wizard #906

Merged

Conversation

GowthamShanmugam
Copy link
Contributor

@GowthamShanmugam GowthamShanmugam commented Jun 22, 2023

On top of: #903

@GowthamShanmugam GowthamShanmugam changed the title Assign policy wizard Assign policy wizard - WIP Jun 22, 2023
@GowthamShanmugam
Copy link
Contributor Author

/hold

}) => {
const [isOpen, setOpen] = React.useState(false);
const [selected, setSelected] = React.useState<string[]>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the Assign policy modal, the use case is to clear all selected labels for the clear button. So i want to control setSelected from outside of this component.

@@ -190,6 +193,8 @@ export const NameValueEditor: React.FC<NameValueEditorProps> =
toolTip,
nameString,
valueString,
extraProps,
PairElementComponent = PairElement,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am passing my own custom component to change the NameValueEditor body, But functionality is re-used.

@@ -337,10 +338,6 @@ export const LocalVolumeSetBody: React.FC<LocalVolumeSetBodyProps> = ({
onChange={(selectedValues: string[]) =>
formHandler('deviceType', selectedValues)
}
defaultSelected={[
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since I removed setSelected from multiselecteddropdown.tsx, it no longer has defaultSelected props. I am expecting the state variable "selected" should be pre-initialized with the default variable.

state.deviceType has default redux initialized value of this defaultSelected, no need to pass explicitly.

@@ -0,0 +1,137 @@
import { DRPC_STATUS } from '@odf/mco/constants';
import { DisasterRecoveryFormatted } from '@odf/mco/hooks';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can reuse this file for a subscription app also, so created separate util for that

@GowthamShanmugam
Copy link
Contributor Author

Screencast.from.2023-06-28.15-57-10.webm

@GowthamShanmugam
Copy link
Contributor Author

/hold cancel

@@ -14,3 +14,5 @@ export const enum VOLUME_REPLICATION_HEALTH {
export const ACM_OBSERVABILITY_FLAG = 'ACM_OBSERVABILITY';
export const ADMIN_FLAG = 'ADMIN';
export const ODFMCO_OPERATOR_NAMESPACE = 'openshift-operators';
export const ACM_SEARCH_PROXY_URL =
'/api/proxy/plugin/acm/console/multicloud/proxy/search';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to move all ACM related constant in separate file

Comment on lines +205 to +207
drPlacementControl?: DRPlacementControlKind;
drPolicy?: DRPolicyKind;
drClusters?: DRClusterKind[];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

drpc resources are optional for unprotected apps

}) => {
const [isOpen, setOpen] = React.useState(false);
const [selected, setSelected] = React.useState<string[]>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have a use case like removing the selected Placement from outside of this component,
image

@GowthamShanmugam GowthamShanmugam force-pushed the RHSTOR-4605 branch 3 times, most recently from b1ce37f to 1f026c2 Compare July 7, 2023 11:11
@@ -214,7 +225,17 @@
"Assigned on": "Assigned on",
"View configurations": "View configurations",
"No activity": "No activity",
"Back": "Back",
"Delete": "Delete",
"Select a placement": "Select a placement",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"Select a placement": "Select a placement",
"Select a placement": "Select a placement",

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

};
} else {
return {
title: t('Manage data policy'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we still calling it Manage data policy even though we only allow assign as of now ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ya, But Title and description needs to be decided, doc team is working on this


const assignPolicy = () => {
setAssignDisabled(true);
const updateContext = async (
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const updateContext = async (
const updateContext = (

const getPlacementTags = (drpcs: DRPlacementControlType[]) =>
!!drpcs.length
? drpcs.map(
(drpc) => [getName(drpc.placementInfo), drpc?.pvcSelector] || []
Copy link
Collaborator

@SanjalKatiyar SanjalKatiyar Jul 8, 2023

Choose a reason for hiding this comment

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

it will never reach this condition...

Suggested change
(drpc) => [getName(drpc.placementInfo), drpc?.pvcSelector] || []
(drpc) => [getName(drpc.placementInfo), drpc?.pvcSelector]

const getLabelsFromSearchResult = (searchResult: SearchResult): string[] => {
const pvcLabels =
searchResult?.data.searchResult?.[0]?.items.reduce(
(acc, item) => [...acc, ...item?.[LABEL]?.split(SPLIT_CHAR)],
Copy link
Collaborator

Choose a reason for hiding this comment

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

spread will give error when item?.[LABEL]?.split(SPLIT_CHAR) is undefined...

const getLabelsFromSearchResult = (searchResult: SearchResult): string[] => {
const pvcLabels =
searchResult?.data.searchResult?.[0]?.items.reduce(
(acc, item) => [...acc, ...item?.[LABEL]?.split(SPLIT_CHAR)],
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should work ??

Suggested change
(acc, item) => [...acc, ...item?.[LABEL]?.split(SPLIT_CHAR)],
(acc, item) => [...acc, ...item[LABEL]?.split(SPLIT_CHAR)],


const getPlacementsFromTags = (tags: TagsType, currIndex: number): string[] =>
tags.reduce((acc, tag, index) => {
const placement = tag?.[0];
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is not an array like labels ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tag is an array type and it has only two indexes, one is the placement of string type, other one is the label of string[] type.

type TagsType = (string | string[])[][];

basically tag?.[0] is string, tag?.[1]; is array

Comment on lines 115 to 122
const NameValueEditorComponent = (props) => (
<AsyncLoader
loader={() =>
import('@odf/shared/utils/NameValueEditor').then((c) => c.NameValueEditor)
}
{...props}
/>
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nits: better to export this as LazyNameValueEditor from shared and use that everywhere...

Copy link
Collaborator

Choose a reason for hiding this comment

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

also do we even need lazy import ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are using lazy loading against NameValueEditor component in multiple places for code splitting: https://legacy.reactjs.org/docs/code-splitting.html

To avoid increasing the size of the bundle using some complex library.

Thanks, @bipuladh for the ref link

Copy link
Collaborator

@SanjalKatiyar SanjalKatiyar Jul 10, 2023

Choose a reason for hiding this comment

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

yup, I got that... but my doubt was whether we are saving lot of bundle size by doing splitting here ??
Default NameValueEditor had code for PairElement, but in MCO we are passing that as a prop as well PairElementComponent (which means it is getting bundled in same code as the one which is calling the FC)... so is there any major advantage of splitting here ??

Copy link
Collaborator

@SanjalKatiyar SanjalKatiyar Jul 10, 2023

Choose a reason for hiding this comment

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

anyway, no issues with using lazy loading, but don;t see any specific reason as well here... by some complex library do u mean these ??

import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe i am wrong here but I thought bundle creation is nothing to do with runtime calls, MCO calls the PairElementComponent, or PairElement is decided at runtime, so it will still affect the bundle size when i use NameValueEditor directly.

values: clusterNames,
},
],
limit: 20,
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. do we need limit ??
  2. in the workloadNamespace, can there be PVCs which are not related to this Application, how we decide whether a PVC is independent or belongs to an ACM Application ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, UI API read needs a limit. UI can't read large amounts of PVCs. It will affect the performance. As per PM and QE, the number of PVCs per app is around 20 only, the count may go a little bit higher in the future but never read all PVCs blindly.

UI can't decide which PVCs are related to the app and which PVCs are not realted. UI is just assuming all PVCs under the namespace are realted to the app only. It is up to the user to decide which label to select.

Copy link
Collaborator

Choose a reason for hiding this comment

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

so it will mean that for cases where app has more than 20 PVCs, our UI will not work as expected and can show some missing labels ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

UI needs a limit, If they wants to use more PVC, then they have to use CLI way

Copy link
Collaborator

Choose a reason for hiding this comment

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

my question here would be limit just tells us how my data points the response from the API call will be right ??
If limit=20 or limit=200, in both cases it will still be a single API request right ?? so will it make diff to hard limit it to be 20 PVCs ?? @GowthamShanmugam

Copy link
Collaborator

Choose a reason for hiding this comment

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

in list pages, say Secrets a cluster can have 300 secrets as well... all we display on UI and we send a single API call which gives us all 300 secret in a single response...

Copy link
Collaborator

@SanjalKatiyar SanjalKatiyar Jul 10, 2023

Choose a reason for hiding this comment

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

UI just need to maintain a list of all PVCs (which it can easily), any other performance impact which I might be missing ??

Copy link
Contributor Author

@GowthamShanmugam GowthamShanmugam Jul 10, 2023

Choose a reason for hiding this comment

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

We usually send an API request to the local cluster, But here ACM search API is sending an API request to the managed clusters.

ACM is sending an API request to its managed cluster agent, and an agent will receive the API request and read all PVC from the namespace and convert the result to a custom response object and send it back to the hub cluster.

if we give a limit of 20 then it will read only first 20 PVCs from the namespace. it means the API request will be waiting for the 20 PVC results to be parsed. If we increase the limit then it will take increase the API response time.

Per namespace, I dont think the user will create more than 20 PVCs, If QE thinks the number is not enough i will increase more.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea here is, not all PVCs should have a unique namespace, the user has to reuse the labels as much as possible between PVCs

Comment on lines +105 to +109
export const getClusterNamesFromPlacements = (placements: PlacementType[]) =>
placements?.reduce(
(acc, placemnt) => [...acc, ...placemnt?.deploymentClusters],
[]
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

just to confirm, r u sure we already do not have this function defined somewhere ?? seems like something we have done at other places as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is for the custom object type, the old one for the PlacementDecisionKind object which takes from clusters from status?.decisions

);

// ACM search proxy api call
const [searchResult] = useACMSafeFetch(
Copy link
Collaborator

Choose a reason for hiding this comment

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

what about handling loading and error ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about this, but with the current UX I dont see any places to display error message or any other option, Need to check with ux what to do

Comment on lines +92 to +111
const createDRPlacementControlObj = (
placement: PlacementType,
dataPolicyRef: ObjectReference
): DRPlacementControlType => ({
apiVersion: DRPlacementControlModel.apiVersion,
kind: DRPlacementControlModel.kind,
metadata: {
name: `${getName(placement)}-drpc`,
namespace: getNamespace(placement),
},
drPolicyRef: dataPolicyRef,
placementInfo: placement,
pvcSelector: [],
});

const updateLabels = (
drPlacementControl: DRPlacementControlType,
labels: string[]
): DRPlacementControlType => ({
...drPlacementControl,
pvcSelector: labels,
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

can't we re-use getDRPCKindObj from utils ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a custom-type object for wizard flow,
All the components under the manage policy modal will understand this custom type,
So I am keeping this custom type to reuse components, for example, policy configuration view (used for review and create page, as well as to display policy configurations)
At the end of the assign policy wizard i am converting this custom type to using getDRPCKindObj to create DRPC.

.catch((err) => {
setError(err);
});
}, [setResponse, searchQuery, safeFetch]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
}, [setResponse, searchQuery, safeFetch]);
}, [setResponse, searchQuery]);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

safeFetch is also one dependency

Copy link
Collaborator

Choose a reason for hiding this comment

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

not needed as it won;t change (check useURLPoll)...
if needed anyway then wrap safeFetch in a useCallback before returning it from the hook...

Copy link
Collaborator

Choose a reason for hiding this comment

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

currently if u add it as it is then it will cause issues...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure how it works for useURLPoll, i am getting lint error if i am not adding it in dependency

Copy link
Collaborator

@SanjalKatiyar SanjalKatiyar Jul 10, 2023

Choose a reason for hiding this comment

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

u can disable the lint error... or if u do not want to do that let;s use useCallback so that ref of safeFetch do not changes...

Copy link
Collaborator

Choose a reason for hiding this comment

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

for disabling use // eslint-disable-next-line <error_name>

Copy link
Collaborator

Choose a reason for hiding this comment

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

if want to use useCallback u need to use it in the hook itself that returns safeFetch.

@GowthamShanmugam GowthamShanmugam force-pushed the RHSTOR-4605 branch 2 times, most recently from d478a7e to 08d45c9 Compare July 10, 2023 11:23
Signed-off-by: Gowtham Shanmugasundaram <[email protected]>
Copy link
Contributor

@bipuladh bipuladh left a comment

Choose a reason for hiding this comment

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

lgtm

@SanjalKatiyar
Copy link
Collaborator

/approve
/lgtm

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jul 10, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: GowthamShanmugam, SanjalKatiyar

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@bipuladh
Copy link
Contributor

/test odf-console-e2e-aws

@openshift-merge-robot openshift-merge-robot merged commit e40d0bf into red-hat-storage:master Jul 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants