/* * Copyright OpenSearch Contributors * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ import { EuiAccordion, EuiButton, EuiComboBox, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSuperSelect, EuiTextArea, } from '@elastic/eui'; import React, { Dispatch, Fragment, SetStateAction } from 'react'; import { isEmpty } from 'lodash'; import { RoleIndexPermission, ResourceType } from '../../types'; import { appendElementToArray, removeElementFromArray, updateElementInArrayHandler, } from '../../utils/array-state-utils'; import { appendOptionToComboBoxHandler, comboBoxOptionToString, stringToComboBoxOption, } from '../../utils/combo-box-utils'; import { FormRow } from '../../utils/form-row'; import { PanelWithHeader } from '../../utils/panel-with-header'; import { RoleIndexPermissionStateClass } from './types'; import { FieldLevelSecurityMethod, ComboBoxOptions } from '../../types'; import { getFieldLevelSecurityMethod } from '../../utils/index-permission-utils'; import { LIMIT_WIDTH_INPUT_CLASS } from '../../constants'; import { buildHashUrl } from '../../utils/url-builder'; import { ExternalLinkButton } from '../../utils/display-utils'; import { DocLinks } from '../../constants'; export function getEmptyIndexPermission(): RoleIndexPermissionStateClass { return { indexPatterns: [], allowedActions: [], docLevelSecurity: '', fieldLevelSecurityMethod: 'exclude', fieldLevelSecurityFields: [], maskedFields: [], }; } /** * Remove the leading ~ which indicates exclude and convert to combo box option. * @param fieldLevelSecurityRawFields fields fetched from backend * ["~field1", "~field2"] => ["field1", "field2"] * ["field1", "field2"] => ["field1", "field2"] */ function getFieldLevelSecurityFields(fieldLevelSecurityRawFields: string[]): ComboBoxOptions { return fieldLevelSecurityRawFields .map((s: string) => s.replace(/^~/, '')) .map(stringToComboBoxOption); } function packFieldLevelSecurity(method: FieldLevelSecurityMethod, fieldOptions: ComboBoxOptions) { const fields = fieldOptions.map(comboBoxOptionToString); if (method === 'include') { return fields; } return fields.map((field) => '~' + field); } export function buildIndexPermissionState( indexPerm: RoleIndexPermission[] ): RoleIndexPermissionStateClass[] { return indexPerm.map((perm) => ({ indexPatterns: perm.index_patterns.map(stringToComboBoxOption), allowedActions: perm.allowed_actions.map(stringToComboBoxOption), docLevelSecurity: perm.dls, fieldLevelSecurityMethod: getFieldLevelSecurityMethod(perm.fls), fieldLevelSecurityFields: getFieldLevelSecurityFields(perm.fls), maskedFields: perm.masked_fields.map(stringToComboBoxOption), })); } export function unbuildIndexPermissionState( indexPerm: RoleIndexPermissionStateClass[] ): RoleIndexPermission[] { return indexPerm.map((perm) => ({ index_patterns: perm.indexPatterns.map(comboBoxOptionToString), dls: perm.docLevelSecurity, fls: packFieldLevelSecurity(perm.fieldLevelSecurityMethod, perm.fieldLevelSecurityFields), masked_fields: perm.maskedFields.map(comboBoxOptionToString), allowed_actions: perm.allowedActions.map(comboBoxOptionToString), })); } const FIELD_LEVEL_SECURITY_PLACEHOLDER = `{ "bool": { "must": { "match": { "genres": "Comedy" } } } }`; export function IndexPatternRow(props: { value: ComboBoxOptions; onChangeHandler: (s: ComboBoxOptions) => void; onCreateHandler: (s: string) => void; }) { return ( ); } export function IndexPermissionRow(props: { value: ComboBoxOptions; permisionOptionsSet: ComboBoxOptions; onChangeHandler: (s: ComboBoxOptions) => void; }) { return ( {/* TODO: 'Browse and select' button with a pop-up modal for selection */} ); } export function DocLevelSecurityRow(props: { value: string; onChangeHandler: (e: React.ChangeEvent) => void; }) { return ( ); } export function FieldLevelSecurityRow(props: { method: FieldLevelSecurityMethod; fields: ComboBoxOptions; onMethodChangeHandler: (s: string) => void; onFieldChangeHandler: (s: ComboBoxOptions) => void; onFieldCreateHandler: (s: string) => void; }) { return ( ); } export function AnonymizationRow(props: { value: ComboBoxOptions; onChangeHandler: (s: ComboBoxOptions) => void; onCreateHandler: (s: string) => void; }) { return ( ); } export function generateIndexPermissionPanels( indexPermissions: RoleIndexPermissionStateClass[], permisionOptionsSet: ComboBoxOptions, setRoleIndexPermission: Dispatch> ) { const panels = indexPermissions.map((permission, arrayIndex) => { const onValueChangeHandler = (attributeToUpdate: string) => updateElementInArrayHandler(setRoleIndexPermission, [arrayIndex, attributeToUpdate]); const onCreateOptionHandler = (attributeToUpdate: string) => appendOptionToComboBoxHandler(setRoleIndexPermission, [arrayIndex, attributeToUpdate]); return ( removeElementFromArray(setRoleIndexPermission, [], arrayIndex)} > Remove } > onValueChangeHandler('docLevelSecurity')(e.target.value)} /> ); }); return <>{panels}; } export function IndexPermissionPanel(props: { state: RoleIndexPermissionStateClass[]; optionUniverse: ComboBoxOptions; setState: Dispatch>; }) { const { state, optionUniverse, setState } = props; // Show one empty row if there is no data. if (isEmpty(state)) { setState([getEmptyIndexPermission()]); } return ( {generateIndexPermissionPanels(state, optionUniverse, setState)} { appendElementToArray(setState, [], getEmptyIndexPermission()); }} > Add another index permission ); }