diff --git a/frontend/src/metabase-lib/lib/Dimension.ts b/frontend/src/metabase-lib/lib/Dimension.ts index a3d491da9adff43466064ad5b0ab6d486c8b1507..21acf7c02b092802dd5d32cab758cdd6ee18beae 100644 --- a/frontend/src/metabase-lib/lib/Dimension.ts +++ b/frontend/src/metabase-lib/lib/Dimension.ts @@ -583,6 +583,12 @@ export default class Dimension { return this.withoutTemporalBucketing().withoutBinning(); } + isValidFKRemappingTarget() { + return !( + this.defaultDimension() instanceof FieldDimension && this.temporalUnit() + ); + } + /** * The name to be shown when this dimension is being displayed as a sub-dimension of another. * diff --git a/frontend/src/metabase-lib/lib/metadata/Field.ts b/frontend/src/metabase-lib/lib/metadata/Field.ts index 31b95ed541917cf48797ec07f0af186c2dd88151..c2a100a9f26ad1622bfabab437a2beeb63b0a486 100644 --- a/frontend/src/metabase-lib/lib/metadata/Field.ts +++ b/frontend/src/metabase-lib/lib/metadata/Field.ts @@ -440,6 +440,22 @@ class FieldInner extends Base { }); } + remappingOptions = () => { + const table = this.table; + if (!table) { + return []; + } + + const { fks } = table.query().fieldOptions(); + return fks + .filter(({ field }) => field.id === this.id) + .map(({ field, dimension, dimensions }) => ({ + field, + dimension, + dimensions: dimensions.filter(d => d.isValidFKRemappingTarget()), + })); + }; + clone(fieldMetadata) { if (fieldMetadata instanceof Field) { throw new Error("`fieldMetadata` arg must be a plain object"); diff --git a/frontend/src/metabase/admin/datamodel/components/FieldRemapping.jsx b/frontend/src/metabase/admin/datamodel/components/FieldRemapping.jsx index 65ded2d0d9595171c9866046eece38492e54f129..7a482f31f801f264ccdd8e7137e57e58e4e32892 100644 --- a/frontend/src/metabase/admin/datamodel/components/FieldRemapping.jsx +++ b/frontend/src/metabase/admin/datamodel/components/FieldRemapping.jsx @@ -12,7 +12,7 @@ import ButtonWithStatus from "metabase/components/ButtonWithStatus"; import * as MetabaseAnalytics from "metabase/lib/analytics"; import Dimension, { FieldDimension } from "metabase-lib/lib/Dimension"; -import Question from "metabase-lib/lib/Question"; +import { isEntityName, isFK } from "metabase-lib/lib/types/utils/isa"; import SelectSeparator from "../components/SelectSeparator"; import { FieldMappingContainer, @@ -57,9 +57,9 @@ export default class FieldRemapping extends React.Component { throw new Error(t`Unrecognized mapping type`); }; - hasForeignKeys = () => - this.props.field.semantic_type === "type/FK" && - this.getForeignKeys().length > 0; + hasForeignKeys = () => { + return isFK(this.props.field) && this.getForeignKeys().length > 0; + }; hasMappableNumeralValues = () => { const { field } = this.props; @@ -95,10 +95,7 @@ export default class FieldRemapping extends React.Component { const fkTargetFields = fks[0] && fks[0].dimensions.map(dim => dim.field()); if (fkTargetFields) { - // TODO Atte Keinänen 7/11/17: Should there be `isName(field)` in Field.js? - const nameField = fkTargetFields.find( - field => field.semantic_type === "type/Name", - ); + const nameField = fkTargetFields.find(field => isEntityName(field)); return nameField ? nameField.id : null; } else { throw new Error( @@ -217,34 +214,9 @@ export default class FieldRemapping extends React.Component { return updateFieldValues({ id: field.id }, Array.from(remappings)); }; - // TODO Atte Keinänen 7/11/17: Should we have stricter criteria for valid remapping targets? - isValidFKRemappingTarget = dimension => - !( - dimension.defaultDimension() instanceof FieldDimension && - dimension.temporalUnit() - ); - getForeignKeys = () => { - const { table, field } = this.props; - - // this method has a little odd structure due to using fieldOptions(); basically filteredFKs should - // always be an array with a single value - const metadata = table.metadata; - const fieldOptions = Question.create({ - metadata, - databaseId: table.db.id, - tableId: table.id, - }) - .query() - .fieldOptions(); - const unfilteredFks = fieldOptions.fks; - const filteredFKs = unfilteredFks.filter(fk => fk.field.id === field.id); - - return filteredFKs.map(filteredFK => ({ - field: filteredFK.field, - dimension: filteredFK.dimension, - dimensions: filteredFK.dimensions.filter(this.isValidFKRemappingTarget), - })); + const { field, metadata } = this.props; + return metadata.field(field.id).remappingOptions(); }; onFkPopoverDismiss = () => { diff --git a/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx b/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx index b1b808e1c2c40321dbca13e3e0135c02084953f8..432fba91b1e9a906a97ccf185388a9876a8fdde9 100644 --- a/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx +++ b/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx @@ -352,6 +352,7 @@ const FieldGeneralPane = ({ field={field} table={table} fields={metadata.fields} + metadata={metadata} fieldsError={fieldsError} updateFieldProperties={onUpdateFieldProperties} updateFieldValues={onUpdateFieldValues}