File

src/lib/statistics/cross-source/sz-cross-source-results.data-table.ts

Description

Data Table with specific overrides and formatting for displaying sample results from the cross source summary component.

Extends

SzDataTable

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Outputs
HostBindings
Accessors

Constructor

constructor(prefs: SzPrefsService, cd: ChangeDetectorRef, cssService: SzCSSClassService, dataMartService: SzDataMartService, dialog: MatDialog, overlay: Overlay, viewContainerRef: ViewContainerRef)
Parameters :
Name Type Optional
prefs SzPrefsService No
cd ChangeDetectorRef No
cssService SzCSSClassService No
dataMartService SzDataMartService No
dialog MatDialog No
overlay Overlay No
viewContainerRef ViewContainerRef No

Outputs

loading
Type : Observable<SzStatsSampleTableLoadingEvent>

aggregate observeable for when the component is either loading data, transforming data, or rendering.

onEntityIdClick
Type : Observable<SzEntityIdentifier>

when either a "entityId" or "relatedEntityId" is clicked on

onNoData
Type : Observable<boolean>

when requests have completed but there are no results available to display

HostBindings

class.column-resizing
Type : boolean
class.first-load
Type : boolean
class.loading
Type : boolean
class.no-data
Type : boolean
class.sample-type-ambiguous-matches
Type : boolean

if singular datasource set css class 'singular' on host

class.sample-type-disclosed-relations
Type : boolean
class.sample-type-matches
Type : boolean
class.sample-type-possible-matches
Type : boolean
class.sample-type-possible-relations
Type : boolean
class.show-all-columns
Type : any
class.truncate-cell-data
Type : boolean
class.wrap-lines
Type : any

Methods

Public copyCellValue
copyCellValue(value: any, data?: any)

copy the value of a cell to the clipboard

Parameters :
Name Type Optional
value any No
data any Yes
Returns : void
Public copyElementHTML
copyElementHTML(ele: HTMLElement, data: any, debug?: any)

copy the value of a cell as HTML data

Parameters :
Name Type Optional
ele HTMLElement No
data any No
debug any Yes
Returns : void
Public debug
debug(obj)
Parameters :
Name Optional
obj No
Returns : void
Public getColCount
getColCount()
Returns : number
Public getGridColumnSizes
getGridColumnSizes()
Returns : void
Public getRowCellOrder
getRowCellOrder(fieldName: string)
Parameters :
Name Type Optional
fieldName string No
Returns : number
Public getRowCountForField
getRowCountForField(fieldName: string)
Parameters :
Name Type Optional
fieldName string No
Returns : number
Public getRowCountInSelectedDataSources
getRowCountInSelectedDataSources(item: SzStatSampleEntityTableItem, dataType?: SzStatSampleEntityTableRowType[])

Get the data table row count for a specific item. This is used to set the expand/collapse row-span for the entityId cells for the main entity row and it's related entity row (if not statType of "Matches")

Parameters :
Name Type Optional
item SzStatSampleEntityTableItem No
dataType SzStatSampleEntityTableRowType[] Yes
Returns : number
Public getRowIndex
getRowIndex()
Returns : number
Public getRowSpanForEntityIdCell
getRowSpanForEntityIdCell(rows: SzStatSampleEntityTableRow[])
Parameters :
Name Type Optional
rows SzStatSampleEntityTableRow[] No
Returns : number
Public getTotalRowCount
getTotalRowCount(item: SzStatSampleEntityTableItem, dataType?: SzStatSampleEntityTableRowType[])

get the total data table row count for an entity or related entity. Optionally count only row types matching items in the "dataType" parameter.

Parameters :
Name Type Optional
item SzStatSampleEntityTableItem No
dataType SzStatSampleEntityTableRowType[] Yes
Returns : number
Public hasAdditionalDataSources
hasAdditionalDataSources(rowGroupElement?: HTMLElement)

whethor or not there are additional rows for a result that are not part of the datasources selected from the pulldown

Parameters :
Name Type Optional
rowGroupElement HTMLElement Yes
Returns : any
Public hasTruncatedItems
hasTruncatedItems(value: | [])

used to show expansion buttons for table cells that have information truncated

Parameters :
Name Type Optional
value | [] No
Returns : boolean
Public isColumnExpanded
isColumnExpanded(columnKey: string)

check whether or not a column is expanded by user.

Parameters :
Name Type Optional
columnKey string No
Returns : boolean
Public isDataSourceSelected
isDataSourceSelected(dataSource: string, dataSourceName?: string)

is a particular datasource one of the ones used in the loaded sampleset

Parameters :
Name Type Optional
dataSource string No
dataSourceName string Yes
Returns : boolean
Public isPrefChecked
isPrefChecked(prefName: string)

is a specific boolean dataMart pref exists and is set to "true"

Parameters :
Name Type Optional
prefName string No
Returns : any
Public isShowingAdditionalDataSources
isShowingAdditionalDataSources(rowGroupElement?: HTMLElement)

used for setting the checkbox state in the row context menu option

Parameters :
Name Type Optional
rowGroupElement HTMLElement Yes
Returns : any
moveColumn
moveColumn(fieldName: string, orderModifier: number)

moves the position of a column in the order it is displayed

Parameters :
Name Type Optional
fieldName string No
orderModifier number No
Returns : void
ngOnInit
ngOnInit()
Returns : void
onCellClick
onCellClick(cellName: string, data: any, event?: MouseEvent, element?: HTMLElement)

when a cell is clicked on we detect whethor or not it's an "entityId" cell and if so emit the specific "onEntityIdClick" event. otherwise we emit a generic "cellClick" event that can also be listened for.

Parameters :
Name Type Optional
cellName string No
data any No
event MouseEvent Yes
element HTMLElement Yes
Returns : void
Public onHeaderContextMenu
onHeaderContextMenu(event: MouseEvent, col: any)

when the context click is made on the table header cell

Parameters :
Name Type Optional
event MouseEvent No
col any No
Returns : void
Public onNoResults
onNoResults(hasResults: boolean)

when a sample set has no available data to display

Parameters :
Name Type Optional
hasResults boolean No
Returns : void
Public onPageChange
onPageChange(event)

when a page change event is emitted from the dataMart service

Parameters :
Name Optional
event No
Returns : void
Public onPagingClearFilters
onPagingClearFilters(event)

when the "clear filters" event occurs on the paging component this method is called

Parameters :
Name Optional
event No
Returns : void
Public onPagingSampleClicked
onPagingSampleClicked(event)

when the "sample click" event occurs on the paging component this method is called

Parameters :
Name Optional
event No
Returns : void
Public openEntityById
openEntityById(value: any)

emit an entityId click programatically. (used in id field context menu)

Parameters :
Name Type Optional
value any No
Returns : void
Public openFilterDialog
openFilterDialog()

open the matchKey filtering dialog

Returns : void
Public replaceText
replaceText(template: string, value: any)
Parameters :
Name Type Optional
template string No
value any No
Returns : any
Public rowGroupStyle
rowGroupStyle(item?: SzStatSampleEntityTableItem)

get the css vars for a particular result which is then used by the css for particular display states.

Parameters :
Name Type Optional
item SzStatSampleEntityTableItem Yes
Returns : string
Public toggleBoolPref
toggleBoolPref(prefName: string, value?: any)

toggle a boolean preference for the dataMart prefs stored in local storage

Parameters :
Name Type Optional
prefName string No
value any Yes
Returns : void
Public toggleCellExpando
toggleCellExpando(cellElement?: HTMLElement, event?: MouseEvent)

expand or collapse cell when contents of cell contain items past truncation limit

Parameters :
Name Type Optional
cellElement HTMLElement Yes
event MouseEvent Yes
Returns : void
Public toggleColumnPicker
toggleColumnPicker(event: MouseEvent)

toggle the visibility of the column picker menu

Parameters :
Name Type Optional
event MouseEvent No
Returns : void
Public toggleColumnSelection
toggleColumnSelection(fieldName: string, event: MouseEvent)

handler for toggling whether or not a column is displayed. (used in column picker menu)

Parameters :
Name Type Optional
fieldName string No
event MouseEvent No
Returns : boolean
Public toggleNoDataLabel
toggleNoDataLabel(columnKey: string)

