diff --git a/superset-frontend/spec/javascripts/datasource/DatasourceEditor_spec.jsx b/superset-frontend/spec/javascripts/datasource/DatasourceEditor_spec.jsx index 0032c8d2e9..a6758fb203 100644 --- a/superset-frontend/spec/javascripts/datasource/DatasourceEditor_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/DatasourceEditor_spec.jsx @@ -21,11 +21,15 @@ import { shallow } from 'enzyme'; import configureStore from 'redux-mock-store'; import fetchMock from 'fetch-mock'; import thunk from 'redux-thunk'; +import { Radio } from 'react-bootstrap'; +import Icon from 'src/components/Icon'; import Tabs from 'src/common/components/Tabs'; import DatasourceEditor from 'src/datasource/DatasourceEditor'; import Field from 'src/CRUD/Field'; import mockDatasource from 'spec/fixtures/mockDatasource'; +import * as featureFlags from 'src/featureFlags'; +import TableSelector from 'src/components/TableSelector'; const props = { datasource: mockDatasource['7__table'], @@ -44,6 +48,7 @@ describe('DatasourceEditor', () => { let wrapper; let el; let inst; + let isFeatureEnabledMock; beforeEach(() => { el = ; @@ -142,4 +147,65 @@ describe('DatasourceEditor', () => { wrapper.find(Field).find({ fieldKey: 'fetch_values_predicate' }).exists(), ).toBe(true); }); + + describe('enable edit Source tab', () => { + beforeAll(() => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation( + feature => feature === 'ENABLE_DATASET_SOURCE_EDIT', + ); + wrapper = shallow(el, { context: { store } }).dive(); + }); + + afterAll(() => { + isFeatureEnabledMock.mockRestore(); + }); + + it('Source Tab: edit mode', () => { + wrapper.setState({ activeTabKey: 0, isEditMode: true }); + const sourceTab = wrapper.find(Tabs.TabPane).first(); + expect(sourceTab.find(Radio).first().prop('disabled')).toBe(false); + + const icon = sourceTab.find(Icon); + expect(icon.prop('name')).toBe('lock-unlocked'); + + const tableSelector = sourceTab.find(Field).shallow().find(TableSelector); + expect(tableSelector.length).toBe(1); + expect(tableSelector.prop('readOnly')).toBe(false); + }); + + it('Source Tab: readOnly mode', () => { + const sourceTab = wrapper.find(Tabs.TabPane).first(); + expect(sourceTab.find(Radio).length).toBe(2); + expect(sourceTab.find(Radio).first().prop('disabled')).toBe(true); + + const icon = sourceTab.find(Icon); + expect(icon.prop('name')).toBe('lock-locked'); + icon.parent().simulate('click'); + expect(wrapper.state('isEditMode')).toBe(true); + + const tableSelector = sourceTab.find(Field).shallow().find(TableSelector); + expect(tableSelector.length).toBe(1); + expect(tableSelector.prop('readOnly')).toBe(true); + }); + }); + + it('disable edit Source tab', () => { + // when edit is disabled, show readOnly controls and no padlock + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(() => true); + wrapper = shallow(el, { context: { store } }).dive(); + wrapper.setState({ activeTabKey: 0 }); + + const sourceTab = wrapper.find(Tabs.TabPane).first(); + expect(sourceTab.find(Radio).length).toBe(2); + expect(sourceTab.find(Radio).first().prop('disabled')).toBe(true); + + const icon = sourceTab.find(Icon); + expect(icon).toHaveLength(0); + + isFeatureEnabledMock.mockRestore(); + }); }); diff --git a/superset-frontend/src/components/DatabaseSelector.tsx b/superset-frontend/src/components/DatabaseSelector.tsx index 52c3f7a2f3..0d565f9bc5 100644 --- a/superset-frontend/src/components/DatabaseSelector.tsx +++ b/superset-frontend/src/components/DatabaseSelector.tsx @@ -64,6 +64,7 @@ interface DatabaseSelectorProps { onDbChange?: (db: any) => void; onSchemaChange?: (arg0?: any) => {}; onSchemasLoad?: (schemas: Array) => void; + readOnly?: boolean; schema?: string; sqlLabMode?: boolean; onChange?: ({ @@ -87,6 +88,7 @@ export default function DatabaseSelector({ onDbChange, onSchemaChange, onSchemasLoad, + readOnly = false, schema, sqlLabMode = false, }: DatabaseSelectorProps) { @@ -237,7 +239,7 @@ export default function DatabaseSelector({ mutator={dbMutator} placeholder={t('Select a database')} autoSelect - isDisabled={!isDatabaseSelectEnabled} + isDisabled={!isDatabaseSelectEnabled || readOnly} />, null, ); @@ -245,7 +247,7 @@ export default function DatabaseSelector({ function renderSchemaSelect() { const value = schemaOptions.filter(({ value }) => currentSchema === value); - const refresh = !formMode && ( + const refresh = !formMode && !readOnly && ( changeDataBase({ id: dbId }, true)} tooltipContent={t('Force refresh schema list')} @@ -266,6 +268,7 @@ export default function DatabaseSelector({ isLoading={schemaLoading} autosize={false} onChange={item => changeSchema(item)} + isDisabled={readOnly} />, refresh, ); diff --git a/superset-frontend/src/components/TableSelector.tsx b/superset-frontend/src/components/TableSelector.tsx index c5c3a52af2..395b5be834 100644 --- a/superset-frontend/src/components/TableSelector.tsx +++ b/superset-frontend/src/components/TableSelector.tsx @@ -97,6 +97,7 @@ interface TableSelectorProps { onSchemasLoad?: () => void; onTableChange?: (tableName: string, schema: string) => void; onTablesLoad?: (options: Array) => {}; + readOnly?: boolean; schema?: string; sqlLabMode?: boolean; tableName?: string; @@ -116,6 +117,7 @@ const TableSelector: FunctionComponent = ({ onSchemasLoad, onTableChange, onTablesLoad, + readOnly = false, schema, sqlLabMode = true, tableName, @@ -286,28 +288,22 @@ const TableSelector: FunctionComponent = ({ getTableList={fetchTables} handleError={handleError} onChange={onSelectionChange} - onDbChange={onDbChange} - onSchemaChange={onSchemaChange} + onDbChange={readOnly ? undefined : onDbChange} + onSchemaChange={readOnly ? undefined : onSchemaChange} onSchemasLoad={onSchemasLoad} schema={currentSchema} sqlLabMode={sqlLabMode} - isDatabaseSelectEnabled={isDatabaseSelectEnabled} + isDatabaseSelectEnabled={isDatabaseSelectEnabled && !readOnly} + readOnly={readOnly} /> ); } function renderTableSelect() { - let tableSelectPlaceholder; - let tableSelectDisabled = false; - if (database && database.allow_multi_schema_metadata_fetch) { - tableSelectPlaceholder = t('Type to search ...'); - } else { - tableSelectPlaceholder = t('Select table '); - tableSelectDisabled = true; - } const options = tableOptions; let select = null; if (currentSchema && !formMode) { + // dataset editor select = (