diff --git a/authentik/events/api/events.py b/authentik/events/api/events.py index c073ae62bb..e00dbe1b20 100644 --- a/authentik/events/api/events.py +++ b/authentik/events/api/events.py @@ -138,6 +138,7 @@ class EventViewSet(ModelViewSet): from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField return [ + StrField(Event, "event_uuid"), StrField(Event, "app", suggest_options=True), StrField(Event, "client_ip"), JSONSearchField(Event, "user"), diff --git a/web/package-lock.json b/web/package-lock.json index 46438130a1..e458fe540b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -30,6 +30,8 @@ "@mdx-js/mdx": "^3.1.0", "@mrmarble/djangoql-completion": "^0.8.3", "@open-wc/lit-helpers": "^0.7.0", + "@openlayers-elements/core": "^0.4.0", + "@openlayers-elements/maps": "^0.4.0", "@patternfly/elements": "^4.1.0", "@patternfly/patternfly": "^4.224.2", "@sentry/browser": "^9.30.0", @@ -2589,6 +2591,48 @@ "@lit/reactive-element": "^1.0.0 || ^2.0.0" } }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-style-spec": { + "version": "13.28.0", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.28.0.tgz", + "integrity": "sha512-B8xM7Fp1nh5kejfIl4SWeY0gtIeewbuRencqO3cJDrCHZpaPg7uY+V8abuR+esMeuOjRl5cLhVTP40v+1ywxbg==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/unitbezier": "^0.0.0", + "csscolorparser": "~1.0.2", + "json-stringify-pretty-compact": "^2.0.0", + "minimist": "^1.2.6", + "rw": "^1.3.3", + "sort-object": "^0.3.2" + }, + "bin": { + "gl-style-composite": "bin/gl-style-composite.js", + "gl-style-format": "bin/gl-style-format.js", + "gl-style-migrate": "bin/gl-style-migrate.js", + "gl-style-validate": "bin/gl-style-validate.js" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", + "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", + "license": "BSD-2-Clause" + }, "node_modules/@mdx-js/mdx": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", @@ -3071,6 +3115,27 @@ "lit": "^2.0.0 || ^3.0.0" } }, + "node_modules/@openlayers-elements/core": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@openlayers-elements/core/-/core-0.4.0.tgz", + "integrity": "sha512-msY2QGYCYf5Zph16j08KszgqtHmMORCK7B5afpe5iM8c3FFSfjijUffiw93MGeowoN4Yo5jfkxuI2plpyidR0A==", + "license": "MIT", + "dependencies": { + "lit": "^3.1.4", + "ol": "^7.5.0" + } + }, + "node_modules/@openlayers-elements/maps": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@openlayers-elements/maps/-/maps-0.4.0.tgz", + "integrity": "sha512-uxGW3Lt1BVA8eC0HykXLZA4a3EfCU44FdGaudC4Xu0s+XYPOEPxCGLDCsWSuy67NvEUTFb+odu6mRDLofxdquA==", + "license": "MIT", + "dependencies": { + "@openlayers-elements/core": "^0.4.0", + "lit": "^3.1.4", + "ol": "^7.5.0" + } + }, "node_modules/@opentelemetry/api": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", @@ -3971,6 +4036,12 @@ "lit": "^3.2.1" } }, + "node_modules/@petamoriken/float16": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz", + "integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==", + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -12178,6 +12249,12 @@ "dev": true, "license": "MIT" }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -13381,6 +13458,12 @@ "node": ">= 0.4" } }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -15962,6 +16045,43 @@ "node": ">=6.9.0" } }, + "node_modules/geotiff": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.1.3.tgz", + "integrity": "sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==", + "license": "MIT", + "dependencies": { + "@petamoriken/float16": "^3.4.7", + "lerc": "^3.0.0", + "pako": "^2.0.4", + "parse-headers": "^2.0.2", + "quick-lru": "^6.1.1", + "web-worker": "^1.2.0", + "xml-utils": "^1.0.2", + "zstddec": "^0.1.0" + }, + "engines": { + "node": ">=10.19" + } + }, + "node_modules/geotiff/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/geotiff/node_modules/quick-lru": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", + "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -18528,6 +18648,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-pretty-compact": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", + "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -18967,6 +19093,12 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/lerc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", + "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==", + "license": "Apache-2.0" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -19496,6 +19628,12 @@ "dev": true, "license": "MIT" }, + "node_modules/mapbox-to-css-font": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.5.tgz", + "integrity": "sha512-VJ6nB8emkO9VODI0Fk+TQ/0zKBTqmf/Pkt8Xv0kHstoc0iXRajA00DAid4Kc3K5xeFIOoiZrVxijEzj0GLVO2w==", + "license": "BSD-2-Clause" + }, "node_modules/markdown-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", @@ -20924,7 +21062,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -22048,6 +22185,34 @@ "dev": true, "optional": true }, + "node_modules/ol": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/ol/-/ol-7.5.2.tgz", + "integrity": "sha512-HJbb3CxXrksM6ct367LsP3N+uh+iBBMdP3DeGGipdV9YAYTP0vTJzqGnoqQ6C2IW4qf8krw9yuyQbc9fjOIaOQ==", + "license": "BSD-2-Clause", + "dependencies": { + "earcut": "^2.2.3", + "geotiff": "^2.0.7", + "ol-mapbox-style": "^10.1.0", + "pbf": "3.2.1", + "rbush": "^3.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/openlayers" + } + }, + "node_modules/ol-mapbox-style": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-10.7.0.tgz", + "integrity": "sha512-S/UdYBuOjrotcR95Iq9AejGYbifKeZE85D9VtH11ryJLQPTZXZSW1J5bIXcr4AlAH6tyjPPHTK34AdkwB32Myw==", + "license": "BSD-2-Clause", + "dependencies": { + "@mapbox/mapbox-gl-style-spec": "^13.23.1", + "mapbox-to-css-font": "^2.4.1", + "ol": "^7.3.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -22378,6 +22543,12 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-headers": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", + "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", + "license": "MIT" + }, "node_modules/parse-ms": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", @@ -22528,6 +22699,19 @@ "node": ">= 14.16" } }, + "node_modules/pbf": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", + "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, "node_modules/peek-readable": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.4.2.tgz", @@ -22989,6 +23173,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" + }, "node_modules/proxy-agent": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", @@ -23204,6 +23394,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", + "license": "ISC" + }, "node_modules/ramda": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", @@ -23325,6 +23521,15 @@ "node": ">= 0.8" } }, + "node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "license": "MIT", + "dependencies": { + "quickselect": "^2.0.0" + } + }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", @@ -24242,6 +24447,15 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, "node_modules/resolve.exports": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", @@ -25083,6 +25297,22 @@ "node": ">= 14" } }, + "node_modules/sort-asc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz", + "integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz", + "integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -25119,6 +25349,18 @@ "node": ">=0.10.0" } }, + "node_modules/sort-object": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz", + "integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==", + "dependencies": { + "sort-asc": "^0.1.0", + "sort-desc": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sort-object-keys": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz", @@ -28351,6 +28593,12 @@ "license": "MIT", "optional": true }, + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", + "license": "Apache-2.0" + }, "node_modules/webauthn-polyfills": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/webauthn-polyfills/-/webauthn-polyfills-0.1.7.tgz", @@ -28925,6 +29173,12 @@ "repeat-string": "^1.5.2" } }, + "node_modules/xml-utils": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz", + "integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==", + "license": "CC0-1.0" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -29182,6 +29436,12 @@ "zod": "^3.18.0" } }, + "node_modules/zstddec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz", + "integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==", + "license": "MIT AND BSD-3-Clause" + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/web/package.json b/web/package.json index f9caf5d87d..aaae6cdf55 100644 --- a/web/package.json +++ b/web/package.json @@ -101,6 +101,8 @@ "@mdx-js/mdx": "^3.1.0", "@mrmarble/djangoql-completion": "^0.8.3", "@open-wc/lit-helpers": "^0.7.0", + "@openlayers-elements/core": "^0.4.0", + "@openlayers-elements/maps": "^0.4.0", "@patternfly/elements": "^4.1.0", "@patternfly/patternfly": "^4.224.2", "@sentry/browser": "^9.30.0", diff --git a/web/src/admin/events/EventListPage.ts b/web/src/admin/events/EventListPage.ts index 758491a0dc..ff2ecf92da 100644 --- a/web/src/admin/events/EventListPage.ts +++ b/web/src/admin/events/EventListPage.ts @@ -1,3 +1,7 @@ +import "#elements/Tabs"; +import { WithLicenseSummary } from "#elements/mixins/license"; +import { updateURLParams } from "#elements/router/RouteMatch"; +import "@goauthentik/admin/events/EventMap"; import "@goauthentik/admin/events/EventVolumeChart"; import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; @@ -15,10 +19,12 @@ import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement, property } from "lit/decorators.js"; -import { Event, EventsApi } from "@goauthentik/api"; +import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; + +import { Event, EventsApi, LicenseSummaryStatusEnum } from "@goauthentik/api"; @customElement("ak-event-list") -export class EventListPage extends TablePage { +export class EventListPage extends WithLicenseSummary(TablePage) { expandable = true; supportsQL = true; @@ -39,11 +45,15 @@ export class EventListPage extends TablePage { order = "-created"; static get styles(): CSSResult[] { - return super.styles.concat(css` - .pf-m-no-padding-bottom { - padding-bottom: 0; - } - `); + // @ts-expect-error + return super.styles.concat( + PFGrid, + css` + .pf-m-no-padding-bottom { + padding-bottom: 0; + } + `, + ); } async apiEndpoint(): Promise> { @@ -62,16 +72,39 @@ export class EventListPage extends TablePage { } renderSectionBefore(): TemplateResult { - return html` -
+ if (this.licenseSummary?.status !== LicenseSummaryStatusEnum.Unlicensed) { + return html`
-
- `; + ) => { + this.search = `event_uuid = "${ev.detail.eventId}"`; + this.page = 1; + updateURLParams({ + search: this.search, + tablePage: this.page, + }); + this.fetch(); + }} + > +
`; + } + return html``; } row(item: EventWithContext): SlottedTemplateResult[] { diff --git a/web/src/admin/events/EventMap.ts b/web/src/admin/events/EventMap.ts new file mode 100644 index 0000000000..d56074dd4d --- /dev/null +++ b/web/src/admin/events/EventMap.ts @@ -0,0 +1,139 @@ +import { EventWithContext } from "#common/events"; +import { globalAK } from "#common/global"; +import { PaginatedResponse } from "#elements/table/Table"; +import { AKElement } from "@goauthentik/elements/Base"; +import "@openlayers-elements/core/ol-layer-vector"; +import type OlLayerVector from "@openlayers-elements/core/ol-layer-vector"; +import "@openlayers-elements/core/ol-map"; +import type OlMap from "@openlayers-elements/core/ol-map"; +import "@openlayers-elements/maps/ol-layer-openstreetmap"; +import "@openlayers-elements/maps/ol-select"; +import Feature from "ol/Feature"; +import { Point } from "ol/geom"; +import { fromLonLat } from "ol/proj"; +import Icon from "ol/style/Icon"; +import Style from "ol/style/Style"; + +import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit"; +import { customElement, property, query } from "lit/decorators.js"; + +import PFCard from "@patternfly/patternfly/components/Card/card.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +import { Event } from "@goauthentik/api"; + +/** + * + * @event {select-event} - Fired when an event is selected on the map. ID of the event is contained + * in the `Event.detail` field. + * + */ +@customElement("ak-events-map") +export class EventMap extends AKElement { + @property({ attribute: false }) + events?: PaginatedResponse; + + @query("ol-layer-vector") + vectorLayer?: OlLayerVector; + + @query("ol-map") + map?: OlMap; + + @property({ type: Number }) + zoomPaddingPx = 100; + + static get styles(): CSSResult[] { + return [ + PFBase, + PFCard, + css` + .pf-c-card, + ol-map { + height: 24rem; + } + :host([theme="dark"]) ol-map { + filter: invert(100%) hue-rotate(180deg); + } + `, + ]; + } + + updated(_changedProperties: PropertyValues): void { + if (!_changedProperties.has("events")) { + return; + } + if (!this.vectorLayer?.source || !this.map?.map) { + return; + } + // Remove all existing points + this.vectorLayer.source.clear(); + // Re-add them + this.events?.results + .filter((event) => { + if (!Object.hasOwn(event.context, "geo")) { + return false; + } + const geo = (event as EventWithContext).context.geo; + if (!geo?.lat || !geo.long) { + return false; + } + return true; + }) + .forEach((event) => { + const geo = (event as EventWithContext).context.geo!; + const point = new Point(fromLonLat([geo.long!, geo.lat!])); + const feature = new Feature({ + geometry: point, + }); + feature.setStyle( + new Style({ + image: new Icon({ + anchor: [0.5, 1], + offset: [0, 0], + opacity: 1, + scale: 1, + rotateWithView: false, + rotation: 0, + src: `${globalAK().api.base}static/dist/assets/images/map_pin.svg`, + }), + }), + ); + feature.setId(event.pk); + this.vectorLayer?.source?.addFeature(feature); + }); + // Zoom to show points better + this.map.map.getView().fit(this.vectorLayer.source.getExtent(), { + padding: [ + this.zoomPaddingPx, + this.zoomPaddingPx, + this.zoomPaddingPx, + this.zoomPaddingPx, + ], + duration: 500, + maxZoom: 4.5, + }); + } + + render(): TemplateResult { + return html`
+ + ) => { + const eventId = ev.detail.feature.getId(); + this.dispatchEvent( + new CustomEvent("select-event", { + composed: true, + bubbles: true, + detail: { + eventId: eventId, + }, + }), + ); + }} + > + + + +
`; + } +} diff --git a/web/src/admin/events/EventVolumeChart.ts b/web/src/admin/events/EventVolumeChart.ts index fa38d0e6e8..07f36f0761 100644 --- a/web/src/admin/events/EventVolumeChart.ts +++ b/web/src/admin/events/EventVolumeChart.ts @@ -11,11 +11,14 @@ import { EventVolume, EventsApi, EventsEventsListRequest } from "@goauthentik/ap @customElement("ak-events-volume-chart") export class EventVolumeChart extends EventChart { + @property({ attribute: "with-map", type: Boolean }) + withMap = false; + _query?: EventsEventsListRequest; @property({ attribute: false }) set query(value: EventsEventsListRequest | undefined) { - if (JSON.stringify(this._query) === JSON.stringify(value)) return; + if (JSON.stringify(value) !== JSON.stringify(this._query)) return; this._query = value; this.refreshHandler(); } @@ -24,6 +27,9 @@ export class EventVolumeChart extends EventChart { return super.styles.concat( PFCard, css` + :host([with-map]) .pf-c-card { + height: 24rem; + } .pf-c-card { height: 20rem; } diff --git a/web/src/assets/images/map_pin.svg b/web/src/assets/images/map_pin.svg new file mode 100644 index 0000000000..f2a2a0072d --- /dev/null +++ b/web/src/assets/images/map_pin.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/web/src/common/events.ts b/web/src/common/events.ts index 418c9a0a10..e07fac5672 100644 --- a/web/src/common/events.ts +++ b/web/src/common/events.ts @@ -12,6 +12,8 @@ export interface EventGeo { city?: string; country?: string; continent?: string; + lat?: number; + long?: number; } export interface EventModel { diff --git a/web/src/components/events/ObjectChangelog.ts b/web/src/components/events/ObjectChangelog.ts index 653d5ee37f..7cc5665d9d 100644 --- a/web/src/components/events/ObjectChangelog.ts +++ b/web/src/components/events/ObjectChangelog.ts @@ -76,7 +76,6 @@ export class ObjectChangelog extends Table { html`
${formatElapsedTime(item.created)}
${item.created.toLocaleString()}`, html`
${item.clientIp || msg("-")}
- ${EventGeo(item)}`, ]; }