Skip to content

Commit

Permalink
Merge branch 'clean-up-merge-modal' of github.com:scalableminds/webkn…
Browse files Browse the repository at this point in the history
…ossos into chunk-save-actions
  • Loading branch information
philippotto committed Jul 30, 2018
2 parents 6d5a5cf + 4bfebc8 commit 9b99158
Show file tree
Hide file tree
Showing 56 changed files with 4,802 additions and 1,394 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react/jsx-filename-extension": "off",
"react/no-multi-comp": "warn",
"react/prop-types": "off",
"react/require-default-props": "off",
"radix": "off",
"no-bitwise": "off",
"no-confusing-arrow": "off",
Expand Down
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PROJECT_ROOT>/node_modules/findup/
<PROJECT_ROOT>/node_modules/documentation/
<PROJECT_ROOT>/node_modules/flow-coverage-report/
<PROJECT_ROOT>/.nyc_output

[untyped]
<PROJECT_ROOT>/node_modules/ava/
Expand Down
134 changes: 83 additions & 51 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ RUN addgroup --system --gid 999 webknossos \

USER webknossos

ENTRYPOINT [ "bin/oxalis" ]
ENTRYPOINT [ "bin/webknossos" ]
8 changes: 7 additions & 1 deletion MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ All migrations of webknossos are documented in this file.
This project adheres to [Calendar Versioning](http://calver.org/) `0Y.0M.MICRO`.
User-facing changes are documented in the [changelog](CHANGELOG.md).

## [Unreleased]
## Unreleased
### Postgres Evolutions:
-

## [18.08.0](https://github.com/scalableminds/webknossos/releases/tag/18.08.0) - 2018-07-23
### Postgres Evolutions:
- [013-add-logoUrl.sql](conf/evolutions/013-add-logoUrl.sql)
- [014-equalize-schema-and-evolutions.sql](conf/evolutions/014-equalize-schema-and-evolutions.sql)
- [015-add-organization-displayname.sql](conf/evolutions/015-add-organization-displayname.sql)
- To clean up half-deleted tasks as caused by [this bug](https://github.com/scalableminds/webknossos/issues/2873), run `update webknossos.annotations set isDeleted = true where _id in (select a._id from webknossos.annotations_ a join webknossos.tasks t on a._task = t._id where t.isDeleted and a.typ == 'Task')`
- [016-add-schema-version.sql](conf/evolutions/016-add-schema-version.sql)
- [017-add-organization-email.sql](conf/evolutions/017-add-organization-email.sql)
- Add email addresses for notifications about new users and about task overtime to the `webknossos.organizations` entries in the Postgres database (previously in `application.conf` > `braintracing.newuserlist` and `braintracing.overTimeList`)

## [18.07.0](https://github.com/scalableminds/webknossos/releases/tag/18.07.0) - 2018-07-05
First release
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import * as React from "react";
import { Icon, Spin, Table, Card } from "antd";
import Utils from "libs/utils";
import FormatUtils from "libs/format_utils";
import Loop from "components/loop";
import { getProjectProgressReport } from "admin/admin_rest_api";
import type { APIProjectProgressReportType, APITeamType } from "admin/api_flow_types";
import FormattedDate from "components/formatted_date";
import TeamSelectionForm from "./team_selection_form";

const { Column, ColumnGroup } = Table;
Expand Down Expand Up @@ -69,7 +69,7 @@ class ProjectProgressReportView extends React.PureComponent<{}, State> {
<div className="container">
<Loop onTick={this.handleAutoReload} interval={RELOAD_INTERVAL} />
<div className="pull-right">
{this.state.updatedAt != null ? FormatUtils.formatDate(this.state.updatedAt) : null}{" "}
{this.state.updatedAt != null ? <FormattedDate timestamp={this.state.updatedAt} /> : null}{" "}
<Icon type="setting" onClick={this.handleOpenSettings} />
<Icon type="reload" onClick={this.handleReload} />
</div>
Expand Down
6 changes: 4 additions & 2 deletions app/assets/javascripts/admin/task/task_annotation_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { Dropdown, Menu, Icon, Modal } from "antd";
import React from "react";
import { connect } from "react-redux";
import moment from "moment";
import FormatUtils from "libs/format_utils";
import {
getAnnotationsForTask,
Expand All @@ -16,6 +15,7 @@ import messages from "messages";
import TransferTaskModal from "dashboard/transfer_task_modal";
import type { APIUserType, APITaskType, APIAnnotationType } from "admin/api_flow_types";
import type { OxalisState } from "oxalis/store";
import FormattedDate from "components/formatted_date";

const { Item } = Menu;
const { confirm } = Modal;
Expand Down Expand Up @@ -163,7 +163,9 @@ class TaskAnnotationView extends React.PureComponent<Props & StateProps, State>
return (
<tr key={`${annotation.id}-tr`}>
<td>{userString}</td>
<td>{moment(annotation.modified).format("YYYY-MM-DD HH:mm")}</td>
<td>
<FormattedDate timestamp={annotation.modified} />
</td>
<td>
<span>
<Icon type="check-circle-o" />
Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascripts/admin/task/task_list_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { APITaskType, APITaskTypeType } from "admin/api_flow_types";
import type { QueryObjectType, TaskFormFieldValuesType } from "admin/task/task_search_form";
import type { RouterHistory } from "react-router-dom";
import { handleGenericError } from "libs/error_handling";
import FormattedDate from "components/formatted_date";

const { Column } = Table;
const { Search, TextArea } = Input;
Expand Down Expand Up @@ -244,6 +245,7 @@ class TaskListView extends React.PureComponent<Props, State> {
key="created"
width={150}
sorter={Utils.localeCompareBy(typeHint, "created")}
render={created => <FormattedDate timestamp={created} />}
/>
<Column
title="Stats"
Expand Down
14 changes: 10 additions & 4 deletions app/assets/javascripts/components/file_upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ type Props = {
onUploading?: Function,
};

export function readFileAsText(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => resolve(reader.result.toString());
reader.readAsText(file);
});
}

class FileUpload extends React.PureComponent<Props> {
fileInput: ?HTMLInputElement;

Expand All @@ -32,10 +41,7 @@ class FileUpload extends React.PureComponent<Props> {
data: { [this.props.name]: files },
}).then(successCallback, errorCallback);
} else {
const reader = new FileReader();
reader.onerror = errorCallback;
reader.onload = () => successCallback(reader.result);
reader.readAsText(files[0]);
readFileAsText(files[0]).then(successCallback, errorCallback);
}
};

Expand Down
38 changes: 38 additions & 0 deletions app/assets/javascripts/components/formatted_date.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @flow
import * as React from "react";
import moment from "moment";
import { Tooltip } from "antd";

const defaultTimeFormat = "YYYY-MM-DD HH:mm";

/**
* Return current date and time. Please only use this function if you need
* a pure string representation. In all other cases, please prefer the
* <FormattedDate /> component below.
*/
export function formatDateInLocalTimeZone(date?: number = Date.now()): string {
return moment(date).format(defaultTimeFormat);
}

export default function FormattedDate({
timestamp,
format,
}: {
timestamp: string | number,
format?: string,
}) {
const _moment = moment.utc(timestamp);
const _format = format || defaultTimeFormat;
return (
<Tooltip
title={
<span>
The displayed time refers to your local timezone. In UTC, the time is:{" "}
{_moment.format(_format)}
</span>
}
>
{_moment.local().format(_format)}
</Tooltip>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { DatasetType } from "dashboard/dataset_view";
import type { APITeamType } from "admin/api_flow_types";
import dice from "dice-coefficient";
import _ from "lodash";
import FormattedDate from "components/formatted_date";

const { Column } = Table;

Expand Down Expand Up @@ -120,9 +121,9 @@ class AdvancedDatasetView extends React.PureComponent<Props, State> {
title="Creation Date"
dataIndex="created"
key="created"
sorter={Utils.localeCompareBy(typeHint, "formattedCreated")}
sorter={Utils.compareBy(typeHint, "created")}
sortOrder={sortedInfo.columnKey === "created" && sortedInfo.order}
render={(__, dataset: DatasetType) => dataset.formattedCreated}
render={created => <FormattedDate timestamp={created} />}
/>
<Column
title="Scale"
Expand Down
8 changes: 4 additions & 4 deletions app/assets/javascripts/dashboard/dashboard_task_list_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { AsyncButton } from "components/async_clickables";
import { Button, Modal, Tag, Icon, Card, Row, Col, List } from "antd";
import Markdown from "react-remarkable";
import Utils from "libs/utils";
import moment from "moment";
import Toast from "libs/toast";
import messages from "messages";
import TransferTaskModal from "dashboard/transfer_task_modal";
Expand All @@ -32,6 +31,7 @@ import type {
} from "admin/api_flow_types";
import type { OxalisState } from "oxalis/store";
import type { RouterHistory } from "react-router-dom";
import FormattedDate from "components/formatted_date";

const typeHint: APITaskWithAnnotationType[] = [];

Expand Down Expand Up @@ -322,9 +322,9 @@ class DashboardTaskListView extends React.PureComponent<Props, State> {

const TaskCardTitle = ({ task }) => (
<React.Fragment>
<span style={{ marginRight: 8 }}>{`${task.type.summary} (${moment(task.created).format(
"YYYY-MM-DD HH:mm",
)}) `}</span>
<span style={{ marginRight: 8 }}>
{task.type.summary} (<FormattedDate timestamp={task.created} />)
</span>
{task.type.settings.allowedModes.map(mode => <Tag key={mode}>{mode}</Tag>)}
</React.Fragment>
);
Expand Down
3 changes: 0 additions & 3 deletions app/assets/javascripts/dashboard/dataset_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import _ from "lodash";
import * as React from "react";
import { Link, withRouter } from "react-router-dom";
import Utils from "libs/utils";
import moment from "moment";
import { Spin, Input, Button } from "antd";
import AdvancedDatasetView from "dashboard/advanced_dataset/advanced_dataset_view";
import GalleryDatasetView from "dashboard/gallery_dataset_view";
Expand All @@ -26,7 +25,6 @@ type Props = {
export type DatasetType = APIDatasetType & {
hasSegmentation: boolean,
thumbnailURL: string,
formattedCreated: string,
};

type State = {
Expand Down Expand Up @@ -57,7 +55,6 @@ export function transformDatasets(datasets: Array<APIDatasetType>): Array<Datase
layer => layer.category === "segmentation",
),
thumbnailURL: createThumbnailURL(dataset.name, dataset.dataSource.dataLayers),
formattedCreated: moment(dataset.created).format("YYYY-MM-DD HH:mm"),
}),
),
"created",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
} from "admin/admin_rest_api";
import type { RouterHistory } from "react-router-dom";
import { handleGenericError } from "libs/error_handling";
import FormattedDate from "components/formatted_date";

const { Column } = Table;
const { Search } = Input;
Expand Down Expand Up @@ -417,6 +418,7 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
title="Modification Date"
dataIndex="modified"
sorter={Utils.localeCompareBy(typeHint, "modified")}
render={modified => <FormattedDate timestamp={modified} />}
/>
<Column
title="Actions"
Expand Down
7 changes: 2 additions & 5 deletions app/assets/javascripts/dashboard/gallery_dataset_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,14 @@ class GalleryDatasetView extends React.PureComponent<Props, State> {
.entries()
.map(([organization, datasets]) =>
// Sort each group of datasets
[
organization,
datasets.sort(Utils.localeCompareBy(([]: DatasetType[]), "formattedCreated", false)),
],
[organization, datasets.sort(Utils.localeCompareBy(([]: DatasetType[]), "created", false))],
)
.value()
.sort(
// Sort groups by creation date of first dataset
Utils.localeCompareBy(
([]: DatasetType[]),
([_organization, datasets]) => datasets[0].formattedCreated,
([_organization, datasets]) => datasets[0].created,
false,
),
);
Expand Down
7 changes: 0 additions & 7 deletions app/assets/javascripts/libs/format_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ class FormatUtils {
}
return text;
}

/**
* Return current date and time
*/
static formatDate(date?: number = Date.now()): string {
return moment(date).format("YYYY-MM-DD HH:mm");
}
}

export default FormatUtils;
22 changes: 22 additions & 0 deletions app/assets/javascripts/libs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,28 @@ const Utils = {
// Big endian
return [a, b, g, r];
},

async promiseAllWithErrors<T>(
promises: Array<Promise<T>>,
): Promise<{ successes: Array<T>, errors: Array<Error> }> {
const successOrErrorObjects = await Promise.all(promises.map(p => p.catch(error => error)));
return successOrErrorObjects.reduce(
({ successes, errors }, successOrError) => {
if (successOrError instanceof Error) {
return {
successes,
errors: errors.concat([successOrError]),
};
} else {
return {
successes: successes.concat([successOrError]),
errors,
};
}
},
{ successes: [], errors: [] },
);
},
};

export default Utils;
5 changes: 5 additions & 0 deletions app/assets/javascripts/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ In order to restore the current window, a reload is necessary.`,
"tracing.delete_tree_with_initial_node":
"This tree contains the initial node. Do you really want to delete the whole tree?",
"tracing.merged": "Merging successfully done",
"tracing.merged_with_redirect":
"Merging successfully done. You will be redirected to the new annotation.",
"tracing.tree_viewer_no_cyclic_trees":
"Cyclic trees are not supported by the abstract tree viewer.",
"tracing.changed_move_value": "The move value was changed to: ",
Expand Down Expand Up @@ -148,6 +150,9 @@ In order to restore the current window, a reload is necessary.`,
"NML contains <edge ...> with same source and target id: Edge",
"nml.tree_not_connected": "NML contains tree that is not fully connected: Tree with id",
"nml.different_dataset": "Imported NML was originally for a different dataset.",
"merge.different_dataset":
"The merge cannot be executed, because the underlying datasets are not the same.",
"merge.volume_unsupported": "Merging is not supported for volume tracings.",
"users.is_admin":
"At least one of the selected users is an admin of this organization and already has access to all teams. No team assignments are necessary for this user.",
"users.grant_admin_rights_title": "Do you really want to grant admin rights?",
Expand Down
6 changes: 6 additions & 0 deletions app/assets/javascripts/oxalis/api/api_latest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
setActiveNodeAction,
createCommentAction,
deleteNodeAction,
deleteTreeAction,
setNodeRadiusAction,
setTreeNameAction,
} from "oxalis/model/actions/skeletontracing_actions";
Expand Down Expand Up @@ -161,6 +162,11 @@ class TracingApi {
Store.dispatch(deleteNodeAction(nodeId, treeId));
}

