hunk.code_window:         }
           return Mono.whenDelayError(monos).then(updatedUserMono);
       }
       public Map<String, String> getEmailParams(Organization organization, User inviter, String inviteUrl, boolean isNewUser) {
           Map<String, String> params = new HashMap<>();
  
hunk.labels: keep keep replace keep keep keep keep keep
hunk.after_edit:         return Mono.whenDelayError(monos)
                   .then(Mono.zip(updatedUserMono, updatedUserDataMono))
                   .flatMap(tuple -> {
                       final User user = tuple.getT1();
                       final UserData userData = tuple.getT2();
                       return analyticsService.identifyUser(user, userData).thenReturn(user);
                   });
  
hunk.file_path: app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java
hunk.type: replace
file: import { Alignment } from "@blueprintjs/core";
  import { ColumnProperties } from "../component/Constants";
  import { TableWidgetProps } from "../constants";
  import { get } from "lodash";
  
  export enum ColumnTypes {
    TEXT = "text",
    URL = "url",
    NUMBER = "number",
    IMAGE = "image",
    VIDEO = "video",
    DATE = "date",
    BUTTON = "button",
    ICON_BUTTON = "iconButton",
    MENU_BUTTON = "menuButton",
  }
  
  export function defaultSelectedRowValidation(
    value: unknown,
    props: TableWidgetProps,
    _: any,
  ) {
    if (props) {
      if (props.multiRowSelection) {
        if (props && !props.multiRowSelection)
          return { isValid: true, parsed: undefined };
  
        if (_.isString(value)) {
          const trimmed = (value as string).trim();
          try {
            const parsedArray = JSON.parse(trimmed);
            if (Array.isArray(parsedArray)) {
              const sanitized = parsedArray.filter((entry) => {
                return (
                  Number.isInteger(parseInt(entry, 10)) &&
                  parseInt(entry, 10) > -1
                );
              });
              return { isValid: true, parsed: sanitized };
            } else {
              throw Error("Not a stringified array");
            }
          } catch (e) {
            // If cannot be parsed as an array
            const arrayEntries = trimmed.split(",");
            const result: number[] = [];
            arrayEntries.forEach((entry: string) => {
              if (
                Number.isInteger(parseInt(entry, 10)) &&
                parseInt(entry, 10) > -1
              ) {
                if (!_.isNil(entry)) result.push(parseInt(entry, 10));
              }
            });
            return { isValid: true, parsed: result };
          }
        }
        if (Array.isArray(value)) {
          const sanitized = value.filter((entry) => {
            return (
              Number.isInteger(parseInt(entry, 10)) && parseInt(entry, 10) > -1
            );
          });
          return { isValid: true, parsed: sanitized };
        }
        if (Number.isInteger(value) && (value as number) > -1) {
          return { isValid: true, parsed: [value] };
        }
        return {
          isValid: false,
          parsed: [],
          message: `This value does not match type: number[]`,
        };
      } else {
        try {
          const _value: string = value as string;
          if (Number.isInteger(parseInt(_value, 10)) && parseInt(_value, 10) > -1)
            return { isValid: true, parsed: parseInt(_value, 10) };
  
          return {
            isValid: true,
            parsed: -1,
          };
        } catch (e) {
          return {
            isValid: true,
            parsed: -1,
          };
        }
      }
    }
    return {
      isValid: true,
      parsed: value,
    };
  }
  
  export function totalRecordsCountValidation(
    value: unknown,
    props: TableWidgetProps,
    _?: any,
  ) {
    if (_.isNil(value) || value === "") {
      return {
        isValid: true,
        parsed: 0,
        message: "",
      };
    }
    if (!Number.isFinite(value) && !_.isString(value)) {
      return {
        isValid: false,
        parsed: 0,
        message: "This value must be a number",
      };
    }
    if (_.isString(value) && !/^\d+\.?\d*$/.test(value as string)) {
      return {
        isValid: false,
        parsed: 0,
        message: "This value must be a number",
      };
    }
    return {
      isValid: true,
      parsed: Number(value),
      message: "",
    };
  }
  
  // A hook to update all column styles when global table styles are updated
  export const updateColumnStyles = (
    props: TableWidgetProps,
    propertyPath: string,
    propertyValue: any,
  ): Array<{ propertyPath: string; propertyValue: any }> | undefined => {
    const { primaryColumns, derivedColumns = {} } = props;
    const propertiesToUpdate: Array<{
      propertyPath: string;
      propertyValue: any;
    }> = [];
    const tokens = propertyPath.split("."); // horizontalAlignment/textStyle
    const currentStyleName = tokens[0];
    // TODO: Figure out how propertyPaths will work when a nested property control is updating another property
    if (primaryColumns && currentStyleName) {
      // The style being updated currently
  
      // for each primary column
      Object.values(primaryColumns).map((column: ColumnProperties) => {
        // Current column property path
        const propertyPath = `primaryColumns.${column.id}.${currentStyleName}`;
        // Is current column a derived column
        const isDerived = primaryColumns[column.id].isDerived;
  
        // If it is a derived column and it exists in derivedColumns
        if (isDerived && derivedColumns[column.id]) {
          propertiesToUpdate.push({
            propertyPath: `derivedColumns.${column.id}.${currentStyleName}`,
            propertyValue: propertyValue,
          });
        }
        // Is this a dynamic binding property?
        const notADynamicBinding =
          !props.dynamicBindingPathList ||
          props.dynamicBindingPathList.findIndex(
            (item) => item.key === propertyPath,
          ) === -1;
  
        if (notADynamicBinding) {
          propertiesToUpdate.push({
            propertyPath: `primaryColumns.${column.id}.${currentStyleName}`,
            propertyValue: propertyValue,
          });
        }
      });
      if (propertiesToUpdate.length > 0) return propertiesToUpdate;
    }
    return;
  };
  // Select a default Icon Alignment when an icon is chosen
  export function updateIconAlignment(
    props: TableWidgetProps,
    propertyPath: string,
    propertyValue: string,
  ) {
    const property = getBasePropertyPath(propertyPath);
    const iconAlign = get(props, `${property}.iconAlign`, "");
    let propertiesToUpdate = [{ propertyPath, propertyValue }];
    const updateDerivedColumnsHookArr = updateDerivedColumnsHook(
      props,
      propertyPath,
      propertyValue,
    );
    if (updateDerivedColumnsHookArr) {
      propertiesToUpdate = [
        ...updateDerivedColumnsHookArr,
        ...propertiesToUpdate,
      ];
    }
  
    if (iconAlign) {
      propertiesToUpdate.push({
        propertyPath: "iconAlign",
        propertyValue: Alignment.LEFT,
      });
    }
    return propertiesToUpdate;
  }
  
  // A hook for handling property updates when the primaryColumns
  // has changed and it is supposed to update the derivedColumns
  // For example, when we add a new column or update a derived column's name
  // The propertyPath will be of the type `primaryColumns.columnId`
  // Handling BindingProperty of derived columns
  export const updateDerivedColumnsHook = (
    props: TableWidgetProps,
    propertyPath: string,
    propertyValue: any,
  ): Array<{ propertyPath: string; propertyValue: any }> | undefined => {
    let propertiesToUpdate: Array<{
      propertyPath: string;
      propertyValue: any;
    }> = [];
    if (props && propertyValue) {
      // If we're adding a column, we need to add it to the `derivedColumns` property as well
      if (/^primaryColumns\.\w+$/.test(propertyPath)) {
        const newId = propertyValue.id;
        if (newId) {
          propertiesToUpdate = [
            {
              propertyPath: `derivedColumns.${newId}`,
              propertyValue,
            },
          ];
        }
  
        const oldColumnOrder = props.columnOrder || [];
        const newColumnOrder = [...oldColumnOrder, propertyValue.id];
        propertiesToUpdate.push({
          propertyPath: "columnOrder",
          propertyValue: newColumnOrder,
        });
      }
      // If we're updating a columns' name, we need to update the `derivedColumns` property as well.
      const regex = /^primaryColumns\.(\w+)\.(.*)$/;
      if (regex.test(propertyPath)) {
        const matches = propertyPath.match(regex);
        if (matches && matches.length === 3) {
          // updated to use column keys
          const columnId = matches[1];
          const columnProperty = matches[2];
          const primaryColumn = props.primaryColumns[columnId];
          const isDerived = primaryColumn ? primaryColumn.isDerived : false;
  
          const { derivedColumns = {} } = props;
  
          if (isDerived && derivedColumns && derivedColumns[columnId]) {
            propertiesToUpdate = [
              {
                propertyPath: `derivedColumns.${columnId}.${columnProperty}`,
                propertyValue: propertyValue,
              },
            ];
          }
        }
      }
      if (propertiesToUpdate.length > 0) return propertiesToUpdate;
    }
    return;
  };
  // Gets the base property path excluding the current property.
  // For example, for  `primaryColumns[5].computedValue` it will return
  // `primaryColumns[5]`
  export const getBasePropertyPath = (
    propertyPath: string,
  ): string | undefined => {
    try {
      const propertyPathRegex = /^(.*)\.\w+$/g;
      const matches = [...propertyPath.matchAll(propertyPathRegex)][0];
      if (matches && Array.isArray(matches) && matches.length === 2) {
        return matches[1];
      }
      return;
    } catch (e) {
      return;
    }
  };
  
  // Hide column which are not included in the array params
  export const hideByColumnType = (
    props: TableWidgetProps,
    propertyPath: string,
    columnTypes: ColumnTypes[],
    shouldUsePropertyPath?: boolean,
  ) => {
    const baseProperty = shouldUsePropertyPath
      ? propertyPath
      : getBasePropertyPath(propertyPath);
    const columnType = get(props, `${baseProperty}.columnType`, "");
    return !columnTypes.includes(columnType);
  };
  