handler for toggling expansion for columns that have no data in them

Parameters :
Name Type Optional
columnKey string No
Returns : void
Public toggleRowExpansion
toggleRowExpansion(rowGroupElement?: HTMLElement)

when a result row has rows that are not visible(ie records that belong to the entity but come from non-selected datasources) toggle whether or not the additional record rows are visible

Parameters :
Name Type Optional
rowGroupElement HTMLElement Yes
Returns : void
Public truncatedItemCount
truncatedItemCount(value: | [])

used to show how many items are currently being hidden due to truncation

Parameters :
Name Type Optional
value | [] No
Returns : number

Properties

_colOrder
Type : Map<string | number>
Default value : new Map([ ['entityId', 0], ['resolutionRuleCode', 1], ['matchKey', 2], ['relatedEntityId', 3], ['dataSource', 4], ['recordId', 5], ['nameData', 6], ['attributeData', 7], ['identifierData', 8], ['addressData', 9], ['phoneData', 10], ['relationshipData', 11], ['entityData', 12], ['otherData', 13] ])

display the columns in this order

columnPickerRef
Type : ElementRef<HTMLElement>
Decorators :
@ViewChild('columnPickerRef')

Reference to column picker dom node

Public dialog
Type : MatDialog
Public menuPositions
Type : object
Default value : { settings: [ new ConnectionPositionPair( { originX: 'start', originY: 'top' }, { overlayX: 'end', overlayY: 'top' } ), ] }

used for positioning the prefs menu

Public overlay
Type : Overlay
Public prefs
Type : SzPrefsService
resizeIndicatorRef
Type : ElementRef<HTMLElement>
Decorators :
@ViewChild('resizeIndicatorRef')

child ref to column drag resize indicator line

sz_dt_header_context_menu
Type : TemplateRef<any>
Decorators :
@ViewChild('sz_dt_header_context_menu')

Reference to table header context menu

tableRef
Type : ElementRef<HTMLElement>
Decorators :
@ViewChild('tableRef')

child ref to table (used for resize overlay calc)

Public viewContainerRef
Type : ViewContainerRef

Accessors

classAmbiguousMatches
getclassAmbiguousMatches()

if singular datasource set css class 'singular' on host

classMatches
getclassMatches()
classPossibleMatches
getclassPossibleMatches()
classPossibleRelations
getclassPossibleRelations()
classDisclosedRelations
getclassDisclosedRelations()
showAllColumns
getshowAllColumns()
firstLoad
getfirstLoad()
noData
getnoData()
isLoading
getisLoading()
classTruncateLines
getclassTruncateLines()
classWrapLines
getclassWrapLines()
classColumnResizing
getclassColumnResizing()
colDataCount
getcolDataCount()

get counts of how many rows have values for a particular column

Returns : Map<string, number>
selectableColumns
getselectableColumns()

this is the columns that CAN be shown and is generated from the data so that if the columns are not present in the data AND in the "_selectableColumns" list they aren't in the list. This is the main way that the columns are iterated, column field counts are stored, ui iterates etc.

Returns : Map<string, string>
selectedDataSource1
getselectedDataSource1()

the "from" datasource for the loaded sampleset

Returns : string | undefined
selectedDataSource2
getselectedDataSource2()

the "to" datasource for the loaded sampleset

Returns : string | undefined
showColumnPickerMenu
getshowColumnPickerMenu()

is the column picker showing

Returns : boolean
truncateDataTableCellLines
gettruncateDataTableCellLines()

whether or not the cells with more than one item(like address lists) are truncated by default

visibilitySelectableColumns
getvisibilitySelectableColumns()

this is the columns that can be hidden/shown and is generated from the data so that if the columns are not present in the data they aren't in the list.

Returns : Map<string, string>
<!--<h2>gridStyle: "{{gridStyle}}"</h2>-->
<!-- Start Context Menus -->
<ng-template #sz_dt_header_context_menu let-col>
    <div class="sz-dt-header-context-menu" cdkMenu>
        <button class="header-context-menu-item" *ngIf="col.key === 'matchKey'" cdkMenuItem (click)="openFilterDialog()">Filter By Match Key</button>
        <button class="header-context-menu-item" cdkMenuItem *ngIf="!isColumnHidden(col.key)" (click)="selectColumn(col.key, false)">Hide Column</button>
        <button class="header-context-menu-item" cdkMenuItem *ngIf="isColumnHidden(col.key)" (click)="selectColumn(col.key, true)">Show Column</button>
        <button class="header-context-menu-item" cdkMenuItem 
            [cdkMenuTriggerFor]="sz_dt_header_column_order_context_menu"
            [cdkMenuTriggerData]="{$implicit: col}"
        >Column Order</button>
        <!--<button class="header-context-menu-item" cdkMenuItem 
        [cdkMenuTriggerFor]="sz_dt_header_row_order_context_menu"
        [cdkMenuTriggerData]="{$implicit: col}">Order By {{col.value}}</button>-->
    </div>
</ng-template>
<ng-template #sz_dt_header_column_order_context_menu let-col>
    <div class="sz-dt-header-context-menu submenu" cdkMenu>
        <button class="header-context-menu-item" cdkMenuItem (click)="moveColumn(col.key, -1)">Move Left</button>
        <button class="header-context-menu-item" cdkMenuItem (click)="moveColumn(col.key, +1)">Move Right</button>
        <button class="header-context-menu-item" cdkMenuItem disabled="disabled" (click)="moveColumn(col.key, (2 - columnOrder(col.key)))">Send to Front</button>
    </div>
</ng-template>
<ng-template #sz_dt_header_row_order_context_menu let-col> 
    <div class="sz-dt-header-context-menu submenu" cdkMenu>
    <button class="header-context-menu-item" cdkMenuItemRadio 
        [cdkMenuItemChecked]="sortDirection === 'ASC'"
        (cdkMenuItemTriggered)="sortBy(col.key,'ASC')">Ascending</button>
    <button class="header-context-menu-item" cdkMenuItemRadio 
        [cdkMenuItemChecked]="sortDirection === 'DESC'">Decending</button>
    </div>
</ng-template>
<ng-template #sz_dt_cell_context_menu let-data>
    <div class="sz-dt-header-context-menu" cdkMenu>

        <button class="header-context-menu-item" *ngIf="data.col.key === 'matchKey'" cdkMenuItem (click)="openFilterDialog()">Filter By Match Key</button>
        <!--<button class="header-context-menu-item" *ngIf="data.col.key === 'entityId'" cdkMenuItem (click)="copyCellValue(data.entityData && data.entityData['entityId'] ? data.entityData['entityId'] : data.rowData['entityId'], data)">Copy Entity ID</button>
        <button class="header-context-menu-item" *ngIf="data.col.key === 'entityId'" cdkMenuItem (click)="openEntityById(data.entityData && data.entityData['entityId'] ? data.entityData['entityId'] : data.rowData['entityId'])">Open Entity in new tab</button>-->
        <button class="header-context-menu-item" *ngIf="data.col.key === 'entityId' || data.col.key === 'relatedEntityId'" cdkMenuItem 
        [cdkMenuTriggerFor]="sz_dt_cell_entity_context_menu"
        [cdkMenuTriggerData]="{$implicit: data}">Entity</button>
        <!--<button class="header-context-menu-item" *ngIf="data.col.key === 'relatedEntityId'" cdkMenuItem (click)="copyCellValue(data.rowData['relatedEntityId'])">Copy Related Entity ID</button>
        <button class="header-context-menu-item" *ngIf="data.col.key === 'relatedEntityId'" cdkMenuItem (click)="openEntityById(data.rowData['relatedEntityId'])">Open Entity in new tab</button>-->
        <div class="separator" *ngIf="data.col.key === 'entityId' || data.col.key === 'relatedEntityId' || data.col.key === 'matchKey'"></div>
        <!--<button class="header-context-menu-item" *ngIf="data.col.key !== 'entityId'" cdkMenuItem (click)="copyCellContent(data.cell, data.cellData)">Copy Cell As JSON</button>
        <button class="header-context-menu-item" cdkMenuItem (click)="copyRowContent(data.row, data.rowData)">Copy Row As JSON</button>-->
        <button class="header-context-menu-item" cdkMenuItem
        [cdkMenuTriggerFor]="sz_dt_cell_row_context_menu"
        [cdkMenuTriggerData]="{$implicit: data}">Row</button>
        <button class="header-context-menu-item" cdkMenuItem
        [cdkMenuTriggerFor]="sz_dt_cell_cell_context_menu"
        [cdkMenuTriggerData]="{$implicit: data}">Cell</button>        
    <!--<button class="header-context-menu-item" cdkMenuItem (click)="minimizeCol(data.col)">Minimize Column</button>-->
    </div>