deleteTree(treeId: number) {
assertSkeleton(Store.getState().tracing);
Store.dispatch(deleteTreeAction(treeId));
}

/**
* Sets the comment for a node.
*
Expand Down
4 changes: 3 additions & 1 deletion app/assets/javascripts/oxalis/model/actions/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { ViewModeActionType } from "oxalis/model/actions/view_mode_actions"
import type { AnnotationActionTypes } from "oxalis/model/actions/annotation_actions";
import type { FlycamActionType } from "oxalis/model/actions/flycam_actions";
import type { UserActionType } from "oxalis/model/actions/user_actions";
import type { UiActionType } from "oxalis/model/actions/ui_actions";

export type ActionType =
| SkeletonTracingActionType
Expand All @@ -20,7 +21,8 @@ export type ActionType =
| ViewModeActionType
| AnnotationActionTypes
| FlycamActionType
| UserActionType;
| UserActionType
| UiActionType;

export const wkReadyAction = () => ({
type: "WK_READY",
Expand Down
16 changes: 16 additions & 0 deletions app/assets/javascripts/oxalis/model/actions/ui_actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @flow
/* eslint-disable import/prefer-default-export */

type SetDropzoneModalVisibilityActionType = {
type: "SET_DROPZONE_MODAL_VISIBILITY_ACTION_TYPE",
visible: boolean,
};

export type UiActionType = SetDropzoneModalVisibilityActionType;

export const setDropzoneModalVisibilityAction = (
visible: boolean,
): SetDropzoneModalVisibilityActionType => ({
type: "SET_DROPZONE_MODAL_VISIBILITY_ACTION_TYPE",
visible,
});
Loading

0 comments on commit 9b99158

Please sign in to comment.