blob: 471a7a0065bad3d48418f348c6d34e2e95600b56 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License 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 { Children, cloneElement } from 'react';
import { nanoid } from 'nanoid';
import { SupersetClient, tn } from '@superset-ui/core';
import rison from 'rison';
export function recurseReactClone(children, type, propExtender) {
/**
* Clones a React component's children, and injects new props
* where the type specified is matched.
*/
return Children.map(children, child => {
let newChild = child;
if (child && child.type && child.type.name === type.name) {
newChild = cloneElement(child, propExtender(child));
}
if (newChild && newChild.props && newChild.props.children) {
newChild = cloneElement(newChild, {
children: recurseReactClone(
newChild.props.children,
type,
propExtender,
),
});
}
return newChild;
});
}
export function updateColumns(prevCols, newCols, addSuccessToast) {
// cols: Array<{column_name: string; is_dttm: boolean; type: string;}>
const databaseColumnNames = newCols.map(col => col.column_name);
const currentCols = prevCols.reduce((agg, col) => {
// eslint-disable-next-line no-param-reassign
agg[col.column_name] = col;
return agg;
}, {});
const columnChanges = {
added: [],
modified: [],
removed: prevCols
.filter(
col =>
!(col.expression || databaseColumnNames.includes(col.column_name)),
)
.map(col => col.column_name),
finalColumns: [],
};
newCols.forEach(col => {
const currentCol = currentCols[col.column_name];
if (!currentCol) {
// new column
columnChanges.finalColumns.push({
id: nanoid(),
column_name: col.column_name,
type: col.type,
groupby: true,
filterable: true,
is_dttm: col.is_dttm,
});
columnChanges.added.push(col.column_name);
} else if (
currentCol.type !== col.type ||
currentCol.is_dttm !== col.is_dttm
) {
// modified column
columnChanges.finalColumns.push({
...currentCol,
type: col.type,
is_dttm: currentCol.is_dttm || col.is_dttm,
});
columnChanges.modified.push(col.column_name);
} else {
// unchanged
columnChanges.finalColumns.push(currentCol);
}
});
// push all calculated columns
prevCols
.filter(col => col.expression)
.forEach(col => {
columnChanges.finalColumns.push(col);
});
if (columnChanges.modified.length) {
addSuccessToast(
tn(
'Modified 1 column in the virtual dataset',
'Modified %s columns in the virtual dataset',
columnChanges.modified.length,
columnChanges.modified.length,
),
);
}
if (columnChanges.removed.length) {
addSuccessToast(
tn(
'Removed 1 column from the virtual dataset',
'Removed %s columns from the virtual dataset',
columnChanges.removed.length,
columnChanges.removed.length,
),
);
}
if (columnChanges.added.length) {
addSuccessToast(
tn(
'Added 1 new column to the virtual dataset',
'Added %s new columns to the virtual dataset',
columnChanges.added.length,
columnChanges.added.length,
),
);
}
return columnChanges;
}
export async function fetchSyncedColumns(datasource) {
const params = {
datasource_type: datasource.type || datasource.datasource_type,
database_name:
datasource.database?.database_name || datasource.database?.name,
catalog_name: datasource.catalog,
schema_name: datasource.schema,
table_name: datasource.table_name,
normalize_columns: datasource.normalize_columns,
always_filter_main_dttm: datasource.always_filter_main_dttm,
};
Object.entries(params).forEach(([key, value]) => {
// rison can't encode the undefined value
if (value === undefined) {
params[key] = null;
}
});
const endpoint = `/datasource/external_metadata_by_name/?q=${rison.encode_uri(
params,
)}`;
const { json } = await SupersetClient.get({ endpoint });
return json;
}