</ng-template>
<ng-template #sz_dt_cell_cell_context_menu let-data> 
    <div class="sz-dt-header-context-menu submenu" cdkMenu>
        <button class="header-context-menu-item" cdkMenuItem (click)="copyCellContent(data.cell, data.cellData)">Copy as JSON</button>
        <button class="header-context-menu-item" cdkMenuItem (click)="copyElementHTML(data.cell, data.cellData)">Copy as Text</button>
    </div>
</ng-template>
<ng-template #sz_dt_cell_row_context_menu let-data> 
    <div class="sz-dt-header-context-menu submenu" cdkMenu>
        <button class="header-context-menu-item" cdkMenuItem (click)="copyRowContent(data.row, data.rowData)">Copy as JSON</button>
        <!--<button class="header-context-menu-item" cdkMenuItem (click)="copyElementHTML(data.row, data.rowData, data)">Copy as Text</button>-->
        <button class="header-context-menu-item" cdkMenuItemCheckbox 
        [disabled]="!hasAdditionalDataSources(data.row)"
        [cdkMenuItemChecked]="isShowingAdditionalDataSources(data.row)"
        (click)="toggleRowExpansion(data.row)">Show other Data Sources</button>
    </div>
</ng-template>
<ng-template #sz_dt_cell_entity_context_menu let-data> 
    <div class="sz-dt-header-context-menu submenu" cdkMenu>
        <button class="header-context-menu-item" cdkMenuItem (click)="openEntityById(data.col.key === 'entityId' ? data.entityData && data.entityData['entityId'] : data.col.key === 'relatedEntityId' ? data.relatedEntity && data.relatedEntity['entityId'] : undefined)">Open in New Tab</button>
        <button class="header-context-menu-item" cdkMenuItem (click)="copyCellValue(data.col.key === 'entityId' ?  data.entityData && data.entityData['entityId']  : data.col.key === 'relatedEntityId' ? data.relatedEntity && data.relatedEntity['entityId'] : undefined)">Copy ID</button>
    </div>
</ng-template>
<ng-template #sz_dt_settings_picker_menu> 
    <div class="sz-dt-settings-menu" cdkMenu
    >
        <button class="header-context-menu-item" cdkMenuItemCheckbox 
            [cdkMenuItemChecked]="isPrefChecked('rememberSelectedDataSources')"
            (click)="toggleBoolPref('rememberSelectedDataSources')">Remember Selected Datasources</button>
        <button class="header-context-menu-item" cdkMenuItemCheckbox 
            [cdkMenuItemChecked]="isPrefChecked('truncateDataTableCellLines')"
            (click)="toggleBoolPref('truncateDataTableCellLines')">Truncate Lines</button>
        <button class="header-context-menu-item" cdkMenuItemCheckbox 
            [cdkMenuItemChecked]="isPrefChecked('wrapDataTableCellLines')"
            (click)="toggleBoolPref('wrapDataTableCellLines')">Wrap Cell Lines</button>
    </div>
</ng-template>
<!-- End Context Menus -->
<div class="control-ribbon">
    <!-- start paging component -->
    <sz-cross-source-pager 
        [pageSizeOptions]="[ 10, 25, 50, 75, 100 ]"
        (clearFilters)="onPagingClearFilters($event)"
        (sampleClicked)="onPagingSampleClicked($event)"></sz-cross-source-pager>
    <!-- end paging component -->
    <div class="control-ribbon-buttons">
        <!-- start column picker component -->
            <button class="column-picker-button has-tooltip"
                (click)="toggleColumnPicker($event); $event.stopPropagation()" 
                aria-label="Choose Columns"
                matTooltip="Select Columns to display" 
                matTooltipPosition="above">
                <div class="icon-columns-select mdi--view-column-outline"></div>
            </button>
            <div #columnPickerRef class="sz-mat-menu vertical" 
            [class.showing]="showColumnPickerMenu"
            >
                <label class="sz-mat-menu-item" 
                    *ngFor="let col of this.visibilitySelectableColumns | SzOrderedMapEntries; let i = index"
                >{{col.value}}
                    <input type="checkbox" 
                    [attr.is-checked]="isColumnSelected(col.key)" 
                    [checked]="isColumnSelected(col.key)"
                    (click)="toggleColumnSelection(col.key, $event)"
                    >
                    <span class="checkmark" (click)="$event.stopPropagation();"></span>
                </label>
            </div>
        <!-- end column picker component -->
        <!-- start pref settings -->
            <button class="settings-icon-picker-button"
                aria-label="Settings"
                matTooltip="Additional Settings" 
                matTooltipPosition="above"
                [cdkMenuTriggerFor]="sz_dt_settings_picker_menu"
                [cdkMenuPosition]="menuPositions.settings"
                >
                <div class="icon-settings-select mdi--view-settings-outline"></div>
            </button>
        <!-- end pref settings -->
    </div>
</div>
<!--<mat-menu #columnsSelector="matMenu" class="sz-g-flexbox-vertical" yPosition="below" (click)="$event.stopPropagation();">
    <button mat-menu-item *ngFor="let col of this.selectableColumns | SzOrderedMapEntries; let i = index"
    [attr.data-col-order]="columnOrder(col.key)"
    [style.order]="columnOrder(col.key)"
    (click)="$event.stopPropagation();">
    <mat-checkbox [checked]="isColumnSelected(col.key)" (change)="selectColumn(col.key, $event.checked)" (click)="$event.stopPropagation();">{{col.value}}</mat-checkbox>
    </button>
</mat-menu>-->
<!--<button (click)="resetCellSizes()"> reset row cell sizes</button>
<button (click)="getCellSizes()">get row cell sizes</button>-->
<!--<button (click)="getGridColumnSizes()"
sz-tooltip="Tooltip text">Get Grid Column Sizes</button>-->
<!--<button (click)="isColumnHidden2('resolutionRuleCode')">isColumnHidden2('resolutionRuleCode') ? {{isColumnHidden('resolutionRuleCode')}}</button>-->

<table class="data-table data-sample-table" 
    #tableRef
    [class.show-all-columns]="showAllColumns"
    [style]="gridStyle" 
    [attr.data-table-index]="resetTableIndexes()">
    <thead>
        <tr style="order: 0">
        <!--<ng-container>-->
            <th 
                #colRef
                *ngFor="let col of this.selectableColumns | SzOrderedMapEntries; let i = index"
                [class]="'sz-dt-column '+cellClass(col.key, 'sz-dt-header','cell')+' '+cellClass(col.key, 'sz-dt','column')" 
                [class.sorted]="isSortedBy(col.key)" 
                [class.sorted-asc]="sortDirection === 'ASC'" 
                [class.sorted-desc]="sortDirection === 'DESC'"
                [class.hidden]="isColumnHidden(col.key)"
                [class.empty-column]="getRowCountForField(col.key) === 0"
                [class.expanded]="isColumnExpanded(col.key)"
                [cdkContextMenuTriggerFor]="sz_dt_header_context_menu"
                [cdkContextMenuTriggerData]="{$implicit: col}"
                [style]="columnStyle(col.key)"
                [attr.data-field-name]="col.key"
                [attr.data-col-order]="columnOrder(col.key)"
                [attr.data-col-value-count]="getRowCountForField(col.key)"
                (mousedown)="onHeaderMouseDown($event)"
                (mousemove)="onHeaderMouseMove($event)"
                (mouseup)="onHeaderMouseUp($event)"
                >
                <span class="col-name-text">{{col.value}}</span>
                <div *ngIf="getRowCountForField(col.key) === 0" class="no-data-icon-wrapper has-tooltip">
                    <button class="no-data-icon" mat-icon-button
                        (click)="toggleNoDataLabel(col.key)"
                        ><mat-icon aria-hidden="false" aria-label="toggle column label" fontIcon="info_outline"></mat-icon>
                    </button>
                    <span class="tooltiptext">{{col.value}} is collapsed because no data exists for the displayed records.
                        Click to show or hide the column name placeholder.</span>
                </div>

                <span *ngIf="getRowCountForField(col.key) > 0" class="icon-sort descending mdi--sort-descending" (click)="sortBy(col.key,'DESC')"></span>
                <span *ngIf="getRowCountForField(col.key) > 0" class="icon-sort ascending mdi--sort-ascending" (click)="sortBy(col.key,'ASC')"></span>
                <div *ngIf="getRowCountForField(col.key) > 0" class="handle-resize"
                (mousedown)="onResizeMouseDown(col.key, $event)"
                (mouseup)="onResizeMouseUp(col.key, $event)"></div>
                <span *ngIf="col.key === 'matchKey'" class="icon-filter descending mdi--filter" (click)="openFilterDialog()"></span>
            </th>
            <!--<div class="leftdragbar" onmousedown="startColResize(col.key)" onmouseup="endColResize(col.key)"></div>-->
        <!--</ng-container>-->
        
        </tr>
    </thead>
    <!--<tbody>-->
    <ng-container *ngIf="!noData && !isLoading">
    <tbody class="row-group" *ngFor="let row of this.data; let groupIndex=index;" 
        #rowRef
        [attr.group-row-index]="groupIndex" 
        [class.hasExpandedCells]="hasExpandedCells(rowRef)"
        [attr.data-source-1]="selectedDataSource1"
        [attr.data-source-2]="selectedDataSource2"
        [class.has-additional-data]="getTotalRowCount(row) !== getRowCountInSelectedDataSources(row)"
        [style]="rowGroupStyle(row)"
        >
            <!-- show row for entity iteself -->
            <!--
                <tr
                class="row-entity"
                [attr.data-row-index]="incrementRowCount()"
                [attr.data-source]="row.dataSource"
                >
                <td #cellRef *ngFor="let col of this.selectableColumns | SzOrderedMapEntries"
                    [attr.data-row-index]="getRowIndex()" 
                    [attr.data-cell-order]="getCellOrder(col.key, getRowIndex())"
                    [style]="cellStyle(col.key, getRowIndex())"
                    [class]="'sz-dt-cell '+cellClass(col.key, 'sz-dt','cell')+' '+cellClass(col.key, 'sz-dt','column')" 
                    [class.hidden]="isColumnHidden(col.key)"
                    [class.empty-column]="getRowCountForField(col.key) === 0"
                    [cdkContextMenuTriggerFor]="sz_dt_cell_context_menu"
                    [cdkContextMenuTriggerData]="{$implicit: {cell: cellRef, row: rowRef, col: col, cellData: row[col.key], rowData: row}}"
                    (click)="onCellClick(col.key, row[col.key], $event, cellRef)">
                    <div *ngIf="col.key === 'entityId'" class="cell-content" 
                        matTooltip="Click to view Entity Detail page" 
                        matTooltipPosition="right"
                        [innerHTML]="cellValue(row[col.key], col.key)" [attr.cell-key]="col.key"></div>
                    <div *ngIf="col.key !== 'entityId'" class="cell-content"
                        [innerHTML]="cellValue(row[col.key], col.key)" [attr.cell-key]="col.key"></div>
                </td>
            </tr>-->
            <!-- show rows for entity records -->
            <tr *ngFor="let rowQ of row.rows; let recordIndex=index;" 
                [attr.data-row-index]="incrementRowCount()"
                [attr.data-source]="rowQ.dataSource"
                [class.data-source-selected]="isDataSourceSelected(rowQ.dataSource, 'sampleDataSource1')"
                [class.data-source-not-selected]="!isDataSourceSelected(rowQ.dataSource, 'sampleDataSource1')"
                class="row-record row-entity-record">
                <td #cellRef [attr.data-record-index]="recordIndex+1" *ngFor="let col of this.selectableColumns | SzOrderedMapEntries" 
                    [attr.data-cell-order]="getCellOrder(col.key, getRowIndex())"
                    [class.empty-column]="getRowCountForField(col.key) === 0"
                    [class.hidden]="isColumnHidden(col.key)"
                    [style]="cellStyle(col.key, getRowIndex())"
                    [class.has-hidden-items]="hasTruncatedItems(rowQ[col.key])"
                    [class]="'sz-dt-cell '+cellClass(col.key, 'sz-dt','cell')+' '+cellClass(col.key, 'sz-dt','column')" 
                    [cdkContextMenuTriggerFor]="sz_dt_cell_context_menu"
                    [cdkContextMenuTriggerData]="{$implicit: {cell: cellRef, row: rowRef, col: col, cellData: rowQ[col.key], rowData: rowQ, entityData: row}}"
                    (click)="onCellClick(col.key, (col.key === 'entityId'? row[col.key] : rowQ[col.key]), $event, cellRef)"
                >
                    <div *ngIf="col.key === 'entityId'" class="cell-content" 
                        matTooltip="Click to view Entity Detail page" 
                        matTooltipPosition="right"
                        [innerHTML]="cellValue(row[col.key], col.key)" [attr.cell-key]="col.key"></div>
                    <div *ngIf="col.key !== 'entityId'" class="cell-content"
                        [innerHTML]="cellValue(rowQ[col.key], col.key)" [attr.cell-key]="col.key"></div>
                    <!--<div class="cell-content" [innerHTML]="cellValue(rowQ[col.key], col.key)" [attr.cell-key]="col.key"></div>-->
                    <div *ngIf="col.key === 'entityId' && classMatches && (getTotalRowCount(row) - getRowCountInSelectedDataSources(row)) > 0">
                        <button mat-stroked-button class="more-button expanded" 
                            matTooltip="Hide additional records from other data sources." 
                            matTooltipPosition="right"
                            (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                            <mat-icon>visibility_off</mat-icon>
                            {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} Less</button>
                        <button mat-stroked-button class="more-button collapsed" 
                            matTooltip="Show additional records from other data sources." 
                            matTooltipPosition="right"
                            (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                            <mat-icon>visibility</mat-icon>
                            {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} More
                        </button>
                    </div>
                    <!--<button (click)="debugTruncatedItemCount(rowQ[col.key])">truncated lines {{truncatedItemCount(rowQ[col.key])}}</button>-->
                    <div class="toggle-expansion" *ngIf="col.key !== 'entityId' && hasTruncatedItems(rowQ[col.key])"
                    (click)="toggleCellExpando(cellRef, $event)">
                        <button class="more-link">
                            {{truncatedItemCount(rowQ[col.key])}} more items</button>
                        <button class="less-link">
                            hide last {{truncatedItemCount(rowQ[col.key])}} items</button>
                        <mat-icon>transit_enterexit</mat-icon>
                    </div>
                </td>
            </tr>
            <!-- show row for related entity -->
            <!--<tr *ngIf="row.relatedEntity" 
                class="row-related-entity"
                [attr.data-row-index]="incrementRowCount()"
                [attr.data-source]="row.relatedEntity.dataSource"
                >
                <td #cellRef *ngFor="let col of this.selectableColumns | SzOrderedMapEntries"
                    [attr.data-row-index]="getRowIndex()" 
                    [attr.data-cell-order]="getCellOrder(col.key, getRowIndex())"
                    [style]="cellStyle(col.key, getRowIndex())"
                    [class]="'sz-dt-cell '+cellClass(col.key, 'sz-dt','cell')+' '+cellClass(col.key, 'sz-dt','column')" 
                    [class.hidden]="isColumnHidden(col.key)"
                    [class.empty-column]="getRowCountForField(col.key) === 0"
                    [cdkContextMenuTriggerFor]="sz_dt_cell_context_menu"
                    [cdkContextMenuTriggerData]="{$implicit: {cell: cellRef, row: rowRef, col: col, cellData: row.relatedEntity[col.key], rowData: row.relatedEntity}}"
                    (click)="onCellClick(col.key, row.relatedEntity[col.key], $event, cellRef)">
                        <div class="cell-content" 
                            *ngIf="col.key === 'entityId' || col.key === 'relatedEntityId'"
                            matTooltip="Click to view Entity Detail page" 
                            [matTooltipPosition]="col.key === 'entityId' ? 'right':'above'"
                            [innerHTML]="cellValue(row.relatedEntity[col.key], col.key)" [attr.cell-key]="col.key"></div>
                        <div class="cell-content" 
                            *ngIf="col.key !== 'entityId' && col.key !== 'relatedEntityId'"
                            [innerHTML]="cellValue(row.relatedEntity[col.key], col.key)" [attr.cell-key]="col.key"></div>
                        <div *ngIf="col.key === 'entityId' && (getTotalRowCount(row) - getRowCountInSelectedDataSources(row)) > 0">
                            <button mat-stroked-button class="more-button expanded" 
                                matTooltip="Hide additional records from other data sources." 
                                matTooltipPosition="right"
                                (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                                <mat-icon>visibility_off</mat-icon>
                                {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} Less</button>
                            <button mat-stroked-button class="more-button collapsed" 
                                matTooltip="Show additional records from other data sources." 
                                matTooltipPosition="right"
                                (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                                <mat-icon>visibility</mat-icon>
                                {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} More
                            </button>
                        </div>
                </td>
            </tr>-->
            <!-- show rows for related entity records -->
            <ng-container *ngIf="row.relatedEntity && row.relatedEntity.rows">
                <tr *ngFor="let rowY of row.relatedEntity.rows; let recordIndex=index;" 
                [attr.data-row-index]="incrementRowCount()"
                [attr.data-source]="rowY.dataSource"
                [class.data-source-selected]="isDataSourceSelected(rowY.dataSource, 'sampleDataSource2')"
                [class.data-source-not-selected]="!isDataSourceSelected(rowY.dataSource, 'sampleDataSource2')"
                class="row-record row-related-record">
                    <td #cellRef [attr.data-record-index]="recordIndex+1" *ngFor="let col of this.selectableColumns | SzOrderedMapEntries" 
                        [attr.data-cell-order]="getCellOrder(col.key, getRowIndex())"
                        [class.empty-column]="getRowCountForField(col.key) === 0"
                        [class.hidden]="isColumnHidden(col.key)"
                        [style]="cellStyle(col.key, getRowIndex())"
                        [class.has-hidden-items]="hasTruncatedItems(rowY[col.key])"
                        [class]="'sz-dt-cell '+cellClass(col.key, 'sz-dt','cell')+' '+cellClass(col.key, 'sz-dt','column')" 
                        [cdkContextMenuTriggerFor]="sz_dt_cell_context_menu"
                        [cdkContextMenuTriggerData]="{$implicit: {cell: cellRef, row: rowRef, col: col, cellData: rowY[col.key], rowData: rowY, entityData: row, relatedEntity: row.relatedEntity}}"
                        (click)="onCellClick(col.key, (col.key === 'relatedEntityId'? row.relatedEntity[col.key] : rowY[col.key]), $event, cellRef)"
                    >
                        <div class="cell-content" 
                            *ngIf="col.key === 'matchKey'"
                            [innerHTML]="cellValue(row.relatedEntity.relatedMatchKey, col.key)" [attr.cell-key]="col.key"></div>
                        <div class="cell-content" 
                            *ngIf="col.key === 'entityId' || (col.key === 'relatedEntityId')"
                            matTooltip="Click to view Entity Detail page" 
                            [matTooltipPosition]="col.key === 'entityId' ? 'right':'above'"
                            [innerHTML]="cellValue(row.relatedEntity[col.key], col.key)" [attr.cell-key]="col.key"></div>
                        <div class="cell-content" 
                            *ngIf="col.key !== 'entityId' && col.key !== 'relatedEntityId' && col.key !== 'matchKey'"
                            [innerHTML]="cellValue(rowY[col.key], col.key)" [attr.cell-key]="col.key"></div>
                        <!--<div class="cell-content" [innerHTML]="cellValue(rowY[col.key], col.key)" [attr.cell-key]="col.key"></div>-->
                        <div *ngIf="col.key === 'entityId' && (getTotalRowCount(row) - getRowCountInSelectedDataSources(row)) > 0">
                            <button mat-stroked-button class="more-button expanded" 
                                matTooltip="Hide additional records from other data sources." 
                                matTooltipPosition="right"
                                (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                                <mat-icon>visibility_off</mat-icon>
                                {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} Less</button>
                            <button mat-stroked-button class="more-button collapsed" 
                                matTooltip="Show additional records from other data sources." 
                                matTooltipPosition="right"
                                (click)="toggleRowExpansion(rowRef); $event.stopPropagation()">
                                <mat-icon>visibility</mat-icon>
                                {{getTotalRowCount(row) - getRowCountInSelectedDataSources(row)}} More
                            </button>
                        </div>
                        <div class="toggle-expansion" *ngIf="col.key !== 'entityId' && hasTruncatedItems(rowY[col.key])"
                            (click)="toggleCellExpando(cellRef, $event)">
                            <button class="more-link">show {{truncatedItemCount(rowY[col.key])}} more</button>
                            <button class="less-link">hide last {{truncatedItemCount(rowY[col.key])}}</button>
                            <mat-icon>transit_enterexit</mat-icon>
                        </div>
                    </td>
            </tr>
            </ng-container>
    </tbody>
    </ng-container>
    <tbody *ngIf="noData"
    [style]="rowGroupStyle()">
        <tr class="row-no-data">
            <td 
            [style.order]="this.selectableColumns.size + 1"
            class="sz-dt-no-data-cell"
            >No Results</td>
        </tr>
    </tbody>
    <!--</tbody>-->
    </table>
    <div #resizeIndicatorRef class="resize-indicator"></div>

./sz-cross-source-results.data-table.scss

:host {

    * {
        box-sizing: border-box;
    }
    &.sample-type-ambiguous-matches {
        --sz-sample-dt-primary-color: var(--sz-color-ambiguous);
        .data-table th {
            background-color: var(--sz-color-ambiguous);
        }
    }
    &.sample-type-matches {
        --sz-sample-dt-primary-color: var(--sz-color-matches);
        .data-table th {
            background-color: var(--sz-color-matches);
        }

        .data-table tbody.row-group .row-entity-record .sz-dt-match-key-cell .cell-content {
            display: block !important;
        }
        /*.data-table tbody.row-group .sz-dt-entity-id-cell {
            grid-template-rows: 27px auto;
        }*/
    }
    &.sample-type-possible-matches {
        --sz-sample-dt-primary-color: var(--sz-color-possible-matches);
        .data-table th {
            background-color: var(--sz-color-possible-matches);
        }
    }
    &.sample-type-possible-relations {
        --sz-sample-dt-primary-color: var(--sz-color-possibly-related);
        .data-table th {
            background-color: var(--sz-color-possibly-related);
        }
    }
    &.sample-type-disclosed-relations {
        --sz-sample-dt-primary-color: var(--sz-color-disclosed);
        .data-table th {
            background-color: var(--sz-color-disclosed);
        }
    }

    // override any collapsed or hidden columns
    &.show-all-columns {
        .data-table {
            th.empty-column {
                padding: 5px 22px 4px 14px;
                .col-name-text {
                    display: inline-block;
                    text-overflow: ellipsis;
                    width: 100%;
                    overflow: hidden;
                }
                .no-data-icon-wrapper {
                    margin-top: unset;
                    position: absolute;
                    right: 2px;
                    top: 1px;
                }
            }
        }
    }

    .resize-indicator {
        display: none;
        position: absolute;
        left: 0px;
        top: 27px;
        width: 1px;
        height: 100vh;
        z-index: 1000;
        border-left: 2px dotted #0000003f;
    }

    &.column-resizing {
        .resize-indicator {
            display: block;
        }
    }

    &.loading .data-table tbody td {
        opacity: .2;
    }

    .data-table {
        display: grid;
        border-collapse: collapse;
        min-width: 100%;
        /*column-gap: 2px;*/
        font-size: 12px;
        cursor: default;

        /* because we are only setting border-top on 
            * every row we need to add a bottom border to the 
            * table itself
        */
        border-bottom: 1px solid #cfcfcf;

        thead,
        tbody,
        tr {
            display: contents;
        }
        
        th,
        td {
            padding: 5px 14px 4px 14px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            &.hidden {
                display: none;
            }
            &.no-cell {
                display: none;
            }
        }
        
        th {
            position: sticky;
            top: 0;
            background: #6c7ae0;
            text-align: left;
            font-size: 14px;
            font-weight: 400;
            line-height: 14px;
            padding: 5px 14px 6px;
            color: #fff;
            min-width: 100px;
            -webkit-user-select: none;
            user-select: none;
            border-right: 1px solid #666;
            z-index: 5;
            filter: drop-shadow(1px 4px 3px rgba(0,0,0,.3));
            border-bottom: 1px solid #666;

            &.empty-column {
                -webkit-user-select: auto;
                user-select: auto;
                width: unset !important;
                overflow: visible; /* we only want the tooltips to show outside of the header  when col empty */

                &.expanded {
                    width: unset;
                    padding: 5px 22px 4px 14px;
                    .col-name-text {
                        display: inline-block !important;
                        width: 100%;
                        overflow: hidden;
                        text-overflow: ellipsis;
                    }
                    .no-data-icon-wrapper {
                        margin-top: unset;
                        position: absolute;
                        right: 2px;
                        top: 1px;
                    }
                }
            }

            .icon-sort {
                position: absolute;
                right: 5px;
                display: none !important;
                cursor: pointer;
            }
            .icon-filter {
                position: absolute;
                right: 5px;
                display: none;
                cursor: pointer;
            }
            .handle-resize {
                width: 2px;
                background-color: #ffffff59;
                cursor: ew-resize;
                display: block;
                position: absolute;
                right: 0px;
                top: 0px;
                height: 100%;
            }
            &.is-dragging {
                background-color: #c0c0c0;
                .handle-resize {
                    background-color: #000;
                    right: unset;
                }
            }

            &:hover {
                .icon-sort {
                    &.ascending {
                        display: inline-block;
                    }
                }
                .icon-filter {
                    display: inline-block;
                }
            }

            /* don't show icon for sort option already selected */
            &.sorted {
                &.sorted-asc {
                    .icon-sort.ascending {
                        display: inline-block;
                    }
                    &:hover {
                        .icon-sort.ascending {
                            display: none;
                        }
                        .icon-sort.descending {
                            display: inline-block;
                        }
                    }
                }
                &.sorted-desc {
                    .icon-sort.descending {
                        display: inline-block;
                    }
                    &:hover {
                        .icon-sort.descending {
                            display: none;
                        }
                        .icon-sort.ascending {
                            display: inline-block;
                        }
                    }
                }
            }
            .no-data-icon-wrapper {
                display: none;
                position: relative;
                width: 18px;
                height: 18px;
                top: 1px;
            }
            .no-data-icon {
                padding: 0;
                --mdc-icon-button-state-layer-size: 14px;
                width: 18px;
                height: 18px;
                line-height: 18px;
                margin-top: calc(50% - 6px);

                mat-icon {
                    font-size: 18px;
                    line-height: 18px;
                    width: 18px;
                    height: 18px;
                }
            }

            &[data-col-value-count="0"] {
                width: 20px;
                padding: 0;
                min-width: unset;
                span.col-name-text {
                    display: none;
                }
                .no-data-icon-wrapper {
                    display: inline-block;
                }
            }
        }
        
        th:last-child {
            border: 0;
        }
        
        td {
            padding-top: 10px;
            padding-bottom: 10px;
            color: var(--sz-sample-table-cell-color);
        }
        
        tbody {
            .row-record:nth-child(even of .data-source-selected) td {
                /*background-color: #f2f2f2;*/
            }

            .row-no-data {
                border: 2px solid green;
                font-size: 20px;

                .sz-dt-no-data-cell {
                    grid-column: span var(--column-count);
                    min-height: 30vh;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    font-weight: bold;
                    letter-spacing: 0.1em;
                }
            }

            &.row-group {
                border: 1px solid rgb(104, 104, 104);

                /* by default hide all entity id cells */
                .sz-dt-entity-id-cell {
                    display: none;
                }
                /* by default hide all "relatedEntityId" content cells */
                .sz-dt-related-entity-id-cell  .cell-content {
                    display: none;
                }

                .row-related-record {
                    .sz-dt-entity-id-cell .cell-content,
                    .sz-dt-match-key-cell .cell-content {
                        display: none;
                    }
                }
                /* for entity records on everything EXCEPT for "Matches" we don't want to show these */
                .row-entity-record .sz-dt-match-key-cell .cell-content {
                    display: none;
                }

                /**
                Sometimes the very first visible row is not the same thing as the first row
                in the DOM. Hence the Fancy selectors for "first-instance-of-this-class"
                */
                :nth-child(1 of .data-source-selected) {
                    border: 1px solid orange;

                    .sz-dt-entity-id-cell {
                        grid-row: span var(--selected-datasources-entity-row-count);
                        display: grid;
                        grid-template-rows: 27px auto;
                    }
                    td {
                        border-top: 2px solid #666;
                    }
                }

                :nth-child(1 of .row-related-record.data-source-selected) {
                    border: 1px solid green;
                    
                    .sz-dt-entity-id-cell {
                        grid-row: span var(--selected-datasources-related-row-count);
                        display: block;
                    }
                    /* show the content only in the very first visible cell */
                    .sz-dt-related-entity-id-cell  .cell-content,
                    .sz-dt-match-key-cell .cell-content {
                        display: block;
                    }
                    td {
                        border-top: 1px dotted #313131;;
                    }
                }
                &.expanded {
                    /* first unset the row-span(s) for "first row in selected datasources"*/
                    :nth-child(1 of .data-source-selected),
                    :nth-child(1 of .row-related-record.data-source-selected) {
                        .sz-dt-entity-id-cell { 
                            /* by default hide all the "entityId" cells (we'll enable just the first one below) */
                            grid-row: unset; 
                            display: none;
                        }
                        .sz-dt-related-entity-id-cell .cell-content,
                        .sz-dt-match-key-cell .cell-content {
                            display: none;
                        }
                    }
                    :nth-child(1 of .row-related-record.data-source-selected) td { 
                        border-top: none;
                    }
                    .row-record .sz-dt-entity-id-cell {
                        display: none;
                    }
                    /* by default hide all "relatedEntityId" content elements (well enable just the fist one below */
                    /*
                    .row-record .sz-dt-related-entity-id-cell {
                        .cell-content {
                            display: none;
                        }
                    }*/

                    /* since everything should be visible now just apply the rowspan to the 
                    first row entity id cell*/
                    .row-record:first-child {
                        .sz-dt-entity-id-cell {
                            grid-row: span var(--entity-row-count);
                            display: grid !important;
                            grid-template-rows: 27px auto;
                        }
                    }
                    :nth-child(1 of .row-related-record) { 
                        // the first related record row gets a dotted line separating it from 
                        // the entity records
                        td {
                            border-top: 1px dotted #313131 !important;
                        }
                        /* now show the "relatedEntityId" content for just the first row */
                        .sz-dt-related-entity-id-cell .cell-content, 
                        .sz-dt-match-key-cell .cell-content {
                            display: block !important;
                        }

                        /* now apply the related rows count to the rowspan for the first related row's
                        * related record entity id cell */
                        .sz-dt-entity-id-cell {
                            grid-row: span var(--related-row-count) !important;
                            display: grid !important;
                        }
                    }
                }

                .sz-dt-entity-id-cell {
                    .cell-content {
                        /*color: var(--sz-sample-dt-primary-color);*/
                        color: var(--sz-sample-table-cell-link-color);
                        font-size: var(--sz-sample-table-cell-link-font-size);
                        font-weight: var(--sz-sample-table-cell-link-font-weight);
                        align-items: var(--sz-sample-table-cell-link-text-align);
                        text-align: var(--sz-sample-table-cell-link-text-align);
                        text-decoration: var(--sz-sample-table-cell-link-text-decoration);
                        
                        &:hover {
                            cursor: pointer;
                        }
                    }

                    .more-button {
                        font-size: 10px;
                        height: 22px;
                        padding: 2px 5px 2px 8px;
                        /*background-color: var(--sz-sample-dt-primary-color);*/
                        /*background-color: var(--sz-sample-table-expanded-row-background-color);*/
                        background-color: var(--sz-sample-table-expand-button-background-color);
                        color: var(--sz-sample-table-expand-button-color);
                        margin-top: 5px;
                        line-height: 18px;
                        mat-icon {
                            margin-right: 0;
                            margin-top: 1px;
                            font-size: 14px;
                            line-height: 14px;
                            opacity: 0.6;
                            width: 14px;
                            height: 14px;
                        }
                    }
                    .more-button.collapsed  { display: block; }
                    .more-button.expanded   { 
                        display: none; 
                        background-color:   var(--sz-sample-table-expanded-row-expand-button-background-color);
                        border-color:       var(--sz-sample-table-expanded-row-expand-button-border-color);
                        color:              var(--sz-sample-table-expanded-row-expand-button-color);
                        
                        mat-icon {
                            opacity: 1;
                        }
                    }
                }

                :nth-child(1 of .row-entity-record.data-source-selected) {
                    /* we want the entity id cell to span all children row cells 
                    the variables '--selected-datasources-row-count' and '--total-row-count'
                    are defined on the scope of each .row-group through the style tag
                    */
                    .sz-dt-entity-id-cell {
                        /*grid-row: span var(--selected-datasources-entity-row-count);*/
                        max-height: unset;
                        border-bottom: none;
                        /*.cell-content {
                            font-size: 16px;
                            font-weight: bold;
                            align-items: center;
                            text-align: center;
                            
                            &:hover {
                                text-decoration: underline;
                                cursor: pointer;
                            }
                        }*/
                    }
                }
                :nth-child(1 of .row-related-record.data-source-selected) { 
                    .sz-dt-entity-id-cell {
                        /*grid-row: span var(--selected-datasources-related-row-count);*/
                        overflow: visible;

                        .cell-content {
                            display: none;
                        }

                        /* when the more button is in the lower cell we want to straddle the line */
                        .more-button {
                            position: absolute;
                            top: -13px;
                            margin-top: 0px;
                        }
                    }
                }
                &.has-expanded-data .row-related-entity .sz-dt-entity-id-cell {
                    padding-top: 20px;
                }
                .row-record.data-source-not-selected {
                    display: none;
                    td {
                        background-color: var(--sz-sample-table-expanded-row-background-color);
                    }
                }
                /* we never want the first "entityId" cell to be blue 
                * (which can happen if the very first record row is not in the selected 
                * datasources)*/
                .row-record {
                    &.row-entity .sz-dt-entity-id-cell,
                    &.row-entity-record .sz-dt-entity-id-cell {
                        background-color: var(--sz-sample-table-entity-row-background-color) !important;
                    }
                    &.row-related-entity .sz-dt-entity-id-cell,
                    &.row-related-record .sz-dt-entity-id-cell {
                        background-color: var(--sz-sample-table-related-row-background-color) !important;
                    }
                }
                &.expanded {
                    :nth-child(1 of .data-source-selected) { 
                        border-top: none;
                        td {
                            border-top: none;
                        }
                    }
                    tr:first-child td {
                        border-top: 2px solid #666 !important;
                        .sz-dt-entity-id-cell {
                            /*grid-row: span var(--selected-datasources-entity-row-count);*/
                            max-height: unset;
                            border-bottom: none;
                            .cell-content {
                                /*color: var(--sz-sample-dt-primary-color);*/
                                color: var(--sz-sample-table-cell-link-color);
                                font-size: var(--sz-sample-table-cell-link-font-size);
                                font-weight: var(--sz-sample-table-cell-link-font-weight);
                                align-items: var(--sz-sample-table-cell-link-text-align);
                                text-align: var(--sz-sample-table-cell-link-text-align);
                                text-decoration: var(--sz-sample-table-cell-link-text-decoration);
                                
                                &:hover {
                                    text-decoration: underline;
                                    cursor: pointer;
                                }
                            }

                        }
                    }
                    .row-record:nth-child(even) td {
                        /*background-color: #f2f2f2;*/
                    }
                    .row-record.data-source-not-selected td {
                        background-color: var(--sz-sample-table-expanded-row-background-color);
                    }
                    /*
                    .row-entity-record.first .sz-dt-entity-id-cell {
                        grid-row: span var(--entity-row-count);
                        border-bottom: none;
                    }
                    .row-related-record.first .sz-dt-entity-id-cell {
                        grid-row: span var(--related-row-count);
                        
                    }*/
                    /* swap "more" button to "less" button */

                    .row-entity, .row-entity-record,
                    .row-related-entity, .row-related-record {
                        .sz-dt-entity-id-cell {
                            .more-button.collapsed  { display: none;  }
                            .more-button.expanded   { display: block; }
                        }
                    }
                    .row-record.data-source-not-selected {
                        display: contents;
                    }
                    :nth-child(1 of .row-related-record) {
                        .sz-dt-entity-id-cell {
                            overflow: visible;
                            /* when the more button is in the lower cell we want to straddle the line */
                            .more-button {
                                position: absolute;
                                top: -13px;
                                margin-top: 0px;
                            }
                        }
                        // hide
                    }

                }
                &:nth-of-type(1) tr {
                    &:first-child {
                        td {
                            margin-top: 0 !important;
                            border-top: 0 !important;
                        }
                    }
                }
            }
            
            /*tr:nth-child(even) td {
                background: #f8f6ff;
                .min-max-toggle {
                    background-color: #f8f6ff;
                }
            }*/
            /* because display='contents' we cant just add a row-grap or margin 
             * on the row itself
            */
            tr {
                td {
                    /*margin-bottom: 2px;*/
                    border-right: 2px solid #fff;
                    border-top: 2px solid #fff;
                    &:last-child {
                        border-right: none;
                    }
                }
                &:first-child, &:last-child {
                    td {
                        margin-bottom: 0;
                    }
                }

                /*&:first-child {
                    td {
                        border-top: 2px solid #666;
                    }
                }*/               
            }

            td {
                position: relative;
                
                .min-max-toggle {
                    display: none;
                    background-color: #fff;
                    position: absolute;
                    bottom: 0;
                    right: 0;
                    fill: #808080;
                    cursor: pointer;
                }
                &.empty-column {
                    min-width: unset;
                    width: unset;
                    padding: 0;
                }
            }
            td.expandable {
                &.expanded {
                    max-height: unset;
                }
                /* hide everything after first row */
                /*.cell-content {
                    div {
                        visibility: hidden;
                        &:first-child {
                            visibility: visible;
                        }
                    }
                }*/
                
                &:hover {
                    .min-max-toggle { 
                        display: block;
                    }
                }
            }
        }


        .sz-dt-related-entity-id-cell {
            .cell-content {
                color: var(--sz-sample-table-cell-link-color);
                font-size: var(--sz-sample-table-cell-link-font-size);
                font-weight: var(--sz-sample-table-cell-link-font-weight);
                align-items: var(--sz-sample-table-cell-link-text-align);
                text-align: var(--sz-sample-table-cell-link-text-align);
                text-decoration: var(--sz-sample-table-cell-link-text-decoration);

                &:hover {
                    cursor: pointer;
                }
            }
        }
        /* hide the entity id value in related entity row */
        .row-related-entity .sz-dt-entity-id-cell .cell-content {
            display: none;
        }
        .row-entity-record {
            td {
                background-color: var(--sz-sample-table-entity-row-background-color);
            }
            &:last-of-type {
                td {
                    border-bottom: none !important;
                }
            }
            &.first {
                td {
                    border-top: 2px solid #636363;
                    /*border-bottom: 1px dotted #636363;*/
                }
            }
        }
        .row-related-entity {
            td {
                border-top: 1px solid #636363;
                background-color: var(--sz-sample-table-related-row-background-color);
            }
        }
        .row-related-record {
            td {
                background-color: var(--sz-sample-table-related-row-background-color);
            }
            &.first {
                td {
                    border-top: 1px dotted #212121;
                }
            }
            &:last-child td {
                border-bottom: none;
            }
        }
        .row-record, .row-related-record {
            &.data-source-not-selected {
                td {
                    background-color: var(--sz-sample-table-expanded-row-background-color);
                }
            }
        }
    }
    /* coloring specific to types of tables */
    &.sample-type-ambiguous-matches,
    &.sample-type-possible-matches,
    &.sample-type-possible-relations,
    &.sample-type-disclosed-relations {
        .data-table {
            .row-entity, .row-record {
                td {
                    background-color: var(--sz-sample-table-entity-row-background-color);
                }
            }
            .row-related-entity, .row-related-record {
                td {
                    background-color: var(--sz-sample-table-related-row-background-color);
                }
            }
        }
    }

    .control-ribbon {
        position: relative;
        display: inline-flex;
        flex-direction: row;
        flex-wrap: nowrap;
        justify-content: center;
        align-items: center;
        top: -5px;
        float: right;

        .control-ribbon-buttons {
            position: relative;
            display: inline-flex;
            flex-direction: row;
            height: 20px;
            margin-left: 10px;
            
            button {
                display: flex;
                align-items: center;
                border: 1px solid #666;
                padding: 0 5px;
                min-width: 25px;
                line-height: 20px;
                height: 20px;
                color: #666;
                cursor: pointer;
                border-left: 0;
    
                .mdc-button__label {
                    height: 20px;
                }
            }
            button:first-child {
                border-top-right-radius: 0;
                border-bottom-right-radius: 0;
                border-bottom-left-radius: 10px;
                border-top-left-radius: 10px;
                border-left: 1px solid;
                padding: 0 6px 0 11px;
            }
            button:last-child {
                border-top-left-radius: 0;
                border-bottom-left-radius: 0;
                border-bottom-right-radius: 10px;
                border-top-right-radius: 10px;
                padding: 0 8px 0 5px;
            }
        }
        .sz-mat-menu {
            right: 56px;
            top: 0px;
            position: absolute;
            filter: drop-shadow(0px 8px 5px rgba(0, 0, 0, 0.3));

            .sz-mat-menu-item {
                position: relative;
                border-bottom: 0;
                border-top: 1px solid #666;
                border-left: 1px solid #666;
                border-right: 1px solid #666;
                /*background-color: var(--sz-sample-table-related-row-background-color);*/
                background-color: #fafafa;
                cursor: pointer;
                padding: 0 10px 0 24px;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
                font-size: 11px;
                text-transform: capitalize;
                height: 19px;
                line-height: 19px;
                color: #666;
                white-space: nowrap;

                input {
                    position: absolute;
                    opacity: 0;
                    height: 0;
                    width: 0;
                    cursor: pointer;

                    /* When the checkbox is checked, add a blue background */
                    &:checked ~ .checkmark {
                        /*background-color: #2196F3;
                        border-color: #2196F3;*/
                        /* Show the checkmark when checked */
                        &:after {
                            display: block;
                        }
                    }
                }

                .checkmark {
                    position: absolute;
                    left: 7px;
                    top: 4px;
                    height: 12px;
                    width: 12px;
                    /*background-color: #ddd;
                    border: 1px solid #666;*/
                    
                    /* Create the checkmark/indicator (hidden when not checked) */
                    &:after {
                        content: "";
                        position: absolute;
                        display: none;
                        left: 3px;
                        top: -3px;
                        width: 4px;
                        height: 9px;
                        border: solid #808080;
                        border-width: 0 2px 2px 0;
                        -webkit-transform: rotate(45deg);
                        -ms-transform: rotate(45deg);
                        transform: rotate(45deg);
                    }
                }

                &:hover:not([disabled]), &[aria-expanded=true] {
                    background-color: #ddf4ff;
                }

                &:first-child {
                    border-top: 1px solid #666;
                    border-top-left-radius: 4px;
                    border-top-right-radius: 0;
                }
                &:last-child {
                    border-bottom: 1px solid #636363;
                    border-bottom-left-radius: 4px;
                    border-bottom-right-radius: 4px;
                }
            }
        }
        .has-tooltip .tooltiptext {
            top: 0px;
            right: 40px;
            width: unset;
            padding: 8px 15px;
            white-space: nowrap;
        }
    }

    /* column picker */
    .column-picker {
        position: relative;
        display: inline-block;
        .right {
            right: 0px;
            position: relative;
        }
        
    }

    /* settings picker */
    /*
    button.settings-icon-picker-button {
        position: relative;
        right: 0px;

        border: 1px solid #666;
    }*/

    /* tooltips */
    .has-tooltip {
        .tooltiptext {
            display: inline-block;
            position: absolute;
            top: 2px;
            right: 30px;
            visibility: hidden;
            opacity: 0;
            width: 220px;
            background-color: #3b3b3b;
            color: #fff;
            text-align: center;
            padding: 8px 14px 10px 9px;
            border-radius: 4px;
            font-size: 10px;
            white-space: break-spaces;
            transition: opacity 0.2s ease-out 0.4s;
            filter: drop-shadow(5px 8px 5px rgba(0, 0, 0, 0.3));


            /* Position the tooltip text - see examples below! */
            position: absolute;
            z-index: 7;

            &:not(.no-nubbin):before {
                content: "";
                position: absolute;
                top: 9px;
                right: -15px;
                height: 20px;
                width: 20px;
                background: #3b3b3b;
                box-sizing: border-box;
                transform: rotate(34deg) translate(-50%);
                border-top: inherit;
                border-right: inherit;
                box-shadow: inherit;
                z-index: 6;
            }
        }
        &:hover .tooltiptext {
            visibility: visible;
            display: inline-block;
            opacity: 1;
        }
    }

    /* icons */
    .mdi--sort-descending {
        display: inline-block;
        width: 1em;
        height: 1em;
        --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M19 7h3l-4-4l-4 4h3v14h2M2 17h10v2H2M6 5v2H2V5m0 6h7v2H2z'/%3E%3C/svg%3E");
        background-color: currentColor;
        -webkit-mask-image: var(--svg);
        mask-image: var(--svg);
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: 100% 100%;
        mask-size: 100% 100%;
    }
    .mdi--sort-ascending {
        display: inline-block;
        width: 1em;
        height: 1em;
        --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M19 17h3l-4 4l-4-4h3V3h2M2 17h10v2H2M6 5v2H2V5m0 6h7v2H2z'/%3E%3C/svg%3E");
        background-color: currentColor;
        -webkit-mask-image: var(--svg);
        mask-image: var(--svg);
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: 100% 100%;
        mask-size: 100% 100%;
    }
    .mdi--view-settings-outline {
        display: inline-block;
        width: 1.5em;
        height: 1.5em;
        font-size: 10px;
        --svg: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="%23e8eaed"><g><path d="M0,0h24v24H0V0z" fill="none"/><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></g></svg>');
        background-color: currentColor;
        -webkit-mask-image: var(--svg);
        mask-image: var(--svg);
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: 100% 100%;
        mask-size: 100% 100%;
    }
    .mdi--view-column-outline {
        display: inline-block;
        width: 1.5em;
        height: 1.5em;
        font-size: 11px;
        --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M4 5v13h17V5zm10 2v9h-3V7zM6 7h3v9H6zm13 9h-3V7h3z'/%3E%3C/svg%3E");
        background-color: currentColor;
        -webkit-mask-image: var(--svg);
        mask-image: var(--svg);
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: 100% 100%;
        mask-size: 100% 100%;
      }
      .mdi--filter {
        display: inline-block;
        width: 1em;
        height: 1em;
        --svg: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="%23e8eaed"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/></svg>');
        background-color: currentColor;
        -webkit-mask-image: var(--svg);
        mask-image: var(--svg);
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: 100% 100%;
        mask-size: 100% 100%;
      }
}

.sz-dt-context-menu {
  background-color: #fafafa;
  padding: 4pt;
  font-size: 10pt;
  z-index: 1000;
  box-shadow: 0 0 12pt rgba(0, 0, 0, 0.25);
  border-radius: 4px;
  padding: 0.5em 0 0.5em 0;
  animation: fadeIn 0.1s ease-out;
  opacity:1.0;
  display:block;
}

results matching ""

    No results matching ""