From 7a10a64897854ab6b21700bde9225bf2ddae499b Mon Sep 17 00:00:00 2001 From: Florian M Date: Tue, 19 Nov 2024 08:08:42 +0100 Subject: [PATCH 1/4] Exploring remote datasets: drop neuroglancer prefixes from URIs (#8195) * Exploring remote datasets: drop neuroglancer prefixes from URIs * changelog --- CHANGELOG.unreleased.md | 1 + .../admin/dataset/dataset_add_remote_view.tsx | 9 +++++++++ .../explorative_annotations_view.tsx | 2 +- .../datastore/explore/ExploreLayerUtils.scala | 19 ++++++++++--------- .../explore/ExploreRemoteLayerService.scala | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 3784c9075c7..70be3ed09df 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -11,6 +11,7 @@ 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) diff --git a/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx b/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx index eb12f66bc18..3afe7e82e5d 100644 --- a/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx +++ b/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx @@ -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://")) { diff --git a/frontend/javascripts/dashboard/explorative_annotations_view.tsx b/frontend/javascripts/dashboard/explorative_annotations_view.tsx index a57790d896b..cce9042286a 100644 --- a/frontend/javascripts/dashboard/explorative_annotations_view.tsx +++ b/frontend/javascripts/dashboard/explorative_annotations_view.tsx @@ -699,7 +699,7 @@ class ExplorativeAnnotationsView extends React.PureComponent {
- {teamTags.length > 0 ? : null} + {teamTags.length > 0 ? : null}
{teamTags}
diff --git a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreLayerUtils.scala b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreLayerUtils.scala index 5af8788385d..907e45e2f67 100644 --- a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreLayerUtils.scala +++ b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreLayerUtils.scala @@ -137,14 +137,15 @@ trait ExploreLayerUtils extends FoxImplicits { } def removeHeaderFileNamesFromUriSuffix(uri: String): String = - if (uri.endsWith(N5Header.FILENAME_ATTRIBUTES_JSON)) uri.dropRight(N5Header.FILENAME_ATTRIBUTES_JSON.length) - else if (uri.endsWith(ZarrHeader.FILENAME_DOT_ZARRAY)) uri.dropRight(ZarrHeader.FILENAME_DOT_ZARRAY.length) - else if (uri.endsWith(NgffMetadata.FILENAME_DOT_ZATTRS)) uri.dropRight(NgffMetadata.FILENAME_DOT_ZATTRS.length) - else if (uri.endsWith(NgffGroupHeader.FILENAME_DOT_ZGROUP)) - uri.dropRight(NgffGroupHeader.FILENAME_DOT_ZGROUP.length) - else if (uri.endsWith(PrecomputedHeader.FILENAME_INFO)) uri.dropRight(PrecomputedHeader.FILENAME_INFO.length) - else if (uri.endsWith(Zarr3ArrayHeader.FILENAME_ZARR_JSON)) - uri.dropRight(Zarr3ArrayHeader.FILENAME_ZARR_JSON.length) - else uri + uri + .stripSuffix(N5Header.FILENAME_ATTRIBUTES_JSON) + .stripSuffix(ZarrHeader.FILENAME_DOT_ZARRAY) + .stripSuffix(NgffMetadata.FILENAME_DOT_ZATTRS) + .stripSuffix(NgffGroupHeader.FILENAME_DOT_ZGROUP) + .stripSuffix(PrecomputedHeader.FILENAME_INFO) + .stripSuffix(Zarr3ArrayHeader.FILENAME_ZARR_JSON) + + def removeNeuroglancerPrefixesFromUri(uri: String): String = + uri.stripPrefix("zarr3://").stripPrefix("zarr://").stripPrefix("precomputed://").stripPrefix("n5://") } diff --git a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreRemoteLayerService.scala b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreRemoteLayerService.scala index 1cc8ce8a0e2..84cd905863f 100644 --- a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreRemoteLayerService.scala +++ b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/explore/ExploreRemoteLayerService.scala @@ -77,7 +77,7 @@ class ExploreRemoteLayerService @Inject()(dataVaultService: DataVaultService, reportMutable: ListBuffer[String])( implicit ec: ExecutionContext): Fox[List[(DataLayerWithMagLocators, VoxelSize)]] = for { - uri <- tryo(new URI(removeHeaderFileNamesFromUriSuffix(layerUri))) ?~> s"Received invalid URI: $layerUri" + uri <- tryo(new URI(removeNeuroglancerPrefixesFromUri(removeHeaderFileNamesFromUriSuffix(layerUri)))) ?~> s"Received invalid URI: $layerUri" _ <- bool2Fox(uri.getScheme != null) ?~> s"Received invalid URI: $layerUri" _ <- assertLocalPathInWhitelist(uri) credentialOpt: Option[DataVaultCredential] <- Fox.runOptional(credentialId)(remoteWebknossosClient.getCredential) From 3e04578f257f479f42c3a7931cfc912c878f723b Mon Sep 17 00:00:00 2001 From: MichaelBuessemeyer <39529669+MichaelBuessemeyer@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:47:33 +0100 Subject: [PATCH 2/4] Do not restrict bbox size for inferral jobs for super users (#8200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * do not restrict bbox size for inferal jobs for super user * add changelog entry --------- Co-authored-by: Michael Büßemeyer Co-authored-by: Florian M --- CHANGELOG.unreleased.md | 1 + .../oxalis/view/action-bar/starting_job_modals.tsx | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 70be3ed09df..2a4763695a3 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -16,6 +16,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released ### 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) diff --git a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx index a3f071a2fb6..40640a56de1 100644 --- a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx +++ b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx @@ -111,6 +111,7 @@ type StartJobFormProps = Props & { type BoundingBoxSelectionProps = { isBoundingBoxConfigurable?: boolean; userBoundingBoxes: UserBoundingBox[]; + isSuperUser: boolean; onChangeSelectedBoundingBox: (bBoxId: number | null) => void; value: number | null; }; @@ -183,6 +184,7 @@ export function BoundingBoxSelection({ function BoundingBoxSelectionFormItem({ isBoundingBoxConfigurable, userBoundingBoxes, + isSuperUser, onChangeSelectedBoundingBox, value: selectedBoundingBoxId, }: BoundingBoxSelectionProps): JSX.Element { @@ -218,7 +220,7 @@ function BoundingBoxSelectionFormItem({ }, { validator: (_rule, value) => { - if (!isBoundingBoxConfigurable) return Promise.resolve(); + if (!isBoundingBoxConfigurable || isSuperUser) return Promise.resolve(); const selectedBoundingBox = userBoundingBoxes.find((bbox) => bbox.id === value); let rejectionReason = ""; @@ -533,6 +535,7 @@ function StartJobForm(props: StartJobFormProps) { const dataset = useSelector((state: OxalisState) => state.dataset); const tracing = useSelector((state: OxalisState) => state.tracing); const activeUser = useSelector((state: OxalisState) => state.activeUser); + const isActiveUserSuperUser = activeUser?.isSuperUser || false; const colorLayers = getColorLayers(dataset); const layers = chooseSegmentationLayer ? getSegmentationLayers(dataset) : colorLayers; const [useCustomWorkflow, setUseCustomWorkflow] = React.useState(false); @@ -643,6 +646,7 @@ function StartJobForm(props: StartJobFormProps) { form.setFieldsValue({ boundingBoxId: bBoxId })} value={form.getFieldValue("boundingBoxId")} /> From 42f1c52bf8a12b22ee8921e6b8c8a3fe9354b644 Mon Sep 17 00:00:00 2001 From: Florian M Date: Tue, 19 Nov 2024 13:14:42 +0100 Subject: [PATCH 3/4] Remove Google Analytics (#8201) * Remove Google Analytics * changelog, migration guide * Update CHANGELOG.unreleased.md Co-authored-by: Daniel --------- Co-authored-by: Daniel --- CHANGELOG.unreleased.md | 1 + MIGRATIONS.unreleased.md | 2 + app/utils/WkConf.scala | 5 --- app/views/main.scala.html | 23 ---------- conf/application.conf | 3 -- .../admin/dataset/dataset_upload_view.tsx | 2 - .../advanced_dataset/dataset_table.tsx | 2 - .../dataset/dataset_settings_view.tsx | 2 - .../explorative_annotations_view.tsx | 3 -- frontend/javascripts/main.tsx | 2 - frontend/javascripts/navbar.tsx | 13 ++---- .../oxalis/model/helpers/analytics.ts | 44 ------------------- .../oxalis/model/sagas/settings_saga.ts | 8 ---- .../oxalis/view/action_bar_view.tsx | 2 - .../oxalis/view/nml_upload_zone_container.tsx | 2 - frontend/javascripts/router.tsx | 22 ---------- 16 files changed, 7 insertions(+), 129 deletions(-) delete mode 100644 frontend/javascripts/oxalis/model/helpers/analytics.ts diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 2a4763695a3..f069e844ba0 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -24,5 +24,6 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released - 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 diff --git a/MIGRATIONS.unreleased.md b/MIGRATIONS.unreleased.md index 20414e596e6..de99ce01d12 100644 --- a/MIGRATIONS.unreleased.md +++ b/MIGRATIONS.unreleased.md @@ -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: diff --git a/app/utils/WkConf.scala b/app/utils/WkConf.scala index c71a644185e..0272635bbf2 100644 --- a/app/utils/WkConf.scala +++ b/app/utils/WkConf.scala @@ -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") @@ -259,7 +255,6 @@ class WkConf @Inject()(configuration: Configuration) extends ConfigReader with L Silhouette, Jobs, Airbrake, - GoogleAnalytics, BackendAnalytics, Slick, Voxelytics, diff --git a/app/views/main.scala.html b/app/views/main.scala.html index f78be6c1aae..921ea8c5e1f 100755 --- a/app/views/main.scala.html +++ b/app/views/main.scala.html @@ -6,9 +6,6 @@ - @if(conf.GoogleAnalytics.trackingId.nonEmpty) { - - } @(conf.WebKnossos.tabTitle) @openGraphTitle.map { ogt => @@ -52,25 +49,5 @@
- - @if(conf.GoogleAnalytics.trackingId.nonEmpty) { - - - } diff --git a/conf/application.conf b/conf/application.conf index 0ae8b6f25dd..2cfdcccb0cd 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -293,9 +293,6 @@ airbrake { projectID = "insert-valid-projectID-here" } -# Front-end analytics -googleAnalytics.trackingId = "" - # Slack notification slackNotifications { uri = "" diff --git a/frontend/javascripts/admin/dataset/dataset_upload_view.tsx b/frontend/javascripts/admin/dataset/dataset_upload_view.tsx index 653d2ff1249..46b46d4116b 100644 --- a/frontend/javascripts/admin/dataset/dataset_upload_view.tsx +++ b/frontend/javascripts/admin/dataset/dataset_upload_view.tsx @@ -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, @@ -350,7 +349,6 @@ class DatasetUploadView extends React.Component { }); finishDatasetUpload(datastoreUrl, uploadInfo).then( async () => { - trackAction("Upload dataset"); Toast.success(messages["dataset.upload_success"]); let maybeError; diff --git a/frontend/javascripts/dashboard/advanced_dataset/dataset_table.tsx b/frontend/javascripts/dashboard/advanced_dataset/dataset_table.tsx index 80631b46f8e..ffabefa87bc 100644 --- a/frontend/javascripts/dashboard/advanced_dataset/dataset_table.tsx +++ b/frontend/javascripts/dashboard/advanced_dataset/dataset_table.tsx @@ -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, @@ -791,7 +790,6 @@ export function DatasetTags({ }; } - trackAction("Edit dataset tag"); updateDataset(dataset, updater); }; diff --git a/frontend/javascripts/dashboard/dataset/dataset_settings_view.tsx b/frontend/javascripts/dashboard/dataset/dataset_settings_view.tsx index 7567b7fe756..5b593afcd14 100644 --- a/frontend/javascripts/dashboard/dataset/dataset_settings_view.tsx +++ b/frontend/javascripts/dashboard/dataset/dataset_settings_view.tsx @@ -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"; @@ -390,7 +389,6 @@ class DatasetSettingsView extends React.PureComponent { 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."); } @@ -475,7 +473,6 @@ class ExplorativeAnnotationsView extends React.PureComponent { editAnnotation(newAnnotation.id, newAnnotation.typ, { tags: newAnnotation.tags, }); - trackAction("Edit annotation tag"); } return newAnnotation; diff --git a/frontend/javascripts/main.tsx b/frontend/javascripts/main.tsx index 4e997850157..31d59217e44 100644 --- a/frontend/javascripts/main.tsx +++ b/frontend/javascripts/main.tsx @@ -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"; @@ -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()]); diff --git a/frontend/javascripts/navbar.tsx b/frontend/javascripts/navbar.tsx index 7d9d3571080..6c09b28fc88 100644 --- a/frontend/javascripts/navbar.tsx +++ b/frontend/javascripts/navbar.tsx @@ -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"; @@ -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({ @@ -831,7 +826,7 @@ function Navbar({ location.href = "/"; }; - const version = useFetch(getAndTrackVersion, null, []); + const version = useFetch(getVersion, null, []); const [isHelpMenuOpen, setIsHelpMenuOpen] = useState(false); const [polledVersion, setPolledVersion] = useState(null); const [isHelpModalOpen, setIsHelpModalOpen] = useState(false); @@ -839,7 +834,7 @@ function Navbar({ useInterval( async () => { if (isHelpMenuOpen) { - setPolledVersion(await getAndTrackVersion(true)); + setPolledVersion(await getVersion()); } }, 2000, diff --git a/frontend/javascripts/oxalis/model/helpers/analytics.ts b/frontend/javascripts/oxalis/model/helpers/analytics.ts deleted file mode 100644 index 43af3d697b1..00000000000 --- a/frontend/javascripts/oxalis/model/helpers/analytics.ts +++ /dev/null @@ -1,44 +0,0 @@ -import window from "libs/window"; -import Store from "oxalis/store"; - -function getOrganization() { - const { activeUser } = Store.getState(); - return activeUser != null ? activeUser.organization : null; -} - -// @ts-expect-error ts-migrate(7019) FIXME: Rest parameter 'params' implicitly has an 'any[]' ... Remove this comment to see the full error message -function gtagGuard(...params) { - // @ts-expect-error ts-migrate(2339) FIXME: Property 'gtag' does not exist on type '(Window & ... Remove this comment to see the full error message - if (typeof window.gtag !== "undefined" && window.gtag !== null) { - // @ts-expect-error ts-migrate(2339) FIXME: Property 'gtag' does not exist on type '(Window & ... Remove this comment to see the full error message - window.gtag(...params); - } -} - -export function trackAction(action: string): void { - gtagGuard("event", "action", action, getOrganization()); -} -export function trackVersion(version: string): void { - gtagGuard("event", "version", { - event_category: "page_load", - event_label: version, - }); -} -export function googleAnalyticsLogClicks(evt: MouseEvent) { - // This function logs all clicks on elements that contain text to google analytics - // Flow doesn't allow to check for the textContent property otherwise - const target = evt.target as any as Node; - - if (target.textContent != null) { - // Restrict the textContent to a maximum length - const textContent = target.textContent.trim().slice(0, 50); - - if (textContent.length > 0) { - gtagGuard("event", "click", { - event_category: textContent, - event_label: getOrganization(), - }); - } - } -} -export default {}; diff --git a/frontend/javascripts/oxalis/model/sagas/settings_saga.ts b/frontend/javascripts/oxalis/model/sagas/settings_saga.ts index da0666c79e3..bc7ef8e9076 100644 --- a/frontend/javascripts/oxalis/model/sagas/settings_saga.ts +++ b/frontend/javascripts/oxalis/model/sagas/settings_saga.ts @@ -5,7 +5,6 @@ import { import { type Saga, take, select } from "oxalis/model/sagas/effect-generators"; import { all, takeEvery, debounce, call, retry } from "typed-redux-saga"; import type { UpdateUserSettingAction } from "oxalis/model/actions/settings_actions"; -import { trackAction } from "oxalis/model/helpers/analytics"; import { updateUserConfiguration, updateDatasetConfiguration } from "admin/admin_rest_api"; import ErrorHandling from "libs/error_handling"; import Toast from "libs/toast"; @@ -97,12 +96,6 @@ function* prepareDatasetSettingsForSaving( return maskedDatasetConfiguration; } -function* trackUserSettingsAsync(action: UpdateUserSettingAction): Saga { - if (action.propertyName === "newNodeNewTree") { - yield* call(trackAction, `${action.value ? "Enabled" : "Disabled"} soma clicking`); - } -} - function* showUserSettingToast(action: UpdateUserSettingAction): Saga { const { propertyName } = action; @@ -129,7 +122,6 @@ export default function* watchPushSettingsAsync(): Saga { pushDatasetSettingsAsync(originalDatasetSettings), ), debounce(2500, "UPDATE_LAYER_SETTING", () => pushDatasetSettingsAsync(originalDatasetSettings)), - takeEvery("UPDATE_USER_SETTING", trackUserSettingsAsync), takeEvery("UPDATE_USER_SETTING", showUserSettingToast), ]); } diff --git a/frontend/javascripts/oxalis/view/action_bar_view.tsx b/frontend/javascripts/oxalis/view/action_bar_view.tsx index a10ecb1df13..0f33c15c2c9 100644 --- a/frontend/javascripts/oxalis/view/action_bar_view.tsx +++ b/frontend/javascripts/oxalis/view/action_bar_view.tsx @@ -9,7 +9,6 @@ import { getLayoutConfig, addNewLayout, } from "oxalis/view/layouting/layout_persistence"; -import { trackAction } from "oxalis/model/helpers/analytics"; import AddNewLayoutModal from "oxalis/view/action-bar/add_new_layout_modal"; import { withAuthentication } from "admin/auth/authentication_modal"; import { type ViewMode, type ControlMode, MappingStatusEnum } from "oxalis/constants"; @@ -196,7 +195,6 @@ class ActionBarView extends React.PureComponent { fallbackLayerName, maybeMappingName, ); - trackAction("Create hybrid tracing (from view mode)"); location.href = `${location.origin}/annotations/${annotation.typ}/${annotation.id}${location.hash}`; }; diff --git a/frontend/javascripts/oxalis/view/nml_upload_zone_container.tsx b/frontend/javascripts/oxalis/view/nml_upload_zone_container.tsx index 07ce3751d89..5d37fa67e45 100644 --- a/frontend/javascripts/oxalis/view/nml_upload_zone_container.tsx +++ b/frontend/javascripts/oxalis/view/nml_upload_zone_container.tsx @@ -8,7 +8,6 @@ import type { Dispatch } from "redux"; import type { OxalisState } from "oxalis/store"; import { setDropzoneModalVisibilityAction } from "oxalis/model/actions/ui_actions"; import FormattedDate from "components/formatted_date"; -import { trackAction } from "oxalis/model/helpers/analytics"; type State = { files: Array; @@ -115,7 +114,6 @@ class NmlUploadZoneContainer extends React.PureComponent { files, dropzoneActive: false, }); - trackAction("NML drag and drop"); this.props.hideDropzoneModal(); }; diff --git a/frontend/javascripts/router.tsx b/frontend/javascripts/router.tsx index dcbc7815c49..4e8d088609c 100644 --- a/frontend/javascripts/router.tsx +++ b/frontend/javascripts/router.tsx @@ -46,7 +46,6 @@ import window from "libs/window"; import _ from "lodash"; import Navbar from "navbar"; import { ControlModeEnum } from "oxalis/constants"; -import { trackAction } from "oxalis/model/helpers/analytics"; import type { OxalisState } from "oxalis/store"; import HelpButton from "oxalis/view/help_modal"; import TracingLayoutView from "oxalis/view/layouting/tracing_layout_view"; @@ -85,26 +84,6 @@ type StateProps = { }; type Props = StateProps; const browserHistory = createBrowserHistory(); -browserHistory.listen((location) => { - // @ts-ignore - if (typeof window.ga !== "undefined" && window.ga !== null && window.ga.getByName != null) { - // t0 is the default tracker name - // @ts-ignore - const tracker = window.ga.getByName("t0"); - if (tracker == null) return; - const lastPage = tracker.get("page"); - const newPage = location.pathname; - - // The listener is called repeatedly for a single page change, don't send repeated pageviews - if (lastPage !== newPage) { - // Update the tracker state first, so that subsequent pageviews AND events use the correct page - // @ts-ignore - window.gtag("set", "page_path", newPage); - // @ts-ignore - window.gtag("event", "page_view"); - } - } -}); function PageNotFoundView() { return ( @@ -673,7 +652,6 @@ class ReactRouter extends React.Component { null, resolutionRestrictions, ); - trackAction(`Create ${type} tracing`); return `/annotations/${annotation.id}`; }} /> From 417ce8fb23af9d229a67f3924d82792a95de1477 Mon Sep 17 00:00:00 2001 From: frcroth Date: Wed, 20 Nov 2024 09:34:47 +0100 Subject: [PATCH 4/4] Rename parameter in findAllListableExplorationals (#8208) --- app/controllers/AnnotationController.scala | 3 +-- app/controllers/UserController.scala | 6 ++---- app/models/annotation/Annotation.scala | 24 +++++++++++++++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/controllers/AnnotationController.scala b/app/controllers/AnnotationController.scala index 9279822fa10..7a5b610240c 100755 --- a/app/controllers/AnnotationController.scala +++ b/app/controllers/AnnotationController.scala @@ -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) ) diff --git a/app/controllers/UserController.scala b/app/controllers/UserController.scala index 6fbd048f64c..8e5b92af165 100755 --- a/app/controllers/UserController.scala +++ b/app/controllers/UserController.scala @@ -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) ) @@ -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) ) diff --git a/app/models/annotation/Annotation.scala b/app/models/annotation/Annotation.scala index 887bf7439c9..cd0f0e38c2e 100755 --- a/app/models/annotation/Annotation.scala +++ b/app/models/annotation/Annotation.scala @@ -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.