Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move "User access list" to Settings #6166

Merged
merged 8 commits into from
Apr 26, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Add filter functionality to "Access Permissions" column to filter for public datasets.
- Removed `isActive` and `isPublic` columns to save screen space.
- Changed data layer entries to display layer names instead of categories, e.g. "color" --> "axons".
- Moved the list of "user with access to the selected dataset" from the dashboard to the respective dataset's settings (Sharing Tab). [6166](https://github.com/scalableminds/webknossos/pull/6166)

### Fixed
- Fixed a bug that led to an error when drag-'n-dropping an empty volume annotation in the dataset view. [#6116](https://github.com/scalableminds/webknossos/pull/6116)
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/admin/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { OxalisState } from "oxalis/store";
import Store from "oxalis/store";
import LinkButton from "components/link_button";
import { getDatastores, sendInvitesForOrganization } from "admin/admin_rest_api";
import DatasetImportView from "dashboard/dataset/dataset_import_view";
import DatasetSettingsView from "dashboard/dataset/dataset_settings_view";
import DatasetUploadView from "admin/dataset/dataset_upload_view";
import RegistrationForm from "admin/auth/registration_form";
import CreditsFooter from "components/credits_footer";
Expand Down Expand Up @@ -502,7 +502,7 @@ class OnboardingView extends React.PureComponent<Props, State> {
)}
{this.state.datasetNameToImport != null && (
<Modal visible width="85%" footer={null} maskClosable={false} onCancel={this.advanceStep}>
<DatasetImportView
<DatasetSettingsView
isEditingMode={false}
datasetId={{
name: this.state.datasetNameToImport || "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { APIDataset, APIUser } from "types/api_flow_types";
import { getDatasetAccessList } from "admin/admin_rest_api";
import { handleGenericError } from "libs/error_handling";
import { stringToColor } from "libs/format_utils";

type Props = {
dataset: APIDataset;
};
Expand Down Expand Up @@ -66,7 +67,6 @@ export default class DatasetAccessListView extends React.PureComponent<Props, St
renderTable() {
return (
<div>
<h5>Users with Access Rights</h5>
<ul>
{this.state.datasetUsers.map((user: APIUser) => (
<li key={user.id}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ import { getDatasetExtentAsString } from "oxalis/model/accessors/dataset_accesso
import { stringToColor, formatScale } from "libs/format_utils";
import { trackAction } from "oxalis/model/helpers/analytics";
import CategorizationLabel from "oxalis/view/components/categorization_label";
import DatasetAccessListView from "dashboard/advanced_dataset/dataset_access_list_view";
import DatasetActionView from "dashboard/advanced_dataset/dataset_action_view";
import EditableTextIcon from "oxalis/view/components/editable_text_icon";
import FixedExpandableTable from "components/fixed_expandable_table";
import FormattedDate from "components/formatted_date";
import * as Utils from "libs/utils";
import FixedExpandableTable from "components/fixed_expandable_table";

const { Column } = Table;
const typeHint: APIMaybeUnimportedDataset[] = [];
Expand All @@ -38,7 +37,6 @@ type Props = {
searchQuery: string;
searchTags: Array<string>;
isUserAdmin: boolean;
isUserTeamManager: boolean;
isUserDatasetManager: boolean;
datasetFilteringMode: DatasetFilteringMode;
reloadDataset: (arg0: APIDatasetId, arg1: Array<APIMaybeUnimportedDataset>) => Promise<void>;
Expand Down Expand Up @@ -184,7 +182,6 @@ class DatasetTable extends React.PureComponent<Props, State> {
}

render() {
const { isUserAdmin, isUserTeamManager } = this.props;
const filteredDataSource = this.getFilteredDatasets();
const { sortedInfo } = this.state;
const dataSourceSortedByRank = useLruRank
Expand Down Expand Up @@ -249,11 +246,6 @@ class DatasetTable extends React.PureComponent<Props, State> {
defaultPageSize: 50,
}}
onChange={this.handleChange}
expandedRowRender={
isUserAdmin || isUserTeamManager
? (dataset) => <DatasetAccessListView dataset={dataset} />
: undefined
}
locale={{
emptyText: this.renderEmptyText(),
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {

const FormItem = Form.Item;

export default function SimpleAdvancedDataForm({
export default function DatasetSettingsDataTab({
isReadOnlyDataset,
form,
activeDataSourceEditMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import type { RouteComponentProps } from "react-router-dom";
import { withRouter } from "react-router-dom";
import { DatasetCacheContext } from "dashboard/dataset/dataset_cache_provider";
import { confirmAsync } from "./helper_components";

type Props = {
datasetId: APIDatasetId;
history: RouteComponentProps["history"];
};

const ImportDeleteComponent = ({ datasetId, history }: Props) => {
const DatasetSettingsDeleteTab = ({ datasetId, history }: Props) => {
const [isDeleting, setIsDeleting] = useState(false);
const [dataset, setDataset] = useState<APIDataset | null | undefined>(null);
const datasetContext = useContext(DatasetCacheContext);
Expand Down Expand Up @@ -66,4 +67,4 @@ const ImportDeleteComponent = ({ datasetId, history }: Props) => {
);
};

export default withRouter<RouteComponentProps & Props, any>(ImportDeleteComponent);
export default withRouter<RouteComponentProps & Props, any>(DatasetSettingsDeleteTab);
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Input, Col, Row, DatePicker } from "antd";
import React from "react";
import { FormItemWithInfo } from "./helper_components";
export default function ImportGeneralComponent() {

export default function DatasetSettingsMetadataTab() {
return (
<div>
<Row gutter={48}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import { Button, Input, Checkbox, Tooltip, FormInstance } from "antd";
import React, { useState, useEffect } from "react";
import type { APIDataset, APIDatasetId } from "types/api_flow_types";
import { RouteComponentProps, withRouter } from "react-router-dom";
import { connect } from "react-redux";
import { Button, Input, Checkbox, Tooltip, FormInstance, Collapse } from "antd";
import { CopyOutlined, RetweetOutlined } from "@ant-design/icons";
import type { APIDataset, APIDatasetId, APIUser } from "types/api_flow_types";
import { AsyncButton } from "components/async_clickables";
import {
getDatasetSharingToken,
getDataset,
revokeDatasetSharingToken,
} from "admin/admin_rest_api";
import { getDatasetSharingToken, revokeDatasetSharingToken } from "admin/admin_rest_api";
import Toast from "libs/toast";
import features from "features";
import window from "libs/window";
import TeamSelectionComponent from "dashboard/dataset/team_selection_component";
import { CopyOutlined, RetweetOutlined } from "@ant-design/icons";
import DatasetAccessListView from "dashboard/advanced_dataset/dataset_access_list_view";
import { OxalisState } from "oxalis/store";
import { isUserAdminOrTeamManager } from "libs/utils";
import { FormItemWithInfo } from "./helper_components";

type Props = {
form: FormInstance | null;
datasetId: APIDatasetId;
dataset: APIDataset | null | undefined;
hasNoAllowedTeams: boolean;
activeUser: APIUser | null | undefined;
};
export default function ImportSharingComponent({ form, datasetId, hasNoAllowedTeams }: Props) {

function DatasetSettingsSharingTab({
form,
datasetId,
dataset,
hasNoAllowedTeams,
activeUser,
}: Props) {
const [sharingToken, setSharingToken] = useState("");
const [dataSet, setDataSet] = useState<APIDataset | null | undefined>(null);

const allowedTeamsComponent = (
<FormItemWithInfo
name={["dataset", "allowedTeams"]}
Expand All @@ -39,9 +50,7 @@ export default function ImportSharingComponent({ form, datasetId, hasNoAllowedTe

async function fetch() {
const newSharingToken = await getDatasetSharingToken(datasetId);
const newDataSet = await getDataset(datasetId);
setSharingToken(newSharingToken);
setDataSet(newDataSet);
}

useEffect(() => {
Expand Down Expand Up @@ -77,6 +86,7 @@ export default function ImportSharingComponent({ form, datasetId, hasNoAllowedTe

function getSharingLink() {
if (!form) return undefined;

const doesNeedToken = !form.getFieldValue("dataset.isPublic");
const tokenSuffix = `?token=${sharingToken}`;
return `${window.location.origin}/datasets/${datasetId.owningOrganization}/${
Expand All @@ -85,13 +95,26 @@ export default function ImportSharingComponent({ form, datasetId, hasNoAllowedTe
}

function getAllowUsageCode() {
if (dataSet != null) {
const dataStoreName = dataSet.dataStore.name;
const dataStoreURL = dataSet.dataStore.url;
if (dataset != null) {
const dataStoreName = dataset.dataStore.name;
const dataStoreURL = dataset.dataStore.url;
return `${dataStoreName}, ${dataStoreURL}, ${datasetId.name}`;
} else return "";
}

function getUserAccessList() {
if (!activeUser || !dataset) return undefined;
if (!isUserAdminOrTeamManager(activeUser)) return undefined;

return (
<Collapse collapsible="header">
<Collapse.Panel header="All users with access rights to this dataset" key="1">
<DatasetAccessListView dataset={dataset} />
</Collapse.Panel>
</Collapse>
);
}

return form ? (
<div>
<FormItemWithInfo
Expand Down Expand Up @@ -179,6 +202,15 @@ export default function ImportSharingComponent({ form, datasetId, hasNoAllowedTe
</Input.Group>
</FormItemWithInfo>
)}

{getUserAccessList()}
</div>
) : null;
}

const mapStateToProps = (state: OxalisState) => ({
activeUser: state.activeUser,
});

const connector = connect(mapStateToProps);
export default connector(withRouter<RouteComponentProps & Props, any>(DatasetSettingsSharingTab));
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ import features from "features";
import { isDatasourceJSONValid } from "types/validation";
import { enforceValidatedDatasetViewConfiguration } from "types/schemas/dataset_view_configuration_defaults";
import { Hideable, hasFormError, jsonEditStyle } from "./helper_components";
import DefaultConfigComponent from "./default_config_component";
import ImportGeneralComponent from "./import_general_component";
import ImportSharingComponent from "./import_sharing_component";
import ImportDeleteComponent from "./import_delete_component";
import SimpleAdvancedDataForm from "./simple_advanced_data_form";
import DatasetSettingsViewConfigTab from "./dataset_settings_viewconfig_tab";
import DatasetSettingsMetadataTab from "./dataset_settings_metadata_tab";
import DatasetSettingsSharingTab from "./dataset_settings_sharing_tab";
import DatasetSettingsDeleteTab from "./dataset_settings_delete_tab";
import DatasetSettingsDataTab from "./dataset_settings_data_tab";

const { TabPane } = Tabs;
const FormItem = Form.Item;
Expand Down Expand Up @@ -153,7 +153,7 @@ function ensureValidScaleOnInferredDataSource(
return inferredDataSourceClone;
}

class DatasetImportView extends React.PureComponent<PropsWithFormAndRouter, State> {
class DatasetSettingsView extends React.PureComponent<PropsWithFormAndRouter, State> {
formRef = React.createRef<FormInstance>();
unblock: UnregisterCallback | null | undefined;
blockTimeoutId: number | null | undefined;
Expand Down Expand Up @@ -866,7 +866,7 @@ class DatasetImportView extends React.PureComponent<PropsWithFormAndRouter, Stat
// to hidden form elements.
}
<Hideable hidden={this.state.activeTabKey !== "data"}>
<SimpleAdvancedDataForm
<DatasetSettingsDataTab
key="SimpleAdvancedDataForm"
isReadOnlyDataset={
this.state.dataset != null &&
Expand Down Expand Up @@ -903,17 +903,18 @@ class DatasetImportView extends React.PureComponent<PropsWithFormAndRouter, Stat
forceRender
>
<Hideable hidden={this.state.activeTabKey !== "sharing"}>
<ImportSharingComponent
<DatasetSettingsSharingTab
form={form}
datasetId={this.props.datasetId}
dataset={this.state.dataset}
hasNoAllowedTeams={hasNoAllowedTeams}
/>
</Hideable>
</TabPane>

<TabPane tab={<span>Metadata</span>} key="general" forceRender>
<Hideable hidden={this.state.activeTabKey !== "general"}>
<ImportGeneralComponent />
<DatasetSettingsMetadataTab />
</Hideable>
</TabPane>

Expand All @@ -923,15 +924,15 @@ class DatasetImportView extends React.PureComponent<PropsWithFormAndRouter, Stat
forceRender
>
<Hideable hidden={this.state.activeTabKey !== "defaultConfig"}>
<DefaultConfigComponent />
<DatasetSettingsViewConfigTab />
</Hideable>
</TabPane>

{isUserAdmin && features().allowDeleteDatasets ? (
<TabPane tab={<span> Delete Dataset </span>} key="deleteDataset" forceRender>
<Hideable hidden={this.state.activeTabKey !== "deleteDataset"}>
<DatasetCacheProvider>
<ImportDeleteComponent datasetId={this.props.datasetId} />
<DatasetSettingsDeleteTab datasetId={this.props.datasetId} />
</DatasetCacheProvider>
</Hideable>
</TabPane>
Expand Down Expand Up @@ -961,4 +962,4 @@ const mapStateToProps = (state: OxalisState): StateProps => ({
});

const connector = connect(mapStateToProps);
export default connector(withRouter<RouteComponentProps & OwnProps, any>(DatasetImportView));
export default connector(withRouter<RouteComponentProps & OwnProps, any>(DatasetSettingsView));
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { getDefaultLayerViewConfiguration } from "types/schemas/dataset_view_con
import { layerViewConfigurations } from "messages";
import type { DatasetLayerConfiguration } from "oxalis/store";
import { FormItemWithInfo, jsonEditStyle } from "./helper_components";

const FormItem = Form.Item;
export default function DefaultConfigComponent() {

export default function DatasetSettingsViewConfigTab() {
const columns = [
{
title: "Name",
Expand Down
1 change: 0 additions & 1 deletion frontend/javascripts/dashboard/dataset_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ function DatasetView(props: Props) {
searchQuery={searchQuery}
searchTags={searchTags}
isUserAdmin={Utils.isUserAdmin(user)}
isUserTeamManager={Utils.isUserTeamManager(user)}
isUserDatasetManager={Utils.isUserDatasetManager(user)}
datasetFilteringMode={datasetFilteringMode}
updateDataset={context.updateCachedDataset}
Expand Down
6 changes: 3 additions & 3 deletions frontend/javascripts/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import AuthTokenView from "admin/auth/auth_token_view";
import ChangePasswordView from "admin/auth/change_password_view";
import DashboardView, { urlTokenToTabKeyMap } from "dashboard/dashboard_view";
import DatasetAddView from "admin/dataset/dataset_add_view";
import DatasetImportView from "dashboard/dataset/dataset_import_view";
import DatasetSettingsView from "dashboard/dataset/dataset_settings_view";
import DisableGenericDnd from "components/disable_generic_dnd";
import FinishResetPasswordView from "admin/auth/finish_reset_password_view";
import JobListView from "admin/job/job_list_view";
Expand Down Expand Up @@ -333,7 +333,7 @@ class ReactRouter extends React.Component<Props> {
isAuthenticated={isAuthenticated}
path="/datasets/:organizationName/:datasetName/import"
render={({ match }: ContextRouter) => (
<DatasetImportView
<DatasetSettingsView
isEditingMode={false}
datasetId={{
name: match.params.datasetName || "",
Expand All @@ -351,7 +351,7 @@ class ReactRouter extends React.Component<Props> {
isAuthenticated={isAuthenticated}
path="/datasets/:organizationName/:datasetName/edit"
render={({ match }: ContextRouter) => (
<DatasetImportView
<DatasetSettingsView
isEditingMode
datasetId={{
name: match.params.datasetName || "",
Expand Down