-
Notifications
You must be signed in to change notification settings - Fork 6
feat: Generalize user preferences as per resource kind #793
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
base: develop
Are you sure you want to change the base?
Changes from 9 commits
778d3ea
dd3130a
a57ec47
3d9334e
51576c9
92672b0
f6c28c1
6d0a506
ad82427
8fc790b
5319e27
d41abb6
374c90c
8c09454
6ebd364
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { getNoMatchingResultText, SelectPicker, SelectPickerVariantType } from '@Shared/Components' | ||
import { ComponentSizeType } from '@Shared/constants' | ||
|
||
import { ContextSwitcherTypes } from './types' | ||
import { customSelectFilterOption, getDisabledOptions } from './utils' | ||
|
||
export const ContextSwitcher = ({ | ||
inputId, | ||
options = [], | ||
inputValue, | ||
onInputChange, | ||
isLoading, | ||
value, | ||
onChange, | ||
placeholder, | ||
filterOption, | ||
formatOptionLabel, | ||
optionListError, | ||
reloadOptionList, | ||
classNamePrefix, | ||
}: ContextSwitcherTypes) => { | ||
const selectedOptions = options?.map((section) => ({ | ||
...section, | ||
options: section?.label === 'Recently Visited' ? section.options?.slice(1) : section.options, | ||
})) | ||
return ( | ||
<SelectPicker | ||
inputId={inputId} | ||
options={selectedOptions || []} | ||
inputValue={inputValue} | ||
onInputChange={onInputChange} | ||
isLoading={isLoading} | ||
noOptionsMessage={getNoMatchingResultText} | ||
onChange={onChange} | ||
value={value} | ||
variant={SelectPickerVariantType.BORDER_LESS} | ||
placeholder={placeholder} | ||
isOptionDisabled={getDisabledOptions} | ||
size={ComponentSizeType.xl} | ||
filterOption={filterOption || customSelectFilterOption} | ||
formatOptionLabel={formatOptionLabel} | ||
optionListError={optionListError} | ||
reloadOptionList={reloadOptionList} | ||
classNamePrefix={classNamePrefix} | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { ContextSwitcher } from './ContextSwitcher' | ||
export type { ContextSwitcherTypes, RecentlyVisitedGroupedOptionsType, RecentlyVisitedOptions } from './types' | ||
export { getMinCharSearchPlaceholderGroup } from './utils' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { GroupBase } from 'react-select' | ||
|
||
import { SelectPickerOptionType, SelectPickerProps } from '../SelectPicker' | ||
|
||
export interface ContextSwitcherTypes | ||
extends Pick< | ||
SelectPickerProps, | ||
| 'placeholder' | ||
| 'onChange' | ||
| 'value' | ||
| 'isLoading' | ||
| 'onInputChange' | ||
| 'inputValue' | ||
| 'inputId' | ||
| 'formatOptionLabel' | ||
| 'filterOption' | ||
| 'optionListError' | ||
| 'reloadOptionList' | ||
| 'classNamePrefix' | ||
> { | ||
options: GroupBase<SelectPickerOptionType<string | number>>[] | ||
isAppDataAvailable?: boolean | ||
} | ||
|
||
export interface RecentlyVisitedOptions extends SelectPickerOptionType<number> { | ||
isDisabled?: boolean | ||
isRecentlyVisited?: boolean | ||
} | ||
|
||
export interface RecentlyVisitedGroupedOptionsType extends GroupBase<SelectPickerOptionType<number>> { | ||
label: string | ||
options: RecentlyVisitedOptions[] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { SelectPickerProps } from '../SelectPicker' | ||
import { RecentlyVisitedGroupedOptionsType, RecentlyVisitedOptions } from './types' | ||
|
||
export const getDisabledOptions = (option: RecentlyVisitedOptions): SelectPickerProps['isDisabled'] => option.isDisabled | ||
|
||
export const customSelectFilterOption: SelectPickerProps['filterOption'] = (option, searchText: string) => { | ||
const label = option.data.label as string | ||
return option.data.value === 0 || label.toLowerCase().includes(searchText.toLowerCase()) | ||
} | ||
|
||
export const getMinCharSearchPlaceholderGroup = (resourceKind: string): RecentlyVisitedGroupedOptionsType => ({ | ||
label: `All ${resourceKind}`, | ||
options: [{ value: 0, label: 'Type 3 characters to search', isDisabled: true }], | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,11 +17,10 @@ | |
import { ROUTES } from '@Common/Constants' | ||
import { get, getUrlWithSearchParams, patch, showError } from '@Common/index' | ||
import { THEME_PREFERENCE_MAP } from '@Shared/Providers/ThemeProvider/types' | ||
import { BaseAppMetaData } from '@Shared/Services' | ||
import { ResourceKindType } from '@Shared/types' | ||
|
||
import { USER_PREFERENCES_ATTRIBUTE_KEY } from './constants' | ||
import { PreferredResourceKinds, USER_PREFERENCES_ATTRIBUTE_KEY } from './constants' | ||
import { | ||
BaseRecentlyVisitedEntitiesTypes, | ||
GetUserPreferencesParsedDTO, | ||
GetUserPreferencesQueryParamsType, | ||
UpdateUserPreferencesPayloadType, | ||
|
@@ -34,6 +33,18 @@ import { | |
} from './types' | ||
import { getUserPreferenceResourcesMetadata } from './utils' | ||
|
||
export const getParsedResourcesMap = ( | ||
resources: GetUserPreferencesParsedDTO['resources'], | ||
): UserPreferencesType['resources'] => { | ||
const parsedResourcesMap: UserPreferencesType['resources'] = {} | ||
|
||
PreferredResourceKinds.forEach((resourceKind) => { | ||
parsedResourcesMap[resourceKind] = resources?.[resourceKind] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls add fallback |
||
}) | ||
|
||
return parsedResourcesMap | ||
} | ||
AbhishekA1509 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* @returns UserPreferencesType | ||
* @description This function fetches the user preferences from the server. It uses the `get` method to make a request to the server and retrieves the user preferences based on the `USER_PREFERENCES_ATTRIBUTE_KEY`. The result is parsed and returned as a `UserPreferencesType` object. | ||
|
@@ -64,17 +75,9 @@ export const getUserPreferences = async (): Promise<UserPreferencesType> => { | |
parsedResult.computedAppTheme === 'system-dark' || parsedResult.computedAppTheme === 'system-light' | ||
? THEME_PREFERENCE_MAP.auto | ||
: parsedResult.computedAppTheme, | ||
resources: { | ||
[ResourceKindType.devtronApplication]: { | ||
[UserPreferenceResourceActions.RECENTLY_VISITED]: | ||
parsedResult.resources?.[ResourceKindType.devtronApplication]?.[ | ||
UserPreferenceResourceActions.RECENTLY_VISITED | ||
] || ([] as BaseAppMetaData[]), | ||
}, | ||
}, | ||
resources: getParsedResourcesMap(parsedResult.resources), | ||
} | ||
} | ||
|
||
/** | ||
* @description This function updates the user preferences in the server. It constructs a payload with the updated user preferences and sends a PATCH request to the server. If the request is successful, it returns true. If an error occurs, it shows an error message and returns false. | ||
* @param updatedUserPreferences - The updated user preferences to be sent to the server. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls fix the comment |
||
|
@@ -87,6 +90,8 @@ export const getUserPreferences = async (): Promise<UserPreferencesType> => { | |
const getUserPreferencePayload = async ({ | ||
path, | ||
value, | ||
resourceKind, | ||
userPreferencesResponse, | ||
}: UserPathValueMapType): Promise<Partial<UserPreferencesPayloadValueType>> => { | ||
switch (path) { | ||
case 'themePreference': | ||
|
@@ -100,10 +105,24 @@ const getUserPreferencePayload = async ({ | |
value.pipelineRBACViewSelectedTab === ViewIsPipelineRBACConfiguredRadioTabs.ACCESS_ONLY, | ||
} | ||
|
||
case 'resources': | ||
case 'resources': { | ||
const existingResources = userPreferencesResponse?.resources || {} | ||
|
||
const updatedResources = { | ||
...existingResources, | ||
[resourceKind]: { | ||
...existingResources[resourceKind], | ||
[UserPreferenceResourceActions.RECENTLY_VISITED]: | ||
getUserPreferenceResourcesMetadata(value as BaseRecentlyVisitedEntitiesTypes[], resourceKind)[ | ||
resourceKind | ||
]?.[UserPreferenceResourceActions.RECENTLY_VISITED] || [], | ||
}, | ||
} | ||
|
||
return { | ||
resources: getUserPreferenceResourcesMetadata(value as BaseAppMetaData[]), | ||
resources: updatedResources, | ||
} | ||
} | ||
default: | ||
return {} | ||
} | ||
|
@@ -112,12 +131,21 @@ const getUserPreferencePayload = async ({ | |
export const updateUserPreferences = async ({ | ||
path, | ||
value, | ||
resourceKind, | ||
shouldThrowError = false, | ||
userPreferencesResponse, | ||
}: UserPreferenceResourceProps): Promise<boolean> => { | ||
try { | ||
const payload: UpdateUserPreferencesPayloadType = { | ||
key: USER_PREFERENCES_ATTRIBUTE_KEY, | ||
value: JSON.stringify(await getUserPreferencePayload({ path, value } as UserPathValueMapType)), | ||
value: JSON.stringify( | ||
await getUserPreferencePayload({ | ||
path, | ||
value, | ||
resourceKind, | ||
userPreferencesResponse, | ||
} as UserPathValueMapType), | ||
), | ||
} | ||
|
||
await patch(`${ROUTES.ATTRIBUTES_USER}/${ROUTES.PATCH}`, payload) | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pls move to UPPER_CASE and can we make object since that will be type safe if new type is added