diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts index b1e9bbd8fd..42c4b2241c 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts @@ -134,8 +134,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { isReadOnly: true, width: 25, headerCssStyles: { - 'border': 'none', - 'background-color': '#FFFFFF' + 'border': 'none' }, rowCssStyles: { 'border-top': 'solid 1px #ccc', @@ -151,7 +150,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 175, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -168,7 +166,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 150, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -185,7 +182,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', 'text-align': 'left', ...cssStyles.tableHeader }, @@ -204,7 +200,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 150, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF' }, rowCssStyles: { 'border-top': 'solid 1px #ccc', @@ -262,7 +257,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 200, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -279,7 +273,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 350, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -299,7 +292,6 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage { width: 50, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF' }, rowCssStyles: { 'border-top': 'solid 1px #ccc', diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts index 9c2a8f972d..d769bb9ed6 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts @@ -82,8 +82,7 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { isReadOnly: true, width: 25, headerCssStyles: { - 'border': 'none', - 'background-color': '#FFFFFF' + 'border': 'none' }, rowCssStyles: { 'border-top': 'solid 1px #ccc', @@ -99,7 +98,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -116,7 +114,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 150, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -133,7 +130,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', 'text-align': 'left', ...cssStyles.tableHeader }, @@ -151,8 +147,7 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { isReadOnly: true, width: 150, headerCssStyles: { - 'border': 'none', - 'background-color': '#FFFFFF' + 'border': 'none' }, rowCssStyles: { 'border-top': 'solid 1px #ccc', @@ -186,7 +181,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 125, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -203,7 +197,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', ...cssStyles.tableHeader }, rowCssStyles: { @@ -225,7 +218,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', 'text-align': 'left', ...cssStyles.tableHeader }, @@ -246,7 +238,6 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage { width: 100, headerCssStyles: { 'border': 'none', - 'background-color': '#FFFFFF', 'text-align': 'left', ...cssStyles.tableHeader }, diff --git a/extensions/machine-learning-services/src/common/constants.ts b/extensions/machine-learning-services/src/common/constants.ts index 3d80a20f1f..70d7506abb 100644 --- a/extensions/machine-learning-services/src/common/constants.ts +++ b/extensions/machine-learning-services/src/common/constants.ts @@ -168,7 +168,7 @@ export const installMlsWindowsDocs = 'https://docs.microsoft.com/sql/advanced-an // export namespace cssStyles { export const title = { 'font-size': '14px', 'font-weight': '600' }; - export const tableHeader = { 'text-align': 'left', 'font-weight': 'bold', 'text-transform': 'uppercase', 'font-size': '10px', 'user-select': 'text', 'border': 'none', 'background-color': '#FFFFFF' }; + export const tableHeader = { 'text-align': 'left', 'font-weight': 'bold', 'text-transform': 'uppercase', 'font-size': '10px', 'user-select': 'text', 'border': 'none' }; export const tableRow = { 'border-top': 'solid 1px #ccc', 'border-bottom': 'solid 1px #ccc', 'border-left': 'none', 'border-right': 'none' }; export const hyperlink = { 'user-select': 'text', 'color': '#0078d4', 'text-decoration': 'underline', 'cursor': 'pointer' }; export const text = { 'margin-block-start': '0px', 'margin-block-end': '0px' }; diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts index cdbc7ffe97..84f47a837a 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts @@ -16,7 +16,6 @@ const localize = nls.loadMessageBundle(); const NumberInputWidth = '100px'; const inputWidth = '180px'; const labelWidth = '200px'; -const spaceBetweenFields = '5px'; export class ServiceSettingsPage extends WizardPageBase { private inputComponents: InputComponents = {}; @@ -115,177 +114,6 @@ export class ServiceSettingsPage extends WizardPageBase { ] }; - const hintTextForStorageFields = localize('deployCluster.storageFieldTooltip', "Use controller settings"); - const storageSectionInfo: SectionInfo = { - title: '', - labelWidth: '0px', - inputWidth: inputWidth, - spaceBetweenFields: spaceBetweenFields, - rows: [{ - fields: [ - { - type: FieldType.ReadonlyText, - label: '', - required: false, - defaultValue: localize('deployCluster.DataStorageClassName', "Storage class for data"), - variableName: '', - labelWidth: labelWidth - }, { - type: FieldType.ReadonlyText, - label: '', - required: false, - defaultValue: localize('deployCluster.DataClaimSize', "Claim size for data (GB)"), - variableName: '' - }, { - type: FieldType.ReadonlyText, - label: '', - required: false, - defaultValue: localize('deployCluster.LogStorageClassName', "Storage class for logs"), - variableName: '', - }, { - type: FieldType.ReadonlyText, - label: '', - required: false, - defaultValue: localize('deployCluster.LogsClaimSize', "Claim size for logs (GB)"), - variableName: '' - } - ] - }, - { - fields: [ - { - type: FieldType.Text, - label: localize('deployCluster.ControllerText', "Controller"), - variableName: VariableNames.ControllerDataStorageClassName_VariableName, - required: true, - description: localize('deployCluster.AdvancedStorageDescription', "By default Controller storage settings will be applied to other services as well, you can expand the advanced storage settings to configure storage for other services."), - labelWidth: labelWidth - }, { - type: FieldType.Number, - label: '', - required: true, - min: 1, - variableName: VariableNames.ControllerDataStorageSize_VariableName, - }, { - type: FieldType.Text, - label: '', - required: true, - min: 1, - variableName: VariableNames.ControllerLogsStorageClassName_VariableName, - }, { - type: FieldType.Number, - label: '', - required: true, - min: 1, - variableName: VariableNames.ControllerLogsStorageSize_VariableName, - } - ] - } - ] - }; - const advancedStorageSectionInfo: SectionInfo = { - title: localize('deployCluster.AdvancedStorageSectionTitle', "Advanced storage settings"), - labelWidth: '0px', - inputWidth: inputWidth, - spaceBetweenFields: spaceBetweenFields, - collapsible: true, - collapsed: true, - rows: [{ - fields: [ - { - type: FieldType.Text, - label: localize('deployCluster.StoragePool', "Storage pool (HDFS)"), - required: false, - variableName: VariableNames.HDFSDataStorageClassName_VariableName, - placeHolder: hintTextForStorageFields, - labelWidth: labelWidth - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.HDFSDataStorageSize_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Text, - label: '', - required: false, - variableName: VariableNames.HDFSLogsStorageClassName_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.HDFSLogsStorageSize_VariableName, - placeHolder: hintTextForStorageFields - } - ] - }, { - fields: [ - { - type: FieldType.Text, - label: localize('deployCluster.DataPool', "Data pool"), - required: false, - variableName: VariableNames.DataPoolDataStorageClassName_VariableName, - labelWidth: labelWidth, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.DataPoolDataStorageSize_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Text, - label: '', - required: false, - variableName: VariableNames.DataPoolLogsStorageClassName_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.DataPoolLogsStorageSize_VariableName, - placeHolder: hintTextForStorageFields - } - ] - }, { - fields: [ - { - type: FieldType.Text, - label: localize('deployCluster.MasterSqlText', "SQL Server Master"), - required: false, - variableName: VariableNames.SQLServerDataStorageClassName_VariableName, - labelWidth: labelWidth, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.SQLServerDataStorageSize_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Text, - label: '', - required: false, - variableName: VariableNames.SQLServerLogsStorageClassName_VariableName, - placeHolder: hintTextForStorageFields - }, { - type: FieldType.Number, - label: '', - required: false, - min: 1, - variableName: VariableNames.SQLServerLogsStorageSize_VariableName, - placeHolder: hintTextForStorageFields - } - ] - }] - }; - this.pageObject.registerContent((view: azdata.ModelView) => { const createSectionFunc = (sectionInfo: SectionInfo): azdata.GroupContainer => { return createSection({ @@ -304,12 +132,7 @@ export class ServiceSettingsPage extends WizardPageBase { }; const scaleSection = createSectionFunc(scaleSectionInfo); this.endpointSection = this.createEndpointSection(view); - const storageSection = createSectionFunc(storageSectionInfo); - const advancedStorageSection = createSectionFunc(advancedStorageSectionInfo); - const storageContainer = createGroupContainer(view, [storageSection, advancedStorageSection], { - header: localize('deployCluster.StorageSectionTitle', "Storage settings"), - collapsible: true - }); + const storageSection = this.createStorageSection(view); this.handleSparkSettingEvents(); const form = view.modelBuilder.formContainer().withFormItems([ @@ -321,7 +144,7 @@ export class ServiceSettingsPage extends WizardPageBase { component: this.endpointSection }, { title: '', - component: storageContainer + component: storageSection } ]).withLayout({ width: '100%' }).component(); return view.initializeModel(form); @@ -392,6 +215,112 @@ export class ServiceSettingsPage extends WizardPageBase { }); } + private createStorageSection(view: azdata.ModelView): azdata.GroupContainer { + const hintTextForStorageFields = localize('deployCluster.storageFieldTooltip', "Use controller settings"); + const controllerLabel = createLabel(view, + { + text: localize('deployCluster.ControllerText', "Controller"), + width: inputWidth, + required: true, + description: localize('deployCluster.AdvancedStorageDescription', "By default Controller storage settings will be applied to other services as well, you can expand the advanced storage settings to configure storage for other services.") + }); + const controllerDataStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.controllerDataStorageClass', "Controller's data storage class"), width: inputWidth, required: true }); + const controllerDataStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.controllerDataStorageClaimSize', "Controller's data storage claim size"), width: inputWidth, required: true, min: 1 }); + const controllerLogsStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.controllerLogsStorageClass', "Controller's logs storage class"), width: inputWidth, required: true }); + const controllerLogsStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.controllerLogsStorageClaimSize', "Controller's logs storage claim size"), width: inputWidth, required: true, min: 1 }); + + const storagePoolLabel = createLabel(view, + { + text: localize('deployCluster.StoragePool', "Storage pool (HDFS)"), + width: inputWidth, + required: false + }); + const storagePoolDataStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.storagePoolDataStorageClass', "Storage pool's data storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const storagePoolDataStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.storagePoolDataStorageClaimSize', "Storage pool's data storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + const storagePoolLogsStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.storagePoolLogsStorageClass', "Storage pool's logs storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const storagePoolLogsStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.storagePoolLogsStorageClaimSize', "Storage pool's logs storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + + const dataPoolLabel = createLabel(view, + { + text: localize('deployCluster.DataPool', "Data pool"), + width: inputWidth, + required: false + }); + const dataPoolDataStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.dataPoolDataStorageClass', "Data pool's data storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const dataPoolDataStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.dataPoolDataStorageClaimSize', "Data pool's data storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + const dataPoolLogsStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.dataPoolLogsStorageClass', "Data pool's logs storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const dataPoolLogsStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.dataPoolLogsStorageClaimSize', "Data pool's logs storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + + + const sqlServerMasterLabel = createLabel(view, + { + text: localize('deployCluster.MasterSqlText', "SQL Server Master"), + width: inputWidth, + required: false + }); + const sqlServerMasterDataStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.sqlServerMasterDataStorageClass', "SQL Server master's data storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const sqlServerMasterDataStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.sqlServerMasterDataStorageClaimSize', "SQL Server master's data storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + const sqlServerMasterLogsStorageClassInput = createTextInput(view, { ariaLabel: localize('deployCluster.sqlServerMasterLogsStorageClass', "SQL Server master's logs storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields }); + const sqlServerMasterLogsStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.sqlServerMasterLogsStorageClaimSize', "SQL Server master's logs storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields }); + + this.inputComponents[VariableNames.ControllerDataStorageClassName_VariableName] = { component: controllerDataStorageClassInput }; + this.inputComponents[VariableNames.ControllerDataStorageSize_VariableName] = { component: controllerDataStorageClaimSizeInput }; + this.inputComponents[VariableNames.ControllerLogsStorageClassName_VariableName] = { component: controllerLogsStorageClassInput }; + this.inputComponents[VariableNames.ControllerLogsStorageSize_VariableName] = { component: controllerLogsStorageClaimSizeInput }; + this.inputComponents[VariableNames.HDFSDataStorageClassName_VariableName] = { component: storagePoolDataStorageClassInput }; + this.inputComponents[VariableNames.HDFSDataStorageSize_VariableName] = { component: storagePoolDataStorageClaimSizeInput }; + this.inputComponents[VariableNames.HDFSLogsStorageClassName_VariableName] = { component: storagePoolLogsStorageClassInput }; + this.inputComponents[VariableNames.HDFSLogsStorageSize_VariableName] = { component: storagePoolLogsStorageClaimSizeInput }; + this.inputComponents[VariableNames.DataPoolDataStorageClassName_VariableName] = { component: dataPoolDataStorageClassInput }; + this.inputComponents[VariableNames.DataPoolDataStorageSize_VariableName] = { component: dataPoolDataStorageClaimSizeInput }; + this.inputComponents[VariableNames.DataPoolLogsStorageClassName_VariableName] = { component: dataPoolLogsStorageClassInput }; + this.inputComponents[VariableNames.DataPoolLogsStorageSize_VariableName] = { component: dataPoolLogsStorageClaimSizeInput }; + this.inputComponents[VariableNames.SQLServerDataStorageClassName_VariableName] = { component: sqlServerMasterDataStorageClassInput }; + this.inputComponents[VariableNames.SQLServerDataStorageSize_VariableName] = { component: sqlServerMasterDataStorageClaimSizeInput }; + this.inputComponents[VariableNames.SQLServerLogsStorageClassName_VariableName] = { component: sqlServerMasterLogsStorageClassInput }; + this.inputComponents[VariableNames.SQLServerLogsStorageSize_VariableName] = { component: sqlServerMasterLogsStorageClaimSizeInput }; + + const storageSettingTable = view.modelBuilder.declarativeTable() + .withProperties( + { + columns: [ + this.createStorageSettingColumn(localize('deployCluster.ServiceName', "Service name"), false), + this.createStorageSettingColumn(localize('deployCluster.DataStorageClassName', "Storage class for data")), + this.createStorageSettingColumn(localize('deployCluster.DataClaimSize', "Claim size for data (GB)")), + this.createStorageSettingColumn(localize('deployCluster.LogStorageClassName', "Storage class for logs")), + this.createStorageSettingColumn(localize('deployCluster.LogsClaimSize', "Claim size for logs (GB)")) + ], + data: [[controllerLabel, controllerDataStorageClassInput, controllerDataStorageClaimSizeInput, controllerLogsStorageClassInput, controllerLogsStorageClaimSizeInput], + [storagePoolLabel, storagePoolDataStorageClassInput, storagePoolDataStorageClaimSizeInput, storagePoolLogsStorageClassInput, storagePoolLogsStorageClaimSizeInput], + [dataPoolLabel, dataPoolDataStorageClassInput, dataPoolDataStorageClaimSizeInput, dataPoolLogsStorageClassInput, dataPoolLogsStorageClaimSizeInput], + [sqlServerMasterLabel, sqlServerMasterDataStorageClassInput, sqlServerMasterDataStorageClaimSizeInput, sqlServerMasterLogsStorageClassInput, sqlServerMasterLogsStorageClaimSizeInput]], + ariaLabel: localize('deployCluster.StorageSettings', "Storage settings") + }) + .component(); + return createGroupContainer(view, [storageSettingTable], { + header: localize('deployCluster.StorageSectionTitle', "Storage settings"), + collapsible: true, + collapsed: false + }); + } + + private createStorageSettingColumn(title: string, showText: boolean = true): azdata.DeclarativeTableColumn { + return { + displayName: showText ? title : '', + ariaLabel: title, + valueType: azdata.DeclarativeDataType.component, + isReadOnly: true, + width: inputWidth, + headerCssStyles: { + 'border': 'none', + 'font-weight': 'inherit' + }, + rowCssStyles: { + 'border': 'none' + } + }; + } + public onEnter(): void { this.setInputBoxValue(VariableNames.ComputePoolScale_VariableName); this.setInputBoxValue(VariableNames.DataPoolScale_VariableName); diff --git a/src/sql/workbench/browser/modelComponents/declarativeTable.component.ts b/src/sql/workbench/browser/modelComponents/declarativeTable.component.ts index c7debb7b62..26bb2e5540 100644 --- a/src/sql/workbench/browser/modelComponents/declarativeTable.component.ts +++ b/src/sql/workbench/browser/modelComponents/declarativeTable.component.ts @@ -31,14 +31,14 @@ export enum DeclarativeDataType { - + -
{{column.displayName}}{{column.displayName}}
+ diff --git a/src/sql/workbench/browser/modelComponents/media/declarativeTable.css b/src/sql/workbench/browser/modelComponents/media/declarativeTable.css index 35d0a1e89c..d1c3591786 100644 --- a/src/sql/workbench/browser/modelComponents/media/declarativeTable.css +++ b/src/sql/workbench/browser/modelComponents/media/declarativeTable.css @@ -11,36 +11,11 @@ .declarative-table-header { padding: 5px; - border-left: 1px solid gray; - border-top: 1px solid gray; - border-right: 1px solid gray; - border-bottom: 1px solid gray; - background-color: #F5F5F5; + border: 1px solid; vertical-align: top; } -.vs-dark .declarative-table-header -.hc-black .declarative-table-header { - padding: 5px; - border-left: 1px solid gray; - border-top: 1px solid gray; - border-right: 1px solid gray; - border-bottom: 1px solid gray; - background-color: #333334; -} - .declarative-table-cell { padding: 5px; - border-left: 1px solid gray; - border-top: 1px solid gray; - border-right: 1px solid gray; - border-bottom: 1px solid gray; -} - -.declarative-table [role="gridcell"]:focus, -.declarative-table [role="gridcell"] *:focus, -.declarative-table [role="grid"] [tabindex="0"]:focus { - outline: #005a9c; - outline-style: dotted; - outline-width: 3px; + border-left: 1px solid; }