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

Show converting datasets #5597

Merged
merged 13 commits into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
- Added UI to infer nuclei for webknossos instances, which support jobs (e.g., webknossos.org). [#5669](https://github.com/scalableminds/webknossos/pull/5669)
- Added the possibility to restrict the volume resolutions when creating explorative annotations. Use this to annotate larger structures without creating tons of high-res data. [#5645](https://github.com/scalableminds/webknossos/pull/5645)
- Added tooltips for all elements of the Settings tab in the left sidebar. [#5673](https://github.com/scalableminds/webknossos/pull/5673)
- Most recent dataset conversions are shown in dashboard (if the webKnossos instance supports processing jobs). [#5597](https://github.com/scalableminds/webknossos/pull/5597)

### Changed
- Improved context menu for interactions with segmentation data which wasn't loaded completely, yet. [#5637](https://github.com/scalableminds/webknossos/pull/5637)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { connect } from "react-redux";
import React, { useState } from "react";
import _ from "lodash";

import { Unicode } from "oxalis/constants";
import type { APIDataStore, APIUser } from "types/api_flow_types";
import type { OxalisState } from "oxalis/store";
import { addWkConnectDataset } from "admin/admin_rest_api";
Expand Down Expand Up @@ -138,15 +139,15 @@ function DatasetAddNeuroglancerView({ datastores, onAdded, activeUser }: Props)
name="authFile"
label={
<React.Fragment>
Google&nbsp;
Google{Unicode.NonBreakingSpace}
<a
href="https://cloud.google.com/iam/docs/creating-managing-service-account-keys"
target="_blank"
rel="noopener noreferrer"
>
Service Account
</a>
&nbsp;Key (Optional)
{Unicode.NonBreakingSpace}Key (Optional)
</React.Fragment>
}
hasFeedback
Expand Down
58 changes: 30 additions & 28 deletions frontend/javascripts/admin/job/job_list_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ import * as Utils from "libs/utils";
import type { OxalisState } from "oxalis/store";
import FormattedDate from "components/formatted_date";

// Unfortunately, the twoToneColor (nor the style) prop don't support
// CSS variables.
export const TOOLTIP_MESSAGES_AND_ICONS = {
UNKNOWN: {
tooltip:
"The status information for this job could not be retreived. Please try again in a few minutes, or contact us if you need assistance.",
icon: <QuestionCircleTwoTone twoToneColor="#a3a3a3" />,
},
SUCCESS: {
tooltip: "This job has successfully been executed.",
icon: <CheckCircleTwoTone twoToneColor="#49b21b" />,
},
PENDING: {
tooltip: "This job will run as soon as a worker becomes available.",
icon: <ClockCircleTwoTone twoToneColor="#d89614" />,
},
STARTED: { tooltip: "This job is currently running.", icon: <LoadingOutlined /> },
FAILURE: {
tooltip:
"Something went wrong when executing this job. Feel free to contact us if you need assistance.",
icon: <CloseCircleTwoTone twoToneColor="#a61d24" />,
},
MANUAL: {
tooltip:
"The job will be handled by an admin shortly, since it could not be finished automatically. Please check back here soon.",
icon: <ToolTwoTone twoToneColor="#d89614" />,
},
};

const refreshInterval = 5000;

const { Column } = Table;
Expand Down Expand Up @@ -186,34 +215,7 @@ class JobListView extends React.PureComponent<Props, State> {
};

renderState = (__: any, job: APIJob) => {
const tooltipMessagesAndIcons = {
UNKNOWN: {
tooltip:
"The status information for this job could not be retreived. Please try again in a few minutes, or contact us if you need assistance.",
icon: <QuestionCircleTwoTone twoToneColor="grey" />,
},
SUCCESS: {
tooltip: "This job has successfully been executed.",
icon: <CheckCircleTwoTone twoToneColor="#49b21b" />,
},
PENDING: {
tooltip: "This job will run as soon as a worker becomes available.",
icon: <ClockCircleTwoTone twoToneColor="orange" />,
},
STARTED: { tooltip: "This job is currently running.", icon: <LoadingOutlined /> },
FAILURE: {
tooltip:
"Something went wrong when executing this job. Feel free to contact us if you need assistance.",
icon: <CloseCircleTwoTone twoToneColor="red" />,
},
MANUAL: {
tooltip:
"The job will be handled by an admin shortly, since it could not be finished automatically. Please check back here soon.",
icon: <ToolTwoTone twoToneColor="orange" />,
},
};

const { tooltip, icon } = tooltipMessagesAndIcons[job.state];
const { tooltip, icon } = TOOLTIP_MESSAGES_AND_ICONS[job.state];
const jobStateNormalized = _.capitalize(job.state.toLowerCase());
return (
<Tooltip title={tooltip}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from "@ant-design/icons";
import { Link, withRouter } from "react-router-dom";
import * as React from "react";
import { Unicode } from "oxalis/constants";

import type { APIMaybeUnimportedDataset, APIDatasetId } from "types/api_flow_types";
import { clearCache } from "admin/admin_rest_api";
Expand Down Expand Up @@ -182,7 +183,7 @@ class DatasetActionView extends React.PureComponent<Props, State> {
/>
) : (
<p style={disabledWhenReloadingStyle}>
New Annotation &nbsp;
New Annotation {Unicode.NonBreakingSpace}
<Tooltip title="Cannot create annotations for read-only datasets">
<InfoCircleOutlined style={{ color: "gray" }} />
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
APIDatasetId,
APIMessage,
} from "types/api_flow_types";
import { Unicode } from "oxalis/constants";
import type { DatasetConfiguration, OxalisState } from "oxalis/store";
import DatasetCacheProvider, { datasetCache } from "dashboard/dataset/dataset_cache_provider";
import LinkButton from "components/link_button";
Expand Down Expand Up @@ -794,7 +795,7 @@ class DatasetImportView extends React.PureComponent<Props, State> {
<Button type="primary" htmlType="submit">
{confirmString}
</Button>
&nbsp;
{Unicode.NonBreakingSpace}
<Button onClick={this.props.onCancel}>Cancel</Button>
</FormItem>
</Spin>
Expand Down
88 changes: 85 additions & 3 deletions frontend/javascripts/dashboard/dataset_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

import React, { useState, useContext, useEffect } from "react";
import { Link, useHistory } from "react-router-dom";
import { Badge, Button, Radio, Col, Dropdown, Input, Menu, Row, Spin } from "antd";
import { Badge, Button, Radio, Col, Dropdown, Input, Menu, Row, Spin, Tooltip, Alert } from "antd";
import {
CloudUploadOutlined,
LoadingOutlined,
PlusOutlined,
ReloadOutlined,
RocketOutlined,
SettingOutlined,
InfoCircleOutlined,
HourglassOutlined,
} from "@ant-design/icons";
import { PropTypes } from "@scalableminds/prop-types";
import useInterval from "@use-it/interval";

import type { APIUser } from "types/api_flow_types";
import type { APIJob, APIUser } from "types/api_flow_types";
import { OptionCard } from "admin/onboarding";
import DatasetTable from "dashboard/advanced_dataset/dataset_table";
import SampleDatasetsModal from "dashboard/dataset/sample_datasets_modal";
Expand All @@ -22,7 +25,11 @@ import * as Utils from "libs/utils";
import features, { getDemoDatasetUrl } from "features";
import renderIndependently from "libs/render_independently";
import Persistence from "libs/persistence";

import { getJobs } from "admin/admin_rest_api";
import moment from "moment";
import FormattedDate from "components/formatted_date";
import { TOOLTIP_MESSAGES_AND_ICONS } from "admin/job/job_list_view";
import { Unicode } from "oxalis/constants";
const { Search, Group: InputGroup } = Input;

type Props = {
Expand All @@ -36,6 +43,10 @@ type PersistenceState = {
datasetFilteringMode: DatasetFilteringMode,
};

const CONVERSION_JOBS_REFRESH_INTERVAL = 60 * 1000;
const MAX_JOBS_TO_DISPLAY = 5;
const RECENT_DATASET_DAY_THRESHOLD = 3;

const persistence: Persistence<PersistenceState> = new Persistence(
{
searchQuery: PropTypes.string,
Expand All @@ -62,6 +73,7 @@ function DatasetView(props: Props) {
const [datasetFilteringMode, setDatasetFilteringMode] = useState<DatasetFilteringMode>(
"onlyShowReported",
);
const [jobs, setJobs] = useState<Array<APIJob>>([]);

useEffect(() => {
const state = persistence.load(history);
Expand All @@ -71,6 +83,7 @@ function DatasetView(props: Props) {
if (state.datasetFilteringMode != null) {
setDatasetFilteringMode(state.datasetFilteringMode);
}
getJobs().then(newJobs => setJobs(newJobs));
context.fetchDatasets({
applyUpdatePredicate: _newDatasets => {
// Only update the datasets when there are none currently.
Expand All @@ -85,6 +98,10 @@ function DatasetView(props: Props) {
});
}, []);

useInterval(() => {
getJobs().then(newJobs => setJobs(newJobs));
}, CONVERSION_JOBS_REFRESH_INTERVAL);

useEffect(() => {
persistence.persist(history, {
searchQuery,
Expand Down Expand Up @@ -187,6 +204,69 @@ function DatasetView(props: Props) {
);
}

function renderNewJobsAlert() {
const now = moment();
const newJobs = jobs
.filter(
job =>
job.type === "convert_to_wkw" &&
moment.duration(now.diff(job.createdAt)).asDays() <= RECENT_DATASET_DAY_THRESHOLD,
)
.sort((a, b) => b.createdAt - a.createdAt);

if (newJobs.length === 0) {
return null;
}

const newJobsHeader = (
<React.Fragment>
Recent Dataset Conversions{" "}
<Tooltip
title="The conversion of the displayed datasets were started in the last 3 days."
placement="right"
>
<InfoCircleOutlined />
</Tooltip>
</React.Fragment>
);
const newJobsList = (
<div style={{ paddingTop: 8 }}>
{newJobs.slice(0, MAX_JOBS_TO_DISPLAY).map(job => {
const { tooltip, icon } = TOOLTIP_MESSAGES_AND_ICONS[job.state];
return (
<Row key={job.id} gutter={16}>
<Col span={10}>
<Tooltip title={tooltip}>{icon}</Tooltip>
{` ${job.datasetName || "UNKNOWN"}`}
{Unicode.NonBreakingSpace}(started at{Unicode.NonBreakingSpace}
<FormattedDate timestamp={job.createdAt} />
<span>)</span>
</Col>
</Row>
);
})}
<Row key="overview" style={{ marginTop: 12 }}>
<Col span={10}>
<Link to="/jobs" title="Jobs Overview">
See complete list
</Link>
</Col>
</Row>
</div>
);

return (
<Alert
message={newJobsHeader}
description={newJobsList}
type="info"
style={{ marginTop: 20 }}
showIcon
icon={<HourglassOutlined />}
/>
);
}

const margin = { marginRight: 5 };
const createFilteringModeRadio = (key, label) => (
<Radio
Expand Down Expand Up @@ -270,6 +350,8 @@ function DatasetView(props: Props) {
<div>
{adminHeader}
<div className="clearfix" style={{ margin: "20px 0px" }} />
{renderNewJobsAlert()}
<div className="clearfix" style={{ margin: "20px 0px" }} />

<Spin size="large" spinning={datasets.length === 0 && context.isLoading}>
{content}
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export const ensureSmallerEdge = false;

export const Unicode = {
ThinSpace: "\u202f",
NonBreakingSpace: "\u00a0",
MultiplicationSymbol: "×",
};

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"@rehooks/document-title": "^1.0.2",
"@scalableminds/prop-types": "^15.6.1",
"@tensorflow/tfjs": "^1.0.0",
"@use-it/interval": "^1.0.0",
"Enumjs": "https://github.com/ryan953/Enumjs#master",
"airbrake-js": "^1.4.0",
"antd": "^4.15.0",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,11 @@
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.4.tgz#c3b0f9d6b465c66138e84e64cb3bdf8373c2c279"
integrity sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==

"@use-it/interval@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@use-it/interval/-/interval-1.0.0.tgz#c42c68f22ca29a0dc929041746373d94496d2b3a"
integrity sha512-WQFcnSt/xM/mS8ZtJ0ut5lhPrl+V0HDPPcI/J0eUClsfiD+/r8A7IeW/pVcfpSVGWRmN3+WnjNteWuKyWs2WZg==

"@webassemblyjs/[email protected]":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
Expand Down