From 1b7f2451caa08b357b834f4c92d82de73d45ba4c Mon Sep 17 00:00:00 2001 From: Julian <118911427+julian-mayorga@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:21:28 -0300 Subject: [PATCH] console: Support computed fields in new permissions UI DSF-426 PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10493 GitOrigin-RevId: 6c326ccc2ebb636feb8f1fa73eb6f20b0757832b --- .../PermissionsForm/PermissionsForm.tsx | 13 ++++- .../api/createSelectArgs.test.ts | 5 ++ .../Permissions/PermissionsForm/api/utils.ts | 5 ++ .../components/ColumnPermissions.tsx | 54 +++++++++++++++++-- .../components/Operator.tsx | 16 +++++- .../components/TableProvider.tsx | 9 ++++ .../components/__tests__/fixtures/tables.ts | 6 +++ .../RowPermissionsBuilder/components/types.ts | 5 ++ .../components/utils/comparatorsFromSchema.ts | 5 +- .../components/utils/helpers.ts | 1 + .../hooks/usePermissionTables.tsx | 1 + .../useFormData/createDefaultValues/index.ts | 5 ++ .../useFormData/createDefaultValues/utils.ts | 21 ++++++++ .../useFormData/createFormData/index.ts | 6 ++- .../useFormData/mock/index.ts | 47 +++++++++++++++- .../useFormData/useFormData.test.ts | 2 + .../mocks/createPermissionsData.mock.ts | 5 ++ .../lib/features/Permissions/schema/index.ts | 4 ++ .../permissions/permissions.ts | 1 + .../hasura-metadata-types/source/table.ts | 8 +++ 20 files changed, 208 insertions(+), 11 deletions(-) diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/PermissionsForm.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/PermissionsForm.tsx index 397eb0e9709..8939410393d 100644 --- a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/PermissionsForm.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/PermissionsForm.tsx @@ -4,7 +4,7 @@ import { Button } from '../../../new-components/Button'; import { IndicatorCard } from '../../../new-components/IndicatorCard'; import { MetadataSelector, - useMetadata, + useMetadata as useLegacyMetadata, useRoles, useSupportedQueryTypes, } from '../../MetadataAPI'; @@ -41,6 +41,7 @@ import { inputValidationEnabledSchema, } from '../../../components/Services/Data/TablePermissions/InputValidation/InputValidation'; import { z } from 'zod'; +import { MetadataSelectors, useMetadata } from '../../hasura-metadata-api'; export interface ComponentProps { dataSourceName: string; @@ -70,7 +71,7 @@ const Component = (props: ComponentProps) => { useScrollIntoView(permissionSectionRef, [roleName], { behavior: 'smooth' }); - const { data: metadataTables } = useMetadata( + const { data: metadataTables } = useLegacyMetadata( MetadataSelector.getTables(dataSourceName) ); const tables = metadataTables?.map(t => t.table) ?? []; @@ -197,6 +198,7 @@ const Component = (props: ComponentProps) => { roleName={roleName} queryType={queryType} columns={formData?.columns} + computedFields={formData?.computed_fields} table={table} dataSourceName={dataSourceName} /> @@ -281,6 +283,11 @@ export const PermissionsForm = (props: PermissionsFormProps) => { const { columns: tableColumns, isLoading: isLoadingTables } = useListAllTableColumns(dataSourceName, table); + const metadataTableResult = useMetadata( + MetadataSelectors.findTable(dataSourceName, table) + ); + const computedFields = metadataTableResult.data?.computed_fields ?? []; + const { data: metadataSource } = useMetadataSource(dataSourceName); const { data, isError, isLoading } = useFormData({ @@ -328,6 +335,7 @@ export const PermissionsForm = (props: PermissionsFormProps) => { metadata: data?.metadata, table, tableColumns, + tableComputedFields: computedFields, defaultQueryRoot: data.defaultQueryRoot, metadataSource, supportedOperators: data.supportedOperators, @@ -357,6 +365,7 @@ export const PermissionsForm = (props: PermissionsFormProps) => { table, metadata: data.metadata, tableColumns, + computedFields, trackedTables: metadataSource.tables, metadataSource, validateInput: { diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/createSelectArgs.test.ts b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/createSelectArgs.test.ts index ae872cf5c21..9ba82683655 100644 --- a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/createSelectArgs.test.ts +++ b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/createSelectArgs.test.ts @@ -17,11 +17,13 @@ test('create select args object from form data', () => { args: { table: ['Album'], role: 'user', + comment: '', permission: { columns: ['AlbumId', 'Title', 'ArtistId'], filter: { _not: { AlbumId: { _eq: 'X-Hasura-User-Id' } } }, set: {}, allow_aggregations: false, + computed_fields: [], }, source: 'Chinook', }, @@ -42,6 +44,7 @@ test('create delete args object from form data', () => { args: { table: ['Album'], role: 'user', + comment: '', permission: { backend_only: false, filter: { Title: { _eq: 'Test' } } }, source: 'Chinook', }, @@ -58,6 +61,7 @@ test('create insert args object from form data', () => { args: { table: ['Album'], role: 'user', + comment: '', permission: { columns: [], check: { @@ -69,6 +73,7 @@ test('create insert args object from form data', () => { }, allow_upsert: true, set: {}, + validate_input: undefined, backend_only: false, }, source: 'Chinook', diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/utils.ts b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/utils.ts index 2f8f95a11cd..1e9d43f2129 100644 --- a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/utils.ts +++ b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/api/utils.ts @@ -30,6 +30,7 @@ const formatFilterValues = (formFilter: Record[] = []) => { type SelectPermissionMetadata = { columns: string[]; + computed_fields: string[]; set: Record; filter: Record; allow_aggregations?: boolean; @@ -43,12 +44,16 @@ const createSelectObject = (input: PermissionsSchema) => { const columns = Object.entries(input.columns) .filter(({ 1: value }) => value) .map(([key]) => key); + const computed_fields = Object.entries(input.computed_fields) + .filter(({ 1: value }) => value) + .map(([key]) => key); // Input may be undefined const filter = formatFilterValues(input.filter); const permissionObject: SelectPermissionMetadata = { columns, + computed_fields, filter, set: {}, allow_aggregations: input.aggregationEnabled, diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/components/ColumnPermissions.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/components/ColumnPermissions.tsx index 17c99e789cd..769f19f1e70 100644 --- a/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/components/ColumnPermissions.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/features/Permissions/PermissionsForm/components/ColumnPermissions.tsx @@ -18,6 +18,7 @@ import { SubscriptionRootPermissionType, QueryRootPermissionType, } from './RootFieldPermissions/types'; +import { MetadataSelectors, useMetadata } from '../../../hasura-metadata-api'; const getAccessText = (queryType: string) => { if (queryType === 'insert') { @@ -35,6 +36,7 @@ export interface ColumnPermissionsSectionProps { queryType: QueryType; roleName: string; columns?: string[]; + computedFields?: string[]; table: unknown; dataSourceName: string; } @@ -85,19 +87,30 @@ const checkIfConfirmationIsNeeded = ( ); }; -// @todo -// this hasn't been fully implemented, it still needs computed columns adding export const ColumnPermissionsSection: React.FC< ColumnPermissionsSectionProps -> = ({ roleName, queryType, columns, table, dataSourceName }) => { +> = ({ + roleName, + queryType, + columns, + table, + computedFields, + dataSourceName, +}) => { const { setValue, watch } = useFormContext(); const [showConfirmation, setShowConfirmationModal] = useState( null ); watch(); - const [selectedColumns, queryRootFields, subscriptionRootFields] = watch([ + const [ + selectedColumns, + selectedComputedFields, + queryRootFields, + subscriptionRootFields, + ] = watch([ 'columns', + 'computed_fields', 'query_root_fields', 'subscription_root_fields', ]); @@ -112,6 +125,13 @@ export const ColumnPermissionsSection: React.FC< table ); + const metadataTableResult = useMetadata( + MetadataSelectors.findTable(dataSourceName, table) + ); + const tableComputedFields = metadataTableResult.data?.computed_fields?.map( + ({ name }) => name + ); + const onClick = () => { columns?.forEach(column => { const toggleAllOn = status !== 'All columns'; @@ -119,6 +139,12 @@ export const ColumnPermissionsSection: React.FC< // otherwise toggle all off setValue(`columns.${column}`, toggleAllOn); }); + computedFields?.forEach(field => { + const toggleAllOn = status !== 'All columns'; + // if status is not all columns: toggle all on + // otherwise toggle all off + setValue(`computed_fields.${field}`, toggleAllOn); + }); }; if (isError) { @@ -206,6 +232,26 @@ export const ColumnPermissionsSection: React.FC< {fieldName} ))} + {queryType === 'select' && + tableComputedFields?.map(fieldName => ( + + ))}