mirror of
https://github.com/apache/superset.git
synced 2024-09-17 11:09:47 -04:00
fix(explore): update overwrite button on perm change (#16437)
* fix(explore): update overwrite on perm change * remove redundant user_id prop * fix types * fix user type * fix tests * fix lint
This commit is contained in:
parent
db11c3e6c8
commit
18be181946
@ -42,14 +42,16 @@ describe('SaveModal', () => {
|
|||||||
dashboards: [],
|
dashboards: [],
|
||||||
},
|
},
|
||||||
explore: {
|
explore: {
|
||||||
can_overwrite: true,
|
|
||||||
user_id: '1',
|
|
||||||
datasource: {},
|
datasource: {},
|
||||||
slice: {
|
slice: {
|
||||||
slice_id: 1,
|
slice_id: 1,
|
||||||
slice_name: 'title',
|
slice_name: 'title',
|
||||||
|
owners: [1],
|
||||||
},
|
},
|
||||||
alert: null,
|
alert: null,
|
||||||
|
user: {
|
||||||
|
userId: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const store = mockStore(initialState);
|
const store = mockStore(initialState);
|
||||||
@ -104,7 +106,7 @@ describe('SaveModal', () => {
|
|||||||
|
|
||||||
it('disable overwrite option for non-owner', () => {
|
it('disable overwrite option for non-owner', () => {
|
||||||
const wrapperForNonOwner = getWrapper();
|
const wrapperForNonOwner = getWrapper();
|
||||||
wrapperForNonOwner.setProps({ can_overwrite: false });
|
wrapperForNonOwner.setProps({ userId: 2 });
|
||||||
const overwriteRadio = wrapperForNonOwner.find('#overwrite-radio');
|
const overwriteRadio = wrapperForNonOwner.find('#overwrite-radio');
|
||||||
expect(overwriteRadio).toHaveLength(1);
|
expect(overwriteRadio).toHaveLength(1);
|
||||||
expect(overwriteRadio.prop('disabled')).toBe(true);
|
expect(overwriteRadio.prop('disabled')).toBe(true);
|
||||||
|
@ -620,7 +620,6 @@ function mapStateToProps(state) {
|
|||||||
timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT,
|
timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT,
|
||||||
ownState: dataMask[form_data.slice_id ?? 0]?.ownState, // 0 - unsaved chart
|
ownState: dataMask[form_data.slice_id ?? 0]?.ownState, // 0 - unsaved chart
|
||||||
impressionId,
|
impressionId,
|
||||||
userId: explore.user_id,
|
|
||||||
user: explore.user,
|
user: explore.user,
|
||||||
reports,
|
reports,
|
||||||
};
|
};
|
||||||
|
@ -175,7 +175,7 @@ export default function PropertiesModal({
|
|||||||
buttonStyle="primary"
|
buttonStyle="primary"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
disabled={!owners || submitting || !name}
|
disabled={submitting || !name}
|
||||||
cta
|
cta
|
||||||
>
|
>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
|
@ -34,11 +34,10 @@ const SK_DASHBOARD_ID = 'save_chart_recent_dashboard';
|
|||||||
const SELECT_PLACEHOLDER = t('**Select** a dashboard OR **create** a new one');
|
const SELECT_PLACEHOLDER = t('**Select** a dashboard OR **create** a new one');
|
||||||
|
|
||||||
type SaveModalProps = {
|
type SaveModalProps = {
|
||||||
can_overwrite?: boolean;
|
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
actions: Record<string, any>;
|
actions: Record<string, any>;
|
||||||
form_data?: Record<string, any>;
|
form_data?: Record<string, any>;
|
||||||
userId: string;
|
userId: number;
|
||||||
dashboards: Array<any>;
|
dashboards: Array<any>;
|
||||||
alert?: string;
|
alert?: string;
|
||||||
sliceName?: string;
|
sliceName?: string;
|
||||||
@ -70,7 +69,7 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> {
|
|||||||
saveToDashboardId: null,
|
saveToDashboardId: null,
|
||||||
newSliceName: props.sliceName,
|
newSliceName: props.sliceName,
|
||||||
alert: null,
|
alert: null,
|
||||||
action: props.can_overwrite ? 'overwrite' : 'saveas',
|
action: this.canOverwriteSlice() ? 'overwrite' : 'saveas',
|
||||||
};
|
};
|
||||||
this.onDashboardSelectChange = this.onDashboardSelectChange.bind(this);
|
this.onDashboardSelectChange = this.onDashboardSelectChange.bind(this);
|
||||||
this.onSliceNameChange = this.onSliceNameChange.bind(this);
|
this.onSliceNameChange = this.onSliceNameChange.bind(this);
|
||||||
@ -78,6 +77,10 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> {
|
|||||||
this.saveOrOverwrite = this.saveOrOverwrite.bind(this);
|
this.saveOrOverwrite = this.saveOrOverwrite.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canOverwriteSlice(): boolean {
|
||||||
|
return this.props.slice?.owners?.includes(this.props.userId);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.actions.fetchDashboards(this.props.userId).then(() => {
|
this.props.actions.fetchDashboards(this.props.userId).then(() => {
|
||||||
const dashboardIds = this.props.dashboards.map(
|
const dashboardIds = this.props.dashboards.map(
|
||||||
@ -196,7 +199,7 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> {
|
|||||||
disabled={!this.state.newSliceName}
|
disabled={!this.state.newSliceName}
|
||||||
data-test="btn-modal-save"
|
data-test="btn-modal-save"
|
||||||
>
|
>
|
||||||
{!this.props.can_overwrite && this.props.slice
|
{!this.canOverwriteSlice() && this.props.slice
|
||||||
? t('Save as new chart')
|
? t('Save as new chart')
|
||||||
: t('Save')}
|
: t('Save')}
|
||||||
</Button>
|
</Button>
|
||||||
@ -225,7 +228,7 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> {
|
|||||||
<FormItem data-test="radio-group">
|
<FormItem data-test="radio-group">
|
||||||
<Radio
|
<Radio
|
||||||
id="overwrite-radio"
|
id="overwrite-radio"
|
||||||
disabled={!(this.props.can_overwrite && this.props.slice)}
|
disabled={!this.canOverwriteSlice()}
|
||||||
checked={this.state.action === 'overwrite'}
|
checked={this.state.action === 'overwrite'}
|
||||||
onChange={() => this.changeAction('overwrite')}
|
onChange={() => this.changeAction('overwrite')}
|
||||||
data-test="save-overwrite-radio"
|
data-test="save-overwrite-radio"
|
||||||
@ -289,8 +292,7 @@ function mapStateToProps({
|
|||||||
return {
|
return {
|
||||||
datasource: explore.datasource,
|
datasource: explore.datasource,
|
||||||
slice: explore.slice,
|
slice: explore.slice,
|
||||||
can_overwrite: explore.can_overwrite,
|
userId: explore.user?.userId,
|
||||||
userId: explore.user_id,
|
|
||||||
dashboards: saveModal.dashboards,
|
dashboards: saveModal.dashboards,
|
||||||
alert: saveModal.saveModalAlert,
|
alert: saveModal.saveModalAlert,
|
||||||
};
|
};
|
||||||
|
@ -219,6 +219,7 @@ export default function exploreReducer(state = {}, action) {
|
|||||||
slice: {
|
slice: {
|
||||||
...state.slice,
|
...state.slice,
|
||||||
...action.slice,
|
...action.slice,
|
||||||
|
owners: action.slice.owners ?? null,
|
||||||
},
|
},
|
||||||
sliceName: action.slice.slice_name ?? state.sliceName,
|
sliceName: action.slice.slice_name ?? state.sliceName,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,10 @@ import {
|
|||||||
ControlStateMapping,
|
ControlStateMapping,
|
||||||
DatasourceMeta,
|
DatasourceMeta,
|
||||||
} from '@superset-ui/chart-controls';
|
} from '@superset-ui/chart-controls';
|
||||||
import { CommonBootstrapData } from 'src/types/bootstrapTypes';
|
import {
|
||||||
|
CommonBootstrapData,
|
||||||
|
UserWithPermissionsAndRoles,
|
||||||
|
} from 'src/types/bootstrapTypes';
|
||||||
import getToastsFromPyFlashMessages from 'src/messageToasts/utils/getToastsFromPyFlashMessages';
|
import getToastsFromPyFlashMessages from 'src/messageToasts/utils/getToastsFromPyFlashMessages';
|
||||||
|
|
||||||
import { ChartState, Slice } from 'src/explore/types';
|
import { ChartState, Slice } from 'src/explore/types';
|
||||||
@ -37,15 +40,15 @@ export interface ExlorePageBootstrapData extends JsonObject {
|
|||||||
can_add: boolean;
|
can_add: boolean;
|
||||||
can_download: boolean;
|
can_download: boolean;
|
||||||
can_overwrite: boolean;
|
can_overwrite: boolean;
|
||||||
|
common: CommonBootstrapData;
|
||||||
datasource: DatasourceMeta;
|
datasource: DatasourceMeta;
|
||||||
form_data: QueryFormData;
|
|
||||||
datasource_id: number;
|
datasource_id: number;
|
||||||
datasource_type: DatasourceType;
|
datasource_type: DatasourceType;
|
||||||
|
forced_height: string | null;
|
||||||
|
form_data: QueryFormData;
|
||||||
slice: Slice | null;
|
slice: Slice | null;
|
||||||
standalone: boolean;
|
standalone: boolean;
|
||||||
user_id: number;
|
user: UserWithPermissionsAndRoles;
|
||||||
forced_height: string | null;
|
|
||||||
common: CommonBootstrapData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getInitialState(
|
export default function getInitialState(
|
||||||
|
@ -471,9 +471,9 @@ sqlatable_user = Table(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SqlaTable( # pylint: disable=too-many-instance-attributes,too-many-public-methods
|
class SqlaTable(
|
||||||
Model, BaseDatasource
|
Model, BaseDatasource
|
||||||
):
|
): # pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||||
"""An ORM object for SqlAlchemy table references"""
|
"""An ORM object for SqlAlchemy table references"""
|
||||||
|
|
||||||
type = "table"
|
type = "table"
|
||||||
|
@ -201,9 +201,7 @@ class Slice( # pylint: disable=too-many-public-methods
|
|||||||
"form_data": self.form_data,
|
"form_data": self.form_data,
|
||||||
"query_context": self.query_context,
|
"query_context": self.query_context,
|
||||||
"modified": self.modified(),
|
"modified": self.modified(),
|
||||||
"owners": [
|
"owners": [owner.id for owner in self.owners],
|
||||||
f"{owner.first_name} {owner.last_name}" for owner in self.owners
|
|
||||||
],
|
|
||||||
"slice_id": self.id,
|
"slice_id": self.id,
|
||||||
"slice_name": self.slice_name,
|
"slice_name": self.slice_name,
|
||||||
"slice_url": self.slice_url,
|
"slice_url": self.slice_url,
|
||||||
|
@ -716,7 +716,6 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods
|
|||||||
def explore( # pylint: disable=too-many-locals
|
def explore( # pylint: disable=too-many-locals
|
||||||
self, datasource_type: Optional[str] = None, datasource_id: Optional[int] = None
|
self, datasource_type: Optional[str] = None, datasource_id: Optional[int] = None
|
||||||
) -> FlaskResponse:
|
) -> FlaskResponse:
|
||||||
user_id = g.user.get_id() if g.user else None
|
|
||||||
form_data, slc = get_form_data(use_slice_data=True)
|
form_data, slc = get_form_data(use_slice_data=True)
|
||||||
query_context = request.form.get("query_context")
|
query_context = request.form.get("query_context")
|
||||||
# Flash the SIP-15 message if the slice is owned by the current user and has not
|
# Flash the SIP-15 message if the slice is owned by the current user and has not
|
||||||
@ -843,14 +842,12 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods
|
|||||||
bootstrap_data = {
|
bootstrap_data = {
|
||||||
"can_add": slice_add_perm,
|
"can_add": slice_add_perm,
|
||||||
"can_download": slice_download_perm,
|
"can_download": slice_download_perm,
|
||||||
"can_overwrite": slice_overwrite_perm,
|
|
||||||
"datasource": datasource_data,
|
"datasource": datasource_data,
|
||||||
"form_data": form_data,
|
"form_data": form_data,
|
||||||
"datasource_id": datasource_id,
|
"datasource_id": datasource_id,
|
||||||
"datasource_type": datasource_type,
|
"datasource_type": datasource_type,
|
||||||
"slice": slc.data if slc else None,
|
"slice": slc.data if slc else None,
|
||||||
"standalone": standalone_mode,
|
"standalone": standalone_mode,
|
||||||
"user_id": user_id,
|
|
||||||
"user": bootstrap_user_data(g.user, include_perms=True),
|
"user": bootstrap_user_data(g.user, include_perms=True),
|
||||||
"forced_height": request.args.get("height"),
|
"forced_height": request.args.get("height"),
|
||||||
"common": common_bootstrap_payload(),
|
"common": common_bootstrap_payload(),
|
||||||
@ -1020,7 +1017,6 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods
|
|||||||
response = {
|
response = {
|
||||||
"can_add": slice_add_perm,
|
"can_add": slice_add_perm,
|
||||||
"can_download": slice_download_perm,
|
"can_download": slice_download_perm,
|
||||||
"can_overwrite": is_owner(slc, g.user),
|
|
||||||
"form_data": slc.form_data,
|
"form_data": slc.form_data,
|
||||||
"slice": slc.data,
|
"slice": slc.data,
|
||||||
"dashboard_url": dash.url if dash else None,
|
"dashboard_url": dash.url if dash else None,
|
||||||
|
Loading…
Reference in New Issue
Block a user