Skip to content

Commit

Permalink
Merge branch 'master' into remove-returns
Browse files Browse the repository at this point in the history
  • Loading branch information
frcroth authored Nov 20, 2024
2 parents f37fe2e + a8fe8b7 commit fa83ccd
Show file tree
Hide file tree
Showing 24 changed files with 80 additions and 157 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
[Commits](https://github.com/scalableminds/webknossos/compare/24.11.1...HEAD)

### Added
- When exploring remote URIs pasted from Neuroglancer, the format prefixes like `precomputed://` are now ignored, so users don’t have to remove them. [#8195](https://github.com/scalableminds/webknossos/pull/8195)

### Changed
- Reading image files on datastore filesystem is now done asynchronously. [#8126](https://github.com/scalableminds/webknossos/pull/8126)
- Improved error messages for starting jobs on datasets from other organizations. [#8181](https://github.com/scalableminds/webknossos/pull/8181)
- Removed bounding box size restriction for inferral jobs for super users. [#8200](https://github.com/scalableminds/webknossos/pull/8200)

### Fixed
- Fix performance bottleneck when deleting a lot of trees at once. [#8176](https://github.com/scalableminds/webknossos/pull/8176)
- Fix a bug when importing an NML with groups when only groups but no trees exist in an annotation. [#8176](https://github.com/scalableminds/webknossos/pull/8176)
- Fix a bug where trying to delete a non-existing node (via the API, for example) would delete the whole active tree. [#8176](https://github.com/scalableminds/webknossos/pull/8176)

### Removed
- Removed Google Analytics integration. [#8201](https://github.com/scalableminds/webknossos/pull/8201)

### Breaking Changes
2 changes: 2 additions & 0 deletions MIGRATIONS.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ User-facing changes are documented in the [changelog](CHANGELOG.released.md).
## Unreleased
[Commits](https://github.com/scalableminds/webknossos/compare/24.11.1...HEAD)

- The config option `googleAnalytics.trackingId` is no longer used and can be removed. [#8201](https://github.com/scalableminds/webknossos/pull/8201)

### Postgres Evolutions:
3 changes: 1 addition & 2 deletions app/controllers/AnnotationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,7 @@ class AnnotationController @Inject()(
annotationInfos <- annotationDAO.findAllListableExplorationals(
isFinished,
None,
isForOwnDashboard = true,
AnnotationType.Explorational,
filterOwnedOrShared = true,
limit.getOrElse(annotationService.DefaultAnnotationListLimit),
pageNumber.getOrElse(0)
)
Expand Down
28 changes: 23 additions & 5 deletions app/controllers/InitialDataController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.scalableminds.util.accesscontext.GlobalAccessContext
import com.scalableminds.util.time.Instant
import com.scalableminds.util.tools.{Fox, FoxImplicits}
import com.typesafe.scalalogging.LazyLogging
import models.aimodels.{AiModel, AiModelCategory, AiModelDAO}
import models.annotation.{TracingStore, TracingStoreDAO}
import models.dataset._
import models.folder.{Folder, FolderDAO, FolderService}
Expand Down Expand Up @@ -42,6 +43,7 @@ class InitialDataService @Inject()(userService: UserService,
taskTypeDAO: TaskTypeDAO,
dataStoreDAO: DataStoreDAO,
folderDAO: FolderDAO,
aiModelDAO: AiModelDAO,
folderService: FolderService,
tracingStoreDAO: TracingStoreDAO,
teamDAO: TeamDAO,
Expand Down Expand Up @@ -139,6 +141,19 @@ Samplecountry
Some(
"This is a wonderful dummy publication, it has authors, it has a link, it has a doi number, those could go here.\nLorem [ipsum](https://github.com/scalableminds/webknossos) dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.")
)
private val defaultDataStore =
DataStore(conf.Datastore.name, conf.Http.uri, conf.Datastore.publicUri.getOrElse(conf.Http.uri), conf.Datastore.key)
private val defaultAiModel = AiModel(
ObjectId("66544a56d20000af0e42ba0f"),
defaultOrganization._id,
defaultDataStore.name,
defaultUser._id,
None,
List.empty,
"sample_ai_model",
Some("Works if model files are manually placed at binaryData/sample_organization/66544a56d20000af0e42ba0f/"),
Some(AiModelCategory.em_neurons)
)

def insert: Fox[Unit] =
for {
Expand All @@ -158,6 +173,7 @@ Samplecountry
_ <- insertTaskType()
_ <- insertProject()
_ <- insertPublication()
_ <- insertAiModel()
} yield ()

private def assertInitialDataEnabled: Fox[Unit] =
Expand Down Expand Up @@ -266,16 +282,18 @@ Samplecountry
} else Fox.successful(())
}

private def insertAiModel(): Fox[Unit] = aiModelDAO.findAll.flatMap { aiModels =>
if (aiModels.isEmpty) {
aiModelDAO.insertOne(defaultAiModel)
} else Fox.successful(())
}

def insertLocalDataStoreIfEnabled(): Fox[Unit] =
if (storeModules.localDataStoreEnabled) {
dataStoreDAO.findOneByUrl(conf.Http.uri).futureBox.flatMap { maybeStore =>
if (maybeStore.isEmpty) {
logger.info("Inserting local datastore")
dataStoreDAO.insertOne(
DataStore(conf.Datastore.name,
conf.Http.uri,
conf.Datastore.publicUri.getOrElse(conf.Http.uri),
conf.Datastore.key))
dataStoreDAO.insertOne(defaultDataStore)
} else Fox.successful(())
}
} else Fox.successful(())
Expand Down
6 changes: 2 additions & 4 deletions app/controllers/UserController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ class UserController @Inject()(userService: UserService,
annotations <- annotationDAO.findAllListableExplorationals(
isFinished,
Some(request.identity._id),
isForOwnDashboard = true,
AnnotationType.Explorational,
filterOwnedOrShared = true,
limit.getOrElse(annotationService.DefaultAnnotationListLimit),
pageNumber.getOrElse(0)
)
Expand Down Expand Up @@ -118,8 +117,7 @@ class UserController @Inject()(userService: UserService,
annotations <- annotationDAO.findAllListableExplorationals(
isFinished,
Some(userIdValidated),
isForOwnDashboard = false,
AnnotationType.Explorational,
filterOwnedOrShared = false,
limit.getOrElse(annotationService.DefaultAnnotationListLimit),
pageNumber.getOrElse(0)
)
Expand Down
24 changes: 19 additions & 5 deletions app/models/annotation/Annotation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -359,20 +359,34 @@ class AnnotationDAO @Inject()(sqlClient: SqlClient, annotationLayerDAO: Annotati
// format: on
}

/**
* Find all annotations which are listable by the user specified in 'forUser'
*
* @param isFinished
* If set to `true`, only finished annotations are returned. If set to `false`, only active annotations are returned.
* If set to `None`, all non-cancelled annotations are returned.
* @param forUser
* If set, only annotations of this user are returned. If not set, all annotations are returned.
* @param filterOwnedOrShared
* If `true`, the function lists only annotations owned by the user or explicitly shared with them (used for the
* user's own dashboard). If `false`, it lists all annotations the viewer is allowed to see.
* @param limit
* The maximum number of annotations to return.
* @param pageNumber
* The page number to return. The first page is 0.
*/
def findAllListableExplorationals(
isFinished: Option[Boolean],
forUser: Option[ObjectId],
// In dashboard, list only own + explicitly shared annotations. When listing those of another user, list all of their annotations the viewer is allowed to see
isForOwnDashboard: Boolean,
typ: AnnotationType,
filterOwnedOrShared: Boolean,
limit: Int,
pageNumber: Int = 0)(implicit ctx: DBAccessContext): Fox[List[AnnotationCompactInfo]] =
for {
accessQuery <- if (isForOwnDashboard) accessQueryFromAccessQWithPrefix(listAccessQ, q"a.")
accessQuery <- if (filterOwnedOrShared) accessQueryFromAccessQWithPrefix(listAccessQ, q"a.")
else accessQueryFromAccessQWithPrefix(readAccessQWithPrefix, q"a.")
stateQuery = getStateQuery(isFinished)
userQuery = forUser.map(u => q"a._user = $u").getOrElse(q"TRUE")
typQuery = q"a.typ = $typ"
typQuery = q"a.typ = ${AnnotationType.Explorational}"

query = q"""WITH
-- teams_agg is extracted to avoid left-join fanout.
Expand Down
5 changes: 0 additions & 5 deletions app/utils/WkConf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,6 @@ class WkConf @Inject()(configuration: Configuration) extends ConfigReader with L
val environment: String = get[String]("airbrake.environment")
}

object GoogleAnalytics {
val trackingId: String = get[String]("googleAnalytics.trackingId")
}

object SlackNotifications {
val uri: String = get[String]("slackNotifications.uri")
val verboseLoggingEnabled: Boolean = get[Boolean]("slackNotifications.verboseLoggingEnabled")
Expand Down Expand Up @@ -259,7 +255,6 @@ class WkConf @Inject()(configuration: Configuration) extends ConfigReader with L
Silhouette,
Jobs,
Airbrake,
GoogleAnalytics,
BackendAnalytics,
Slick,
Voxelytics,
Expand Down
23 changes: 0 additions & 23 deletions app/views/main.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta name="commit-hash" content="@(webknossos.BuildInfo.commitHash)" />
<meta name="selected-theme" content="@(selectedTheme)" />
@if(conf.GoogleAnalytics.trackingId.nonEmpty) {
<meta name="google-analytics-tracking-id" content="@(conf.GoogleAnalytics.trackingId)" />
}
<title>@(conf.WebKnossos.tabTitle)</title>
@openGraphTitle.map { ogt =>
<meta property="og:title" content="@ogt" />
Expand Down Expand Up @@ -52,25 +49,5 @@
</head>
<body>
<main id="main-container"></main>

@if(conf.GoogleAnalytics.trackingId.nonEmpty) {
<script
async
src="https://www.googletagmanager.com/gtag/js?id=@(conf.GoogleAnalytics.trackingId)"
></script>
<script>
const metaElement = document.querySelector("meta[name='google-analytics-tracking-id']");
const googleAnalyticsTrackingId = metaElement ? metaElement.getAttribute("content") : null;
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", googleAnalyticsTrackingId, {
anonymize_ip: true,
cookie_expires: 0,
});
</script>
}
</body>
</html>
3 changes: 0 additions & 3 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,6 @@ airbrake {
projectID = "insert-valid-projectID-here"
}

# Front-end analytics
googleAnalytics.trackingId = ""

# Slack notification
slackNotifications {
uri = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,15 @@ function AddRemoteLayer({
};

function validateUrls(userInput: string) {
const removePrefix = (value: string, prefix: string) =>
value.startsWith(prefix) ? value.slice(prefix.length) : value;

// If pasted from neuroglancer, uris have these prefixes even before the protocol. The backend ignores them.
userInput = removePrefix(userInput, "zarr://");
userInput = removePrefix(userInput, "zarr3://");
userInput = removePrefix(userInput, "n5://");
userInput = removePrefix(userInput, "precomputed://");

if (userInput.startsWith("https://") || userInput.startsWith("http://")) {
setSelectedProtocol("https");
} else if (userInput.startsWith("s3://")) {
Expand Down
2 changes: 0 additions & 2 deletions frontend/javascripts/admin/dataset/dataset_upload_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import {
import Toast from "libs/toast";
import * as Utils from "libs/utils";
import messages from "messages";
import { trackAction } from "oxalis/model/helpers/analytics";
import Zip from "libs/zipjs_wrapper";
import {
AllowedTeamsFormItem,
Expand Down Expand Up @@ -350,7 +349,6 @@ class DatasetUploadView extends React.Component<PropsWithFormAndRouter, State> {
});
finishDatasetUpload(datastoreUrl, uploadInfo).then(
async () => {
trackAction("Upload dataset");
Toast.success(messages["dataset.upload_success"]);
let maybeError;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {
} from "types/api_flow_types";
import type { DatasetFilteringMode } from "dashboard/dataset_view";
import { stringToColor } from "libs/format_utils";
import { trackAction } from "oxalis/model/helpers/analytics";
import CategorizationLabel from "oxalis/view/components/categorization_label";
import DatasetActionView, {
getDatasetActionContextMenu,
Expand Down Expand Up @@ -791,7 +790,6 @@ export function DatasetTags({
};
}

trackAction("Edit dataset tag");
updateDataset(dataset, updater);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
updateDatasetPartial,
} from "admin/admin_rest_api";
import { handleGenericError } from "libs/error_handling";
import { trackAction } from "oxalis/model/helpers/analytics";
import Toast from "libs/toast";
import messages from "messages";
import features from "features";
Expand Down Expand Up @@ -390,7 +389,6 @@ class DatasetSettingsView extends React.PureComponent<PropsWithFormAndRouter, St
}
}

trackAction(`Dataset ${verb}`);
this.props.onComplete();
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import Store from "oxalis/store";
import Toast from "libs/toast";
import * as Utils from "libs/utils";
import messages from "messages";
import { trackAction } from "oxalis/model/helpers/analytics";
import TextWithDescription from "components/text_with_description";
import { getVolumeDescriptors } from "oxalis/model/accessors/volumetracing_accessor";
import { RenderToPortal } from "oxalis/view/layouting/portal_utils";
Expand Down Expand Up @@ -289,7 +288,6 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
const newTracing = await editLockedState(tracing.id, tracing.typ, locked);
Toast.success(messages["annotation.was_edited"]);
this.updateTracingInLocalState(tracing, (_t) => newTracing);
trackAction("Lock/Unlock explorative annotation");
} catch (error) {
handleGenericError(error as Error, "Could not update the annotation lock state.");
}
Expand Down Expand Up @@ -475,7 +473,6 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
editAnnotation(newAnnotation.id, newAnnotation.typ, {
tags: newAnnotation.tags,
});
trackAction("Edit annotation tag");
}

return newAnnotation;
Expand Down Expand Up @@ -699,7 +696,7 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
</div>
<div className="flex-container">
<div className="flex-item" style={{ flexGrow: 0 }}>
{teamTags.length > 0 ? <TeamOutlined /> : null}
{teamTags.length > 0 ? <TeamOutlined className="icon-margin-right" /> : null}
</div>
<div className="flex-item">{teamTags}</div>
</div>
Expand Down
2 changes: 0 additions & 2 deletions frontend/javascripts/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import UnthrottledStore, { startSagas } from "oxalis/store";
import { message } from "antd";

import { getActiveUser, checkAnyOrganizationExists, getOrganization } from "admin/admin_rest_api";
import { googleAnalyticsLogClicks } from "oxalis/model/helpers/analytics";
import { load as loadFeatureToggles } from "features";
import { setActiveUserAction } from "oxalis/model/actions/user_actions";
import { setHasOrganizationsAction, setThemeAction } from "oxalis/model/actions/ui_actions";
Expand Down Expand Up @@ -97,7 +96,6 @@ document.addEventListener("DOMContentLoaded", async () => {
throwAssertions: false,
});
message.config({ top: 30 });
document.addEventListener("click", googleAnalyticsLogClicks);
checkBrowserFeatures();
await Promise.all([loadFeatureToggles(), loadActiveUser(), loadHasOrganizations()]);
await Promise.all([loadOrganization()]);
Expand Down
13 changes: 4 additions & 9 deletions frontend/javascripts/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import {
sendAnalyticsEvent,
} from "admin/admin_rest_api";
import { logoutUserAction, setActiveUserAction } from "oxalis/model/actions/user_actions";
import { trackVersion } from "oxalis/model/helpers/analytics";
import { useFetch, useInterval } from "libs/react_helpers";
import LoginForm from "admin/auth/login_form";
import Request from "libs/request";
Expand Down Expand Up @@ -739,13 +738,9 @@ function AnonymousAvatar() {
);
}

async function getAndTrackVersion(dontTrack: boolean = false) {
async function getVersion() {
const buildInfo = await getBuildInfo();
const { version } = buildInfo.webknossos;
if (dontTrack) {
trackVersion(version);
}
return version;
return buildInfo.webknossos.version;
}

function AnnotationLockedByUserTag({
Expand Down Expand Up @@ -831,15 +826,15 @@ function Navbar({
location.href = "/";
};

const version = useFetch(getAndTrackVersion, null, []);
const version = useFetch(getVersion, null, []);
const [isHelpMenuOpen, setIsHelpMenuOpen] = useState(false);
const [polledVersion, setPolledVersion] = useState<string | null>(null);
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false);

useInterval(
async () => {
if (isHelpMenuOpen) {
setPolledVersion(await getAndTrackVersion(true));
setPolledVersion(await getVersion());
}
},
2000,
Expand Down
Loading

0 comments on commit fa83ccd

Please sign in to comment.