diff --git a/frontend/amundsen_application/static/js/components/OwnerEditor/index.tsx b/frontend/amundsen_application/static/js/components/OwnerEditor/index.tsx
index 25773b19d0..5a0240accf 100644
--- a/frontend/amundsen_application/static/js/components/OwnerEditor/index.tsx
+++ b/frontend/amundsen_application/static/js/components/OwnerEditor/index.tsx
@@ -9,9 +9,11 @@ import AvatarLabel, { AvatarLabelProps } from 'components/AvatarLabel';
import LoadingSpinner from 'components/LoadingSpinner';
import { ResourceType, UpdateMethod, UpdateOwnerPayload } from 'interfaces';
import { logClick, logAction } from 'utils/analytics';
-import { getUserIdLabel } from 'config/config-utils';
+import { getUserIdLabel, getOwnersSectionConfig } from 'config/config-utils';
import { EditableSectionChildProps } from 'components/EditableSection';
+import InfoButton from 'components/InfoButton';
+import { OwnerCategory } from 'interfaces/OwnerCategory';
import * as Constants from './constants';
@@ -33,6 +35,7 @@ export interface ComponentProps {
interface OwnerAvatarLabelProps extends AvatarLabelProps {
link?: string;
isExternal?: boolean;
+ additionalOwnerInfo?: any;
}
export interface StateFromProps {
@@ -238,21 +241,31 @@ export class OwnerEditor extends React.Component<
);
};
- render() {
- const { isEditing, readOnly, resourceType } = this.props;
- const { errorText, itemProps } = this.state;
- const hasItems = Object.keys(itemProps).length > 0;
+ renderOwnersSection = (section: OwnerCategory | null) => {
+ const { resourceType } = this.props;
+ const { itemProps } = this.state;
- if (errorText) {
- return (
-
- {errorText}
-
+ // check if rendering an owner category that lacks any entries
+ let isEmptySection = false;
+
+ if (section) {
+ isEmptySection = Object.keys(itemProps).every(
+ (key) =>
+ itemProps[key].additionalOwnerInfo.owner_category.toLowerCase() !==
+ section.label.toLowerCase()
);
}
- const ownerList = hasItems ? (
+ return (
+ {section ? (
+
+ {section.label}
+
+
+ ) : null}
+ {isEmptySection ? None known : null}
+
{Object.keys(itemProps).map((key) => {
const owner = itemProps[key];
const avatarLabel = React.createElement(AvatarLabel, owner);
@@ -274,7 +287,12 @@ export class OwnerEditor extends React.Component<
{avatarLabel}
);
- } else {
+ } else if (
+ (section && // if section, only render owner that matches category
+ section.label.toLowerCase() ===
+ owner.additionalOwnerInfo.owner_category.toLowerCase()) ||
+ !section
+ ) {
listItem = (
{listItem};
})}
- ) : null;
+ );
+ };
+
+ renderOwnersList = () => {
+ const sections = getOwnersSectionConfig().categories;
+
+ if (sections.length > 0) {
+ return (
+
+ {sections.map((section) => this.renderOwnersSection(section))}
+
+ );
+ }
+
+ return this.renderOwnersSection(null);
+ };
+
+ render() {
+ const { isEditing, readOnly } = this.props;
+ const { errorText, itemProps } = this.state;
+ const hasItems = Object.keys(itemProps).length > 0;
+
+ if (errorText) {
+ return (
+
+ {errorText}
+
+ );
+ }
+
+ const ownerList = hasItems ? this.renderOwnersList() : null;
return (
diff --git a/frontend/amundsen_application/static/js/components/OwnerEditor/styles.scss b/frontend/amundsen_application/static/js/components/OwnerEditor/styles.scss
index c3b15cefcc..2068b0bba9 100644
--- a/frontend/amundsen_application/static/js/components/OwnerEditor/styles.scss
+++ b/frontend/amundsen_application/static/js/components/OwnerEditor/styles.scss
@@ -112,3 +112,12 @@
}
}
}
+
+ul.component-list {
+ margin-bottom: $spacer-1;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/amundsen_application/static/js/config/config-default.ts b/frontend/amundsen_application/static/js/config/config-default.ts
index 7240530d40..5bcba4ec5f 100644
--- a/frontend/amundsen_application/static/js/config/config-default.ts
+++ b/frontend/amundsen_application/static/js/config/config-default.ts
@@ -125,6 +125,9 @@ const configDefault: AppConfig = {
maxNestedColumns: 500,
},
numberFormat: null,
+ ownersSection: {
+ categories: [],
+ },
productTour: {},
resourceConfig: {
[ResourceType.dashboard]: {
diff --git a/frontend/amundsen_application/static/js/config/config-types.ts b/frontend/amundsen_application/static/js/config/config-types.ts
index c39cbf237d..cc3ce2443b 100644
--- a/frontend/amundsen_application/static/js/config/config-types.ts
+++ b/frontend/amundsen_application/static/js/config/config-types.ts
@@ -5,6 +5,7 @@ import {
SortCriteria,
} from '../interfaces';
+import { OwnerCategory } from '../interfaces/OwnerCategory';
import { Widget } from '../interfaces/Widgets';
/**
@@ -36,6 +37,7 @@ export interface AppConfig {
navTheme: 'dark' | 'light';
nestedColumns: NestedColumnConfig;
numberFormat: NumberFormatConfig | null;
+ ownersSection: OwnersSectionConfig;
productTour: ToursConfig;
resourceConfig: ResourceConfig;
searchPagination: SearchPagination;
@@ -84,6 +86,7 @@ export interface AppConfigCustom {
productTour?: ToursConfig;
searchPagination?: SearchPagination;
homePageWidgets?: HomePageWidgetsConfig;
+ ownersSection?: OwnersSectionConfig;
}
/**
@@ -604,3 +607,7 @@ export interface HomePageWidgetsConfig {
*/
widgets: Widget[];
}
+
+export interface OwnersSectionConfig {
+ categories: OwnerCategory[];
+}
diff --git a/frontend/amundsen_application/static/js/config/config-utils.ts b/frontend/amundsen_application/static/js/config/config-utils.ts
index 1cc3e65d5e..a8036f73a9 100644
--- a/frontend/amundsen_application/static/js/config/config-utils.ts
+++ b/frontend/amundsen_application/static/js/config/config-utils.ts
@@ -14,6 +14,7 @@ import {
HomePageWidgetsConfig,
TableLineageConfig,
DateFormatConfig,
+ OwnersSectionConfig,
} from './config-types';
const DEFAULT_DYNAMIC_NOTICES_ENABLED_FLAG = false;
@@ -646,3 +647,10 @@ export function getUserIdLabel(): string {
export function getDateConfiguration(): DateFormatConfig {
return AppConfig.date;
}
+
+/**
+ * Returns the resource owners section configuration
+ */
+export function getOwnersSectionConfig(): OwnersSectionConfig {
+ return AppConfig.ownersSection;
+}
diff --git a/frontend/amundsen_application/static/js/interfaces/OwnerCategory.ts b/frontend/amundsen_application/static/js/interfaces/OwnerCategory.ts
new file mode 100644
index 0000000000..ba83710729
--- /dev/null
+++ b/frontend/amundsen_application/static/js/interfaces/OwnerCategory.ts
@@ -0,0 +1,7 @@
+// Copyright Contributors to the Amundsen project.
+// SPDX-License-Identifier: Apache-2.0
+
+export interface OwnerCategory {
+ label: string;
+ definition?: string;
+}
diff --git a/frontend/amundsen_application/static/js/interfaces/User.ts b/frontend/amundsen_application/static/js/interfaces/User.ts
index d3fd78734e..588bbf91bb 100644
--- a/frontend/amundsen_application/static/js/interfaces/User.ts
+++ b/frontend/amundsen_application/static/js/interfaces/User.ts
@@ -6,6 +6,7 @@ export interface User {
email: string;
profile_url: string;
user_id: string;
+ other_key_values?: Record;
}
// Not a good name, not sure if we can consolidate yet
diff --git a/frontend/amundsen_application/static/js/pages/TableDetailPage/TableOwnerEditor/index.tsx b/frontend/amundsen_application/static/js/pages/TableDetailPage/TableOwnerEditor/index.tsx
index cc8eeeb0c1..a98a8e6023 100644
--- a/frontend/amundsen_application/static/js/pages/TableDetailPage/TableOwnerEditor/index.tsx
+++ b/frontend/amundsen_application/static/js/pages/TableDetailPage/TableOwnerEditor/index.tsx
@@ -19,9 +19,11 @@ export const mapStateToProps = (state: GlobalState) => {
const ownerObj = state.tableMetadata.tableOwners.owners;
const items = Object.keys(ownerObj).reduce((obj, ownerId) => {
// eslint-disable-next-line @typescript-eslint/naming-convention
- const { profile_url, user_id, display_name } = ownerObj[ownerId];
+ const { profile_url, user_id, display_name, other_key_values } =
+ ownerObj[ownerId];
let profileLink = profile_url;
let isExternalLink = true;
+ const additionalOwnerInfo = other_key_values;
if (indexUsersEnabled()) {
isExternalLink = false;
@@ -32,6 +34,7 @@ export const mapStateToProps = (state: GlobalState) => {
label: display_name,
link: profileLink,
isExternal: isExternalLink,
+ additionalOwnerInfo,
};
return obj;