Unverified Commit 9bd7c7bc authored by Diksha Thakur's avatar Diksha Thakur Committed by GitHub

feat: Added GraphQL source to gschema views (#582)

* Added GraphQL source to gschema views
Signed-off-by: 's avatardikshathakur3119 <dikshathakur@lyft.com>

* Added Table Source config
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Deleted gql icon file
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Add unit test cases for SourceLink component
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Run betterer and lint check
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Removed not required null test
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Restructured configurations
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* fix utils functions and linting
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Add null check and betterer results file
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Added documentation
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Code cleanup
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Add new type for description source configuration
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Fix unit test's descriptions
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Update display name on edit table/column description button
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>

* Update betterer result
Signed-off-by: 's avatardikshathakur3119 <dikshathakur3119@gmail.com>
parent e4135b59
......@@ -86,6 +86,9 @@ exports[`strict null compilation`] = {
[141, 17, 16, "Object is possibly \'undefined\'.", "3451845569"],
[257, 30, 34, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "3967943985"]
],
"js/components/TableDetail/SourceLink/index.spec.tsx:3683846951": [
[39, 21, 100, "Object is possibly \'null\'.", "1316242242"]
],
"js/components/TableDetail/TableDashboardResourceList/index.tsx:3147978263": [
[64, 2, 15, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(state: GlobalState) => { dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to parameter of type \'MapStateToPropsParam<StateFromProps, OwnProps, {}>\'.\\n Type \'(state: GlobalState) => { dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to type \'MapStateToPropsFactory<StateFromProps, OwnProps, {}>\'.\\n Type \'{ dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to type \'MapStateToProps<StateFromProps, OwnProps, {}>\'.\\n Type \'{ dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' provides no match for the signature \'(state: {}, ownProps: OwnProps): StateFromProps\'.", "1389821531"]
],
......@@ -104,19 +107,19 @@ exports[`strict null compilation`] = {
"js/components/TableDetail/index.spec.tsx:2169788066": [
[32, 4, 8, "Argument of type \'Partial<Location<{} | null | undefined>> | undefined\' is not assignable to parameter of type \'Partial<Location<{} | null | undefined>>\'.\\n Type \'undefined\' is not assignable to type \'Partial<Location<{} | null | undefined>>\'.", "2700611480"]
],
"js/components/TableDetail/index.tsx:173712209": [
[152, 10, 13, "Type \'null\' is not assignable to type \'((newValue: string, onSuccess?: (() => any) | undefined, onFailure?: (() => any) | undefined) => void) | undefined\'.", "67794331"],
[163, 6, 7, "Type \'Element\' is not assignable to type \'never\'.", "3716929964"],
[170, 6, 3, "Type \'string\' is not assignable to type \'never\'.", "193424690"],
[171, 6, 5, "Type \'string\' is not assignable to type \'never\'.", "183222373"],
[181, 8, 7, "Type \'Element\' is not assignable to type \'never\'.", "3716929964"],
[182, 11, 26, "Type \'{ itemsPerPage: number; source: string; }\' is missing the following properties from type \'Readonly<Pick<TableDashboardResourceListProps, \\"source\\" | \\"dashboards\\" | \\"isLoading\\" | \\"errorText\\" | \\"itemsPerPage\\"> & OwnProps>\': dashboards, isLoading, errorText", "2224258167"],
[187, 8, 3, "Type \'string\' is not assignable to type \'never\'.", "193424690"],
[188, 8, 5, "Type \'string | Element\' is not assignable to type \'never\'.\\n Type \'string\' is not assignable to type \'never\'.", "183222373"],
[260, 16, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "3817619378"],
[302, 20, 35, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "4249007202"],
[316, 20, 36, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "2770872537"],
[321, 16, 36, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "2776557981"]
"js/components/TableDetail/index.tsx:1105490806": [
[153, 10, 13, "Type \'null\' is not assignable to type \'((newValue: string, onSuccess?: (() => any) | undefined, onFailure?: (() => any) | undefined) => void) | undefined\'.", "67794331"],
[164, 6, 7, "Type \'Element\' is not assignable to type \'never\'.", "3716929964"],
[171, 6, 3, "Type \'string\' is not assignable to type \'never\'.", "193424690"],
[172, 6, 5, "Type \'string\' is not assignable to type \'never\'.", "183222373"],
[182, 8, 7, "Type \'Element\' is not assignable to type \'never\'.", "3716929964"],
[183, 11, 26, "Type \'{ itemsPerPage: number; source: string; }\' is missing the following properties from type \'Readonly<Pick<TableDashboardResourceListProps, \\"source\\" | \\"dashboards\\" | \\"isLoading\\" | \\"errorText\\" | \\"itemsPerPage\\"> & OwnProps>\': dashboards, isLoading, errorText", "2224258167"],
[188, 8, 3, "Type \'string\' is not assignable to type \'never\'.", "193424690"],
[189, 8, 5, "Type \'string | Element\' is not assignable to type \'never\'.\\n Type \'string\' is not assignable to type \'never\'.", "183222373"],
[263, 16, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "3817619378"],
[305, 20, 35, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "4249007202"],
[319, 20, 36, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "2770872537"],
[324, 16, 36, "Argument of type \'ProgrammaticDescription[] | undefined\' is not assignable to parameter of type \'ProgrammaticDescription[]\'.\\n Type \'undefined\' is not assignable to type \'ProgrammaticDescription[]\'.", "2776557981"]
],
"js/components/common/Announcements/AnnouncementsList/index.spec.tsx:1710887993": [
[95, 23, 124, "Object is possibly \'null\'.", "4248337497"]
......@@ -229,7 +232,7 @@ exports[`strict null compilation`] = {
[93, 4, 11, "Type \'Tag[]\' is not assignable to type \'never[]\'.", "255414113"],
[98, 4, 9, "Type \'Tag[]\' is not assignable to type \'never[]\'.", "3803340896"]
],
"js/config/config-utils.ts:1181911782": [
"js/config/config-utils.ts:1027600130": [
[86, 4, 25, "\'style\' is specified more than once, so this usage will be overwritten.", "1214862559"]
],
"js/config/index.spec.ts:696974304": [
......
......@@ -18,15 +18,14 @@ $loading-curve: cubic-bezier(0.45, 0, 0.15, 1);
.is-shimmer-animated {
animation: $loading-duration shimmer $loading-curve infinite;
background-image:
linear-gradient(
to right,
$gray10 0%,
$gray10 33%,
$gray5 50%,
$gray10 67%,
$gray10 100%
);
background-image: linear-gradient(
to right,
$gray10 0%,
$gray10 33%,
$gray5 50%,
$gray10 67%,
$gray10 100%
);
background-repeat: no-repeat;
background-size: 300% 100%;
}
......@@ -60,8 +60,8 @@ span.icon {
}
img.icon {
/*DEPRECATED: follow behavior above to generate
icons*/
/* DEPRECATED: follow behavior above to generate
icons */
background-color: $icon-bg;
border: none;
height: $icon-size;
......
......@@ -20,6 +20,7 @@
.last-run-state {
margin-top: $spacer-1;
.status {
@extend %text-body-w2;
......
import * as React from 'react';
import { mount } from 'enzyme';
import SourceLink, { SourceLinkProps } from '.';
import AvatarLabel from 'components/common/AvatarLabel';
import AppConfig from 'config/config';
import { ResourceType } from 'interfaces/Resources';
const setup = (propOverrides?: Partial<SourceLinkProps>) => {
const props = {
tableSource: {
source_type: 'xyz',
source: 'www.xyz.com',
},
...propOverrides,
};
const wrapper = mount<typeof SourceLink>(<SourceLink {...props} />);
return { props, wrapper };
};
describe('render SourceLink', () => {
describe('render', () => {
it('should render without issues', () => {
expect(() => {
setup();
}).not.toThrow();
});
it('should render icon and source link', () => {
const { wrapper } = setup();
const expected = 1;
const actual = wrapper.find('.header-link').length;
expect(actual).toEqual(expected);
});
it('should render correct source link', () => {
const { wrapper } = setup();
const expected = 'www.xyz.com';
const actual = wrapper
.find('.header-link')
.getDOMNode()
.attributes.getNamedItem('href').value;
expect(actual).toEqual(expected);
});
});
describe('when supported description sources present in resource config', () => {
beforeAll(() => {
AppConfig.resourceConfig = {
[ResourceType.table]: {
displayName: 'Tables',
supportedDescriptionSources: {
xyz: {
displayName: 'XYZ',
iconPath: 'images/xyz.png',
},
abc: {
displayName: 'ABC',
iconPath: 'images/abc.png',
},
},
},
[ResourceType.dashboard]: {
displayName: 'Dashboards',
},
[ResourceType.user]: {
displayName: 'Users',
},
};
});
it('should render AvatarLabel', () => {
const { wrapper } = setup();
const expected = 1;
const actual = wrapper.find(AvatarLabel).length;
expect(actual).toEqual(expected);
});
it('should render display name and icon path present in configurations', () => {
const { wrapper } = setup();
const expected = { label: 'XYZ', src: 'images/xyz.png' };
const actual = wrapper.find(AvatarLabel).props();
expect(actual).toMatchObject(expected);
});
it('should render empty icon path and source type as display name', () => {
const { wrapper } = setup({
tableSource: {
source_type: 'foo',
source: 'www.bar.xz',
},
});
const expected = { label: 'foo', src: '' };
const actual = wrapper.find(AvatarLabel).props();
expect(actual).toMatchObject(expected);
});
});
});
......@@ -3,6 +3,10 @@
import * as React from 'react';
import {
getDescriptionSourceDisplayName,
getDescriptionSourceIconPath,
} from 'config/config-utils';
import { logClick } from 'ducks/utilMethods';
import AvatarLabel from 'components/common/AvatarLabel';
import { TableSource } from 'interfaces';
......@@ -16,8 +20,10 @@ const SourceLink: React.FC<SourceLinkProps> = ({
}: SourceLinkProps) => {
if (tableSource === null || tableSource.source === null) return null;
const image =
tableSource.source_type === 'github' ? '/static/images/github.png' : '';
const image = getDescriptionSourceIconPath(tableSource.source_type);
const displayName = getDescriptionSourceDisplayName(tableSource.source_type);
return (
<a
className="header-link"
......@@ -27,7 +33,10 @@ const SourceLink: React.FC<SourceLinkProps> = ({
target="_blank"
rel="noreferrer"
>
<AvatarLabel label={tableSource.source_type} src={image} />
<AvatarLabel
label={getDescriptionSourceDisplayName(tableSource.source_type)}
src={getDescriptionSourceIconPath(tableSource.source_type)}
/>
</a>
);
};
......
......@@ -12,6 +12,7 @@ import { getTableData } from 'ducks/tableMetadata/reducer';
import { GetTableDataRequest } from 'ducks/tableMetadata/types';
import {
getDescriptionSourceDisplayName,
getMaxLength,
getSourceIconClass,
indexDashboardsEnabled,
......@@ -207,7 +208,9 @@ export class TableDetail extends React.Component<
} else {
const data = tableData;
const editText = data.source
? `${EDIT_DESC_TEXT} ${data.source.source_type}`
? `${EDIT_DESC_TEXT} ${getDescriptionSourceDisplayName(
data.source.source_type
)}`
: '';
const editUrl = data.source ? data.source.source : '';
......
......@@ -38,38 +38,34 @@
.badge-overlay-primary {
&:hover,
&:focus {
background-color:
rgba(
$color: $badge-overlay,
$alpha: $badge-opacity-light
);
background-color: rgba(
$color: $badge-overlay,
$alpha: $badge-opacity-light
);
}
&:active {
background-color:
rgba(
$color: $badge-overlay,
$alpha: $badge-pressed-light
);
background-color: rgba(
$color: $badge-overlay,
$alpha: $badge-pressed-light
);
}
}
.badge-overlay-warning {
&:hover,
&:focus {
background-color:
rgba(
$color: $badge-overlay,
$alpha: $badge-opacity-dark
);
background-color: rgba(
$color: $badge-overlay,
$alpha: $badge-opacity-dark
);
}
&:active {
background-color:
rgba(
$color: $badge-overlay,
$alpha: $badge-pressed-dark
);
background-color: rgba(
$color: $badge-overlay,
$alpha: $badge-pressed-dark
);
}
}
}
......@@ -21,10 +21,9 @@ $shimmer-loader-tag-min-width: 50;
@each $item in $shimmer-loader-items {
.shimmer-tag-loader-item--#{$item} {
width:
(
width: (
random($shimmer-loader-tag-max-width - $shimmer-loader-tag-min-width) +
$shimmer-loader-tag-min-width
$shimmer-loader-tag-min-width
) +
px;
}
......
......@@ -154,6 +154,12 @@ const configDefault: AppConfig = {
type: FilterType.INPUT_SELECT,
},
],
supportedDescriptionSources: {
github: {
displayName: 'Github',
iconPath: '/static/images/github.png',
},
},
},
[ResourceType.user]: {
displayName: 'People',
......
......@@ -122,6 +122,13 @@ type SourcesConfig = {
};
};
/**
* Configures the UI for a given table description source
*/
type DescriptionSourceConfig = {
[id: string]: { displayName: string; iconPath: string };
};
/**
* Base interface for all possible ResourceConfig objects
*
......@@ -134,6 +141,10 @@ interface BaseResourceConfig {
supportedSources?: SourcesConfig;
}
interface TableResourceConfig extends BaseResourceConfig {
supportedDescriptionSources?: DescriptionSourceConfig;
}
export enum BadgeStyle {
DANGER = 'negative',
DEFAULT = 'neutral',
......@@ -174,7 +185,7 @@ interface DateFormatConfig {
*/
interface ResourceConfig {
[ResourceType.dashboard]: BaseResourceConfig;
[ResourceType.table]: BaseResourceConfig;
[ResourceType.table]: TableResourceConfig;
[ResourceType.user]: BaseResourceConfig;
}
......
import AppConfig from 'config/config';
import { BadgeStyleConfig, BadgeStyle } from 'config/config-types';
import { BadgeStyle, BadgeStyleConfig } from 'config/config-types';
import { TableMetadata } from 'interfaces/TableMetadata';
import { FilterConfig, LinkConfig } from './config-types';
......@@ -205,3 +205,41 @@ export function generateExploreUrl(tableData: TableMetadata): string {
export function getMaxLength(key: string) {
return AppConfig.editableText[key];
}
/**
* Returns the display name for a given description source id for a given resource type.
* If a configuration or display name does not exist for the given description source id, the id
* is returned.
*/
export function getDescriptionSourceDisplayName(sourceId: string): string {
const config = AppConfig.resourceConfig[ResourceType.table];
if (
config &&
config.supportedDescriptionSources &&
config.supportedDescriptionSources[sourceId] &&
config.supportedDescriptionSources[sourceId].displayName
) {
return config.supportedDescriptionSources[sourceId].displayName;
}
return sourceId;
}
/**
* Returns the icon path for a given description source id for a given resource type.
* If a configuration does not exist for the given description source id, empty string
* is returned.
*/
export function getDescriptionSourceIconPath(sourceId: string): string {
const config = AppConfig.resourceConfig[ResourceType.table];
if (
config &&
config.supportedDescriptionSources &&
config.supportedDescriptionSources[sourceId] &&
config.supportedDescriptionSources[sourceId].iconPath
) {
return config.supportedDescriptionSources[sourceId].iconPath;
}
return '';
}
......@@ -101,6 +101,14 @@ You can configure custom icons to be used throughout the UI when representing en
You can configure a specific display name to be used throughout the UI when representing entities from particular sources. On the `supportedSources` object, add an entry with the `id` used to reference that source and map to an object that specified the `displayName` for that source.
### Table Configuration
To configure Table related features we have created a new resource configuration `TableResourceConfig` which extends `BaseResourceConfig`. In addition to the configurations explained above it also supports `supportedDescriptionSources`.
#### Supported Description Sources
A table resource may have a source of table and column description attached to it. We can customize it by using `supportedDescriptionSources` object which is an optional object.
This object has `displayName` and `iconPath`, which can be used throughout the UI to represent a particular description source. See example in [config-default.ts](https://github.com/lyft/amundsenfrontendlibrary/blob/master/amundsen_application/static/js/config/config-default.ts).
For configuring new description sources, add an entry in `supportedDescriptionSources` with the `id` used to reference that source and add desired display name and icon for it.
## Table Lineage
_TODO: Please add doc_
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment