From 983f8bf6a741cbc2bba73b9bd3fc7832e2c14fa7 Mon Sep 17 00:00:00 2001 From: Jake Bassett Date: Thu, 18 Mar 2021 16:51:24 -0700 Subject: [PATCH 1/5] feat: summary list component --- .../assets-library/assets/icons/external.svg | 4 + .../assets-library/assets/icons/internal.svg | 4 + .../src/icons/icon-library.module.ts | 2 + .../assets-library/src/icons/icon-type.ts | 2 + projects/components/src/public-api.ts | 94 ++++++++++--------- .../src/summary-list/summary-list-api.ts | 6 ++ .../summary-list/summary-list.component.scss | 43 +++++++++ .../summary-list/summary-list.component.ts | 44 +++++++++ .../src/summary-list/summary-list.module.ts | 14 +++ .../cartesian/d3/chart/cartesian-chart.ts | 4 +- 10 files changed, 171 insertions(+), 46 deletions(-) create mode 100644 projects/assets-library/assets/icons/external.svg create mode 100644 projects/assets-library/assets/icons/internal.svg create mode 100644 projects/components/src/summary-list/summary-list-api.ts create mode 100644 projects/components/src/summary-list/summary-list.component.scss create mode 100644 projects/components/src/summary-list/summary-list.component.ts create mode 100644 projects/components/src/summary-list/summary-list.module.ts diff --git a/projects/assets-library/assets/icons/external.svg b/projects/assets-library/assets/icons/external.svg new file mode 100644 index 000000000..40f1e04e2 --- /dev/null +++ b/projects/assets-library/assets/icons/external.svg @@ -0,0 +1,4 @@ + + + + diff --git a/projects/assets-library/assets/icons/internal.svg b/projects/assets-library/assets/icons/internal.svg new file mode 100644 index 000000000..fe628a42f --- /dev/null +++ b/projects/assets-library/assets/icons/internal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/projects/assets-library/src/icons/icon-library.module.ts b/projects/assets-library/src/icons/icon-library.module.ts index 2ef4d6606..5aac4efd2 100644 --- a/projects/assets-library/src/icons/icon-library.module.ts +++ b/projects/assets-library/src/icons/icon-library.module.ts @@ -43,6 +43,7 @@ const iconsRootPath = 'assets/icons'; { key: IconType.Edge, url: `${iconsRootPath}/edge.svg` }, { key: IconType.ExpandAll, url: `${iconsRootPath}/expand-all.svg` }, { key: IconType.Expanded, url: `${iconsRootPath}/minus-circle.svg` }, + { key: IconType.External, url: `${iconsRootPath}/external.svg` }, { key: IconType.Eye, url: `${iconsRootPath}/eye.svg` }, { key: IconType.FileCode, url: `${iconsRootPath}/file-code.svg` }, { key: IconType.Filter, url: `${iconsRootPath}/filter.svg` }, @@ -52,6 +53,7 @@ const iconsRootPath = 'assets/icons'; { key: IconType.IpAddress, url: `${iconsRootPath}/ip-address.svg` }, { key: IconType.Info, url: `${iconsRootPath}/info.svg` }, { key: IconType.Infrastructure, url: `${iconsRootPath}/infrastructure.svg` }, + { key: IconType.Internal, url: `${iconsRootPath}/internal.svg` }, { key: IconType.Java, url: `${iconsRootPath}/java.svg` }, { key: IconType.KnowledgeGraph, url: `${iconsRootPath}/knowledge-graph.svg` }, { key: IconType.Kong, url: `${iconsRootPath}/kong.svg` }, diff --git a/projects/assets-library/src/icons/icon-type.ts b/projects/assets-library/src/icons/icon-type.ts index fd13b4c72..5da912c4e 100644 --- a/projects/assets-library/src/icons/icon-type.ts +++ b/projects/assets-library/src/icons/icon-type.ts @@ -43,6 +43,7 @@ export const enum IconType { Expand = 'launch', ExpandAll = 'svg:expand-all', Expanded = 'svg:minus-square', + External = 'svg:external', Eye = 'svg:eye', Favorite = 'favorite_border', FileCode = 'svg:file-code', @@ -55,6 +56,7 @@ export const enum IconType { IpAddress = 'svg:ip-address', Info = 'svg:info', Infrastructure = 'svg:infrastructure', + Internal = 'svg:internal', Java = 'svg:java', KeyboardArrowLeft = 'keyboard_arrow_left', KeyboardBackspace = 'keyboard_backspace', diff --git a/projects/components/src/public-api.ts b/projects/components/src/public-api.ts index 40e414f03..1813880a5 100644 --- a/projects/components/src/public-api.ts +++ b/projects/components/src/public-api.ts @@ -2,6 +2,10 @@ * Public API Surface of components */ +// Beta tag +export * from './beta-tag/beta-tag.component'; +export * from './beta-tag/beta-tag.module'; + // Breadcrumbs export * from './breadcrumbs/breadcrumbs.component'; export * from './breadcrumbs/breadcrumbs.module'; @@ -21,6 +25,10 @@ export * from './combo-box/combo-box.module'; export * from './combo-box/combo-box.component'; export * from './combo-box/combo-box-api'; +// Confirmation +export * from './confirmation/confirmation.module'; +export * from './confirmation/confirmation.service'; + // Content Holder export * from './content/content-holder'; @@ -37,18 +45,27 @@ export * from './copy-to-clipboard/copy-to-clipboard.module'; export * from './copy-shareable-link-to-clipboard/copy-shareable-link-to-clipboard.component'; export * from './copy-shareable-link-to-clipboard/copy-shareable-link-to-clipboard.module'; -// Open in new tab -export * from './open-in-new-tab/open-in-new-tab.component'; -export * from './open-in-new-tab/open-in-new-tab.module'; - // Date Time picker export * from './datetime-picker/datetime-picker.component'; export * from './datetime-picker/datetime-picker.module'; +// Description +export * from './description/description.component'; +export * from './description/description.module'; + // Divider export * from './divider/divider.component'; export * from './divider/divider.module'; +// Dropdown menu +export { MenuDropdownComponent } from './menu-dropdown/menu-dropdown.component'; +export { MenuItemComponent } from './menu-dropdown/menu-item/menu-item.component'; +export { MenuDropdownModule } from './menu-dropdown/menu-dropdown.module'; + +// Dynamic label +export * from './highlighted-label/highlighted-label.component'; +export * from './highlighted-label/highlighted-label.module'; + // Event Blocker export * from './event-blocker/event-blocker.component'; export * from './event-blocker/event-blocker.module'; @@ -83,6 +100,10 @@ export * from './filtering/filter-modal/in-filter-modal.component'; // Filter Parser export * from './filtering/filter/parser/filter-parser-lookup.service'; +// Greeting label +export { GreetingLabelModule } from './greeting-label/greeting-label.module'; +export { GreetingLabelComponent } from './greeting-label/greeting-label.component'; + // Header export * from './header/application/application-header.component'; export * from './header/application/application-header.module'; @@ -108,9 +129,9 @@ export { JsonViewerModule } from './viewer/json-viewer/json-viewer.module'; export * from './label/label.component'; export * from './label/label.module'; -// Dynamic label -export * from './highlighted-label/highlighted-label.component'; -export * from './highlighted-label/highlighted-label.module'; +// Label tag +export * from './label-tag/label-tag.component'; +export * from './label-tag/label-tag.module'; // Layout Change export { LayoutChangeTriggerDirective } from './layout/layout-change-trigger.directive'; @@ -142,6 +163,15 @@ export { LoadAsyncModule } from './load-async/load-async.module'; export { MessageDisplayComponent } from './message-display/message-display.component'; export { MessageDisplayModule } from './message-display/message-display.module'; +// Modal +export * from './modal/modal'; +export * from './modal/modal.module'; +export * from './modal/modal.service'; + +// Multi-select +export * from './multi-select/multi-select.component'; +export * from './multi-select/multi-select.module'; + // Navigable Tab export * from './tabs/navigable/navigable-tab'; export * from './tabs/navigable/navigable-tab-group.component'; @@ -152,6 +182,14 @@ export * from './tabs/navigable/navigable-tab.module'; export * from './not-found/not-found.component'; export * from './not-found/not-found.module'; +// Notification +export * from './notification/notification.service'; +export * from './notification/notification.module'; + +// Open in new tab +export * from './open-in-new-tab/open-in-new-tab.component'; +export * from './open-in-new-tab/open-in-new-tab.module'; + // Paginator export * from './paginator/page.event'; export * from './paginator/paginator.component'; @@ -187,15 +225,16 @@ export * from './select/select-control-option.component'; export * from './select/select.component'; export * from './select/select.module'; -// Multi-select -export * from './multi-select/multi-select.component'; -export * from './multi-select/multi-select.module'; - // Sequence export { SequenceSegment } from './sequence/sequence'; export * from './sequence/sequence-chart.component'; export * from './sequence/sequence-chart.module'; +// Summary List +export * from './summary-list/summary-list.module'; +export * from './summary-list/summary-list.component'; +export * from './summary-list/summary-list-api'; + // Overlay export { OverlayService } from './overlay/overlay.service'; export * from './overlay/overlay'; @@ -283,36 +322,3 @@ export { ToggleSwitchSize } from './toggle-switch/toggle-switch-size'; // Tooltip export { TooltipModule } from './tooltip/tooltip.module'; export { TooltipDirective } from './tooltip/tooltip.directive'; - -// Greeting label -export { GreetingLabelModule } from './greeting-label/greeting-label.module'; -export { GreetingLabelComponent } from './greeting-label/greeting-label.component'; - -// Dropdown menu -export { MenuDropdownComponent } from './menu-dropdown/menu-dropdown.component'; -export { MenuItemComponent } from './menu-dropdown/menu-item/menu-item.component'; -export { MenuDropdownModule } from './menu-dropdown/menu-dropdown.module'; - -// Beta tag -export * from './beta-tag/beta-tag.component'; -export * from './beta-tag/beta-tag.module'; - -// Label tag -export * from './label-tag/label-tag.component'; -export * from './label-tag/label-tag.module'; - -// Modal -export * from './modal/modal'; -export * from './modal/modal.module'; -export * from './modal/modal.service'; - -export * from './confirmation/confirmation.module'; -export * from './confirmation/confirmation.service'; - -// Notification -export * from './notification/notification.service'; -export * from './notification/notification.module'; - -// Description -export * from './description/description.component'; -export * from './description/description.module'; diff --git a/projects/components/src/summary-list/summary-list-api.ts b/projects/components/src/summary-list/summary-list-api.ts new file mode 100644 index 000000000..090d205b6 --- /dev/null +++ b/projects/components/src/summary-list/summary-list-api.ts @@ -0,0 +1,6 @@ +import { PrimitiveValue } from '@hypertrace/common'; + +export interface SummaryItem { + label: string; + value: PrimitiveValue | PrimitiveValue[]; +} diff --git a/projects/components/src/summary-list/summary-list.component.scss b/projects/components/src/summary-list/summary-list.component.scss new file mode 100644 index 000000000..fb2609b8b --- /dev/null +++ b/projects/components/src/summary-list/summary-list.component.scss @@ -0,0 +1,43 @@ +@import 'mixins'; + +.summary-list { + padding: 16px; + + .summary-header { + display: flex; + align-items: center; + padding-top: 4px; + padding-bottom: 16px; + border-bottom: 1px solid $gray-2; + + .summary-icon { + color: $gray-7; + padding-right: 8px; + } + + .summary-title { + @include body-2-medium($gray-7); + } + } + + .summary-value-title { + @include body-2-medium($gray-7); + display: block; + padding-top: 16px; + } + + .summary-value-list { + list-style-type: none; + margin: 0; + padding: 0; + + .summary-value { + @include body-2-regular($gray-7); + padding-top: 3px; + + &:first-child { + padding-top: 6px; + } + } + } +} diff --git a/projects/components/src/summary-list/summary-list.component.ts b/projects/components/src/summary-list/summary-list.component.ts new file mode 100644 index 000000000..830be3db0 --- /dev/null +++ b/projects/components/src/summary-list/summary-list.component.ts @@ -0,0 +1,44 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { IconType } from '@hypertrace/assets-library'; +import { PrimitiveValue } from '@hypertrace/common'; +import { startCase } from 'lodash-es'; +import { SummaryItem } from './summary-list-api'; + +@Component({ + selector: 'ht-summary-list', + styleUrls: ['./summary-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+
+ + +
+ + +
    +
  • None
  • +
  • {{ value }}
  • +
+
+
+ ` +}) +export class SummaryListComponent { + @Input() + public title?: string = 'External'; + + @Input() + public icon?: IconType = IconType.External; + + @Input() + public items?: SummaryItem[] = []; + + public getFormattedLabel(item: SummaryItem): string { + return startCase(item.label.trim().replace('-', ' ').replace('_', ' ').toLowerCase()); + } + + public getValuesArray(item: SummaryItem): PrimitiveValue[] { + return Array.isArray(item.value) ? item.value : [item.value]; + } +} diff --git a/projects/components/src/summary-list/summary-list.module.ts b/projects/components/src/summary-list/summary-list.module.ts new file mode 100644 index 000000000..273dc61b8 --- /dev/null +++ b/projects/components/src/summary-list/summary-list.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormattingModule } from '@hypertrace/common'; +import { IconModule } from '../icon/icon.module'; +import { LabelModule } from '../label/label.module'; +import { LoadAsyncModule } from '../load-async/load-async.module'; +import { SummaryListComponent } from './summary-list.component'; + +@NgModule({ + declarations: [SummaryListComponent], + exports: [SummaryListComponent], + imports: [CommonModule, LoadAsyncModule, FormattingModule, LabelModule, IconModule] +}) +export class SummaryListModule {} diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 55f9e120e..79b787686 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -439,11 +439,11 @@ export class DefaultCartesianChart implements CartesianChart { ]; this.allCartesianData = [ - ...this.allSeriesData, ...this.bands.map( band => new CartesianBand(this.d3Utils, this.domRenderer, band, this.scaleBuilder, this.getTooltipTrackingStrategy()) - ) + ), + ...this.allSeriesData ]; } From 472f652c60c2b73bde3a5da725f327ad40b8e5a4 Mon Sep 17 00:00:00 2001 From: Jake Bassett Date: Thu, 18 Mar 2021 17:23:43 -0700 Subject: [PATCH 2/5] fix: remove mock inputs --- .../components/src/summary-list/summary-list.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/components/src/summary-list/summary-list.component.ts b/projects/components/src/summary-list/summary-list.component.ts index 830be3db0..d85211592 100644 --- a/projects/components/src/summary-list/summary-list.component.ts +++ b/projects/components/src/summary-list/summary-list.component.ts @@ -26,10 +26,10 @@ import { SummaryItem } from './summary-list-api'; }) export class SummaryListComponent { @Input() - public title?: string = 'External'; + public title?: string; @Input() - public icon?: IconType = IconType.External; + public icon?: IconType; @Input() public items?: SummaryItem[] = []; From 5ac7f1ab63c77ba56f90c42adebd7ab200c53875 Mon Sep 17 00:00:00 2001 From: Jake Bassett Date: Mon, 22 Mar 2021 12:04:41 -0700 Subject: [PATCH 3/5] feat: startCase is smarter than I thought --- projects/components/src/summary-list/summary-list.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/components/src/summary-list/summary-list.component.ts b/projects/components/src/summary-list/summary-list.component.ts index d85211592..636ccd151 100644 --- a/projects/components/src/summary-list/summary-list.component.ts +++ b/projects/components/src/summary-list/summary-list.component.ts @@ -35,7 +35,7 @@ export class SummaryListComponent { public items?: SummaryItem[] = []; public getFormattedLabel(item: SummaryItem): string { - return startCase(item.label.trim().replace('-', ' ').replace('_', ' ').toLowerCase()); + return startCase(item.label.trim().toLowerCase()); } public getValuesArray(item: SummaryItem): PrimitiveValue[] { From f6e778db2e8298d45b667c43ed49297e1c149b8f Mon Sep 17 00:00:00 2001 From: Jake Bassett Date: Mon, 22 Mar 2021 13:06:22 -0700 Subject: [PATCH 4/5] feat: add test --- .../summary-list.component.test.ts | 32 +++++++++++++++++++ .../summary-list/summary-list.component.ts | 14 ++++---- 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 projects/components/src/summary-list/summary-list.component.test.ts diff --git a/projects/components/src/summary-list/summary-list.component.test.ts b/projects/components/src/summary-list/summary-list.component.test.ts new file mode 100644 index 000000000..41f47730d --- /dev/null +++ b/projects/components/src/summary-list/summary-list.component.test.ts @@ -0,0 +1,32 @@ +import { SummaryListComponent } from '@hypertrace/components'; +import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; + +describe('Summary List component', () => { + let spectator: Spectator; + + const createComponent = createComponentFactory({ + component: SummaryListComponent, + shallow: true, + declarations: [] + }); + + beforeEach(() => { + spectator = createComponent(); + }); + + test('formats label', () => { + expect(spectator.component.getFormattedLabel('TEST_UNDERSCORE')).toEqual('Test Underscore'); + expect(spectator.component.getFormattedLabel('TEST-DASH')).toEqual('Test Dash'); + expect(spectator.component.getFormattedLabel('Test_mixed-LABEL')).toEqual('Test Mixed Label'); + expect(spectator.component.getFormattedLabel('test MORE')).toEqual('Test More'); + }); + + test('gets value array', () => { + expect(spectator.component.getValuesArray(1)).toEqual([1]); + expect(spectator.component.getValuesArray([1])).toEqual([1]); + expect(spectator.component.getValuesArray('two')).toEqual(['two']); + expect(spectator.component.getValuesArray(['two', 'three'])).toEqual(['two', 'three']); + expect(spectator.component.getValuesArray(true)).toEqual([true]); + expect(spectator.component.getValuesArray([true, false])).toEqual([true, false]); + }); +}); diff --git a/projects/components/src/summary-list/summary-list.component.ts b/projects/components/src/summary-list/summary-list.component.ts index 636ccd151..6b9cc8785 100644 --- a/projects/components/src/summary-list/summary-list.component.ts +++ b/projects/components/src/summary-list/summary-list.component.ts @@ -15,10 +15,10 @@ import { SummaryItem } from './summary-list-api'; - +
    -
  • None
  • -
  • {{ value }}
  • +
  • None
  • +
  • {{ value }}
@@ -34,11 +34,11 @@ export class SummaryListComponent { @Input() public items?: SummaryItem[] = []; - public getFormattedLabel(item: SummaryItem): string { - return startCase(item.label.trim().toLowerCase()); + public getFormattedLabel(label: string): string { + return startCase(label.toLowerCase()); } - public getValuesArray(item: SummaryItem): PrimitiveValue[] { - return Array.isArray(item.value) ? item.value : [item.value]; + public getValuesArray(value: PrimitiveValue | PrimitiveValue[]): PrimitiveValue[] { + return Array.isArray(value) ? value : [value]; } } From 1f94365b343c5df1c5768a74fe821ca84186e033 Mon Sep 17 00:00:00 2001 From: Jake Bassett Date: Mon, 22 Mar 2021 15:15:37 -0700 Subject: [PATCH 5/5] feat: fix test more betterer --- .../summary-list.component.test.ts | 79 +++++++++++++++---- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/projects/components/src/summary-list/summary-list.component.test.ts b/projects/components/src/summary-list/summary-list.component.test.ts index 41f47730d..762ce8894 100644 --- a/projects/components/src/summary-list/summary-list.component.test.ts +++ b/projects/components/src/summary-list/summary-list.component.test.ts @@ -1,32 +1,79 @@ -import { SummaryListComponent } from '@hypertrace/components'; -import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; +import { IconType } from '@hypertrace/assets-library'; +import { IconComponent, LabelComponent, SummaryListComponent } from '@hypertrace/components'; +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { MockComponent } from 'ng-mocks'; describe('Summary List component', () => { - let spectator: Spectator; + let spectator: SpectatorHost; - const createComponent = createComponentFactory({ + const createHost = createHostFactory({ component: SummaryListComponent, shallow: true, - declarations: [] + declarations: [MockComponent(IconComponent), MockComponent(LabelComponent)] }); beforeEach(() => { - spectator = createComponent(); + spectator = createHost( + ` + `, + { + hostProps: { + title: 'My Title', + icon: IconType.Add, + items: [ + { + label: 'number', + value: 0 + }, + { + label: 'Number-Array', + value: [0, 1, 2] + }, + { + label: 'STRING', + value: 'zero' + }, + { + label: 'STRING_ARRAY', + value: ['zero', 'one', 'two', 'three'] + }, + { + label: 'bOOleAN', + value: true + }, + { + label: 'boolean-array', + value: [true, false] + } + ] + } + } + ); + }); + + test('sets title and icon', () => { + expect(spectator.query('.summary-icon', { read: IconComponent })?.icon).toEqual(IconType.Add); + expect(spectator.query('.summary-title', { read: LabelComponent })?.label).toEqual('My Title'); }); test('formats label', () => { - expect(spectator.component.getFormattedLabel('TEST_UNDERSCORE')).toEqual('Test Underscore'); - expect(spectator.component.getFormattedLabel('TEST-DASH')).toEqual('Test Dash'); - expect(spectator.component.getFormattedLabel('Test_mixed-LABEL')).toEqual('Test Mixed Label'); - expect(spectator.component.getFormattedLabel('test MORE')).toEqual('Test More'); + const labelComponents = spectator.queryAll('.summary-value-title', { read: LabelComponent }); + expect(labelComponents.map(c => c.label)).toEqual([ + 'Number', + 'Number Array', + 'String', + 'String Array', + 'Boolean', + 'Boolean Array' + ]); }); test('gets value array', () => { - expect(spectator.component.getValuesArray(1)).toEqual([1]); - expect(spectator.component.getValuesArray([1])).toEqual([1]); - expect(spectator.component.getValuesArray('two')).toEqual(['two']); - expect(spectator.component.getValuesArray(['two', 'three'])).toEqual(['two', 'three']); - expect(spectator.component.getValuesArray(true)).toEqual([true]); - expect(spectator.component.getValuesArray([true, false])).toEqual([true, false]); + const values = spectator.queryAll('li').map(e => e.textContent); + expect(values).toEqual(['0', '0', '1', '2', 'zero', 'zero', 'one', 'two', 'three', 'true', 'true', 'false']); }); });