* Give a more semantic name to a function
* Make the LineGraph component thinner
* Move LineGraph into a separate file
* Move interval logic into interval-picker.js
This commit also fixes a bug where the interval name displayed inside
the picker component flickers the default interval when the graph is
loading.
The problem was that we were counting on graphData for returning us the
current interval: `let currentInterval = graphData?.interval`
We should always know the default interval before making the main-graph
request. Sending graphData to IntervalPicker component does not make
sense anyway.
* extract data fetching functions out of VisitorGraph component
* Return graph_metric key from Top Stats API
This commit introduces no behavioral changes - only starts returning an
additional field, allowing us to avoid the following logic in React:
1. Finding the metric names, given a stat display name. E.g.
`Unique visitors (last 30 min) -> visitors`
2. Checking if a metric is graphable or not
* Move metric state into localStorage
This commit gets rid of the internal `metric` state in the VisitorGraph
component and starts using localStorage for that instead.
This commit also chains the main-graph request into the top-stats request
callback - meaning that we'll always fetch new graph data after top stats
are updated. And we do it all in a single function.
Doing so simplifies the loading state significantly, and also helps to
make it clear, that at all times, existing top stats are required before
we can fetch the graph. That's because the metric is determined by which
Top stats are returned (for example, we can't be sure whether revenue
metrics will be returned or not).
* Make sure graph tooltip says "Converted Visitors"
* Extract a StatsExport function component
Again, instead of relying on `graphData?.interval` we can read it from
localStorage, or default to the largest interval available. The export
should not be dependant on the graph.
* Extract SamplingNotice function component
* Extract WithImportedSwitch function component
* Stop "lazy-loading" the graph and top stats
Since the container is always on top on the page, it will be visible on
the first render in any case - no matter the screen size.
* Turn VisitorGraph into a function component
* Display empty container until everything has loaded
* Do not display loading spinner on realtime ticks
* Turn Top Stats into a fn component
* fetch top stats and graph async
* Make sure revenue metrics can remain on the graph
* Add an extra check to canMetricBeGraphed
* fix typo
* remove redundant double negation
* CH Migration: exit/entry hostnames in sessions_v2
* Leave only exit_page_hostname, we already record hostnames
* Use ClickHouse DDL in favour of ecto so that cluster is included
* Compress with ZSTD(3)
* Expose Hostname filter in the dashboard dropdown
* Add `exit_page_hostname` to ClickHouse `sessions_v2` schema
* Start tracking hostname changes in sessions
* Implement hostname filter suggestions
* Enable filtering by `event:hostname`
* Add tests for filtering by hostnames
* Ensure filter suggestions work for exit pages too
* Allow overriding hostnames with `send_pageview` mix task
* Remove `:window_time_on_page` flag
It seems that we can remove it after all?
* Initialize `experimental_hostname_filter` query parameter
* Rewrite cache store behaviour with regards to session hostnames
* Work around inconsistent session merging
So that `populate_stats` can get closer to actual ingestion
* Improve top stats test
* Make it possible to filter sessions by entry/exit hostnames
* Update pages tests
* Expose `experimental_hostname_filtering` temporarily in the UI
* Untested yet: also apply experimental filtering to sources
* Introduce `hostname_filter` feature flag
* Format
* Test top sources with hostname filter + experimental flag
* Check import presence across all imports and not just the first one
Also, simplify imported data toggle rendering to not explicitly
refer to the earliest import source.
* Change imported stats toggle icon in dashboard
* Test `Imported.get_imports_date_range/1`
* Simplify failed UA/GA import email copy
* Add validation for the events metric in main_graph
* Test the already existing events metric support in main-graph
* Put total conversions on the graph
* extract main_graph_csv function (refactor only)
* add total_conversions and conversion_rate to goal-filtered visitors.csv
* update changelog
* add conversion rate to Stats API timeseries
* make sure CR can be queried as the only metric
* add a test asserting zeros are returned
* add tests for filtering by other properties at the same time
* Remove unnecessary validation of params
1. It doesn't make to validate `interval` (and its granularity) in all
endpoints. It's only relevant for the main graph.
2. The plug (renamed to `date_validation_plug`) already makes sure that
the dates are validated. No need to call the same function again in
Top Stats and Funnel endpoints.
* add metric validation to main graph
* Add tests for main graph API
* put conversion rate on the graph
* update changelog
* Add revenue metrics into metrics.ex
* make fn private
* avoid setting graph metric to visitors in goal-filtered view
* UX improvement: don't autofocus on Custom properties on dashboard
Currently when you visit the dashboard with a certain configuration,
it will automatically scroll to the bottom, which is annoying.
To reproduce:
1. localStorage.clear() in console
2. Refresh, open properties at the very bottom
3. Refresh again
Expected behavior:
1. Dashboard shows
Actual behavior:
1. Dashboard scrolls to the bottom
* Changelog entry
* Migration: add country rules
* Add CountryRule schema
* Implement CountryRule cache
* Add country rules context interface
* Start country rules cache
* Lookup country rules on ingestion
* Remove :shields feature flag from test helpers
* Add nested sidebar menu for Shields
* Fix typo
* IP Rules: hide description on mobile view
* Prepare SiteController to handle multiple shield types
* Seed some country shield
* Implement LV for country rules
* Remove "YOU" indicator from country rules
* Fix small build
* Format
* Update typespecs
* Make docs link point at /countries
* Fix flash on top of modal for Safari
* Build the rule struct with site_id provided up-front
* Clarify why we're messaging the ComboBox component
* Re-open combobox suggestions after pressing Escape
* Update changelog
* Fix font size in country table cells
* Pass `added_by` via rule add options
* Display site's timezone timestamps in rule tooltips
* Display formatted timestamps in site's timezone
And simplify+test Timezone module; an input timestamp converted
to UTC can never be ambiguous.
* Remove no-op atom
* Display the maximum number of rules when reached
* Improve readability of remove button tests
* Credo
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Follow-up to https://github.com/plausible/analytics/pull/3719
The previous behavior was predicated on:
- Allowing a single custom property filter
- Allowing breaking down only by the chosen custom property filter
Now these restrictions are removed the previous auto-switching just becomes annoying
* Replace footer text
* add COPYING.txt file
* Add new logos
* Use new logos in all layouts
* New logos
* Check license key on startup
* Bypass license check when Mix.env == :dev
* Use new logos with smaller wordmarks
* Add generic logo_path/1 function
* Use new favicons everywhere
* Bypass license check in test env
* Use sha256 for license key hash
* Mix.env -> config_env()
* Use Mix.evn at compile time rather than runtime
* Mix format
---------
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* Revert "Unify percentage change for CR and bounce_rate (#3781)"
This reverts commit a6b1a6ebc7.
* Revert "Bring Stats API up to speed: Add `conversion_rate` to Aggregate and Breakdown (#3739)"
This reverts commit 672d682e95.
* WIP
* Allow `experimetnal_session_count` request serialization
* Extend `Plausible.Stats.Query` with `experimental_session_count` flag
* Add `FunWithFlags` actor implementation for `Site`
* Change the way sessions are retrieved
* Remove redundant test
* Format
* Update the test
---------
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* disable event metric with include_imported in every case
* add missing test for metric validation
* refactor metric validation functions
* implement conversion_rate metric validation
* move calculate_cr function into Stats.Util
* Refactor: Move aggregate CR logic into Stats.aggregate
* define atoms to exist
* Ensure that CR does not depend on visitors being queried
If 'visitors' are already queried, we'll use that value. Otherwise we'll
need to make another query to fetch it.
* confirm Stats API aggregate supports CR (tests only)
* small refactor
This is the only 'event_property' left after pattern matching on all
others in the function clauses defined above.
* Make it possible to optionally query conversion_rate
...in breakdown queries (excluding goal and custom prop breakdown)
* A little refactor asking for revenue metrics
1. The `@revenue_metrics` module attribute is an empty list on full build
anyway
2. We don't need to query for revenue metrics if there are no revenue goals
returned in the given query (even if revenue goals exist in site.goals)
3. Revenue metrics are already dropped in prop breakdown without a goal
filter via (get_revenue_tracking_currency/3)
* Make it possible to optionally query conversion_rate (continuation)
... also from a custom prop and goal breakdown
* Frontend adjustments to the Locations report
* Display conversion rate in Regions and Cities (ListReport view)
* Display total conversions, conversions (visitors), and CR in the
"Details" modals of Countries, Regions, and Cities
* Move the percentage into a separate column in the Countries details table
* confirm Stats API breakdown supports conversion_rate (tests only)
* small refactor: extract maybe_add_time_on_page function
* Make it possible to query cr alone
... (without the visitors metric). Already supported in aggregate, this
commit only implements it for the breakdown API.
* Reuse Stats.Util helper functions from b02db88 for aggregate API
We can follow the same logic as with breakdown for manually adding
`visitors` into the metrics list and taking it out of the response
later on.
That way we don't have to make another query, e.g. in a case where
only pageviews and conversion rate is queried. Also keeps things
consistent.
* changelog update
* fix test after resolving merge conflict
* Use explicit string->atom mapping instead of casting
* alias Util module instead of importing it
* use Enum.empty instead of Enum.any
* improve readability
* rename special_metrics to computed_metrics and explain with a comment
* rename visitors_without_event_filters to total_visitors
* keep a single function for removing unwanted metrics
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Support using matches/contains for most filters
* Change behavior where we auto-zoom to specific browser/os/source to only do so if filtering on a single value
* No contains filtering on `location`
* Update CHANGELOG.md
* Fix merge conflict
* WIP: PropFilterRow
* Get multi-behavior working
* Render multiple prop filters in one
* Modal reads from query string correctly
* Backend support for multiple custom property filters
* Add backend tests for multiple custom property filters
* Disable already selected options in property keys
We can't allow choosing the same property multiple times without changing the request
params, which we decided against
* Allow choosing any property under Behaviors > Custom props even if custom prop filter applied
This was a limitation (I believe) introduced by using ARRAY JOINs to query custom properties
* CHANGELOG.md
* Solve credo warning about too deep nesting
* Update assets/js/dashboard/stats/modals/prop-filter-modal.js
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
* Refactor internal function for clarity
* Add another step -> Add another
* Solve 500 error
* Separate boxes per property filter
* Retain other filters in props table
* removeFilter behavior for props
* matches_member support for custom props
* filter_suggestions for prop keys should account for prop filter
* find over filter
* refactor appliedFilters
* FILTER_TYPES => FILTER_OPERATIONS
* Make add another link not wrap the whole page
* Unique keys
---------
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
* Allow `matches` operator to work in BE for custom props
Note: No FE support yet, needs further testing
* feat: allow choosing `contains` for property filters in the UI
* no autocomplete on prop values if `contains` for consistency
* CHANGELOG.md
* Fix: Handle (none) property in property breakdowns when using matching
When matching we should always exclude (none)
* Make modal for goal settings trigger without BE roundtrip
* Turn goal form into a live component and extract modal into a wrapper
* Further extract modal component and handle reset action
* Make ComboBox selection callback more flexible
* Add rudimentary loading state to dialog
* Make form unaware of being put inside a modal
* Make modal a live component and completely reset contents on open server-side
* Try to avoid race condition
* Fix race condition
* Remove unnecessary conditional on socket assigns
* Add typespecs and fix formatting
* Make goals form high latency friendly
* Fix tests to account for goal settings form becoming live component
* Fix goal settings form live component declaration
* Add documentation for modal
* Fix small build test
* Fix typo
Co-authored-by: hq1 <hq@mtod.org>
* Revert no longer necessary test changes from 46f65d9
* Fix and clean up modal styling
* Keep focus on dialog when open and show only spinner on backdrop when loading
* Adjust corners and shadows and implement open/close transitions
* Lock body scroll when modal is open
* Make modal top-aligned again to avoid jumping around on variable content height
---------
Co-authored-by: hq1 <hq@mtod.org>
* Revert "Remove unused RocketIcon"
This reverts commit c5e8d0c172.
* Revert "Display either hash or actual error message"
This reverts commit 0c091ab35f.
* Revert "Use ApiErrorNotice in funnels"
This reverts commit 5929de248e.
* Revert "Don't render "No data yet" when there's a NetworkError for example"
This reverts commit 70bee07632.
* Revert "Show the sinking shuttle notice whenever an API error occurs"
This reverts commit 9a62c8af2b.
* Revert "Add Hahash dependency"
This reverts commit b94207ea0a.
* Remove support hash
* Add Hahash dependency
* Don't leak internal server error details to the user
* Show the sinking shuttle notice whenever an API error occurs
* Don't render "No data yet" when there's a NetworkError for example
* Use ApiErrorNotice in funnels
* Display either hash or actual error message
The reason "internal-server-error" doesn't work well as a fallback
hash is that e.g. `NetworkError when attempting to fetch resource`
might be completely at client's fault. In such cases it's better
to display the whole thing still.
* Remove unused RocketIcon
* Display premium features tabs on the dashboard
This commit makes the funnels and props tab on the dashboard visible
even when the site owner's plan does not have access to that feature.
This is to raise awareness of those features, and if the site owner does
not want to see that tab, they can still click "Hide this report" to
hide it.
Previously, when the plan did not support a feature, the feature module
`enabled/1` function returned `false`, regardless of the
`sites.feature_enabled` toggle. This commit creates a new function
called `opted_out/1` to differentiate access from explicitly opting out
a feature.
* Remove unused data-conversions-enabled attribute
* DRY Plausible.Billing.Feature.check_availability/1 function
* Allow opting out features the user doesn't have access to
* add upgrade CTA to FeatureSetupNotice
* fix JS linting errors
* simplify notice.js
* fix behaviour when deleting funnels saved to localstorage
In case some other funnel exists, we will use that as the default
selected one. If not, a feature setup notice will be displayed again.
---------
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
This commit replaces the `mousedown` event for `click` to close a modal,
such as the detail dialog. This allows the scrollbar to be clicked
without firing an event, and right clicks too.
Closes#2872
* Inline theme script to layout
* Extract theme_script as Heex component
* Remove unused function
* Reference assigns directly
* Clean up current user
* Clean up theme javascript
* Use new theme script in focus.html layout
* Use `assigns` instead of `@conn.assigns` in `focus.html.heex` template too
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Avoid redirect in site settings
* Fix unicode in SiteController existing tests
* Fix various tests
* Add CHANGELOG
* Make sure test site is example.com
* Use Route helpers in site_controller
* Fix UTF redirect in change domain submit action
* Fix UTF site domain in reset stats action
* Update applications
* Clone community config
* Move modules to experimental dir
* Update runtime config
* Apply first set of compile-time conditionals
* Move funnel schemas to experimental
* Make funnel schema-less build compile
* Use experimental/lib for elixir code
* Move JS funnels to experimental
* Clean up conditional rendering
* Tidy up the pipeline
* Make two builds pass tests without warnings
* Reuse existing dotenvs
* Do a bunch of renames
* Clean up naming
* Run secondary CI
* Update router
* Remove RewriteFunnelDupes migration
Tests were disabled already and it was a one-off shot
* Fixup quota mixins
* Add moduledoc
* Change MIX_ENV for seconary test run
* Skip crm on small
* !fixup
* Exclude flags pipeline
* Update lib/plausible_web/controllers/stats_controller.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Revert "Remove site pins for now"
This reverts commit 5eccf4eaf6.
* Implement basic site pin schema level logic within user specific preferences
* Add vertical ellipsis menu markup
* Implement basic changesets for user preferences
* Implement pin toggling
* Try to fix pin sorting
* Implement pin toggling in LV
* Adjust moduledocs for new schema(s)
* Remove unnecessary `distinct` from query
* Use `button` for pin/unpin action
* Generalize preference setting
* Rename schema and fields for clarity
* Rename `list_type` -> `entry_type`
* Safeguard setting options
* Test `set_option/4` and `toggle_pin/2`
* Add test for listing pinned sites via `Sites.list`
* Disallow pinning sites outside page explicitly
* Test pinning in LV
* Test conditional rendering of site settings in /sites
* Remove unnecessary TODO comment
* Safeguard `Sites.set_option/4` against invalid user/site combo
* Handle pinned sites in dashboard site picker
* Clear flashes upon (un)pinning sites
* Update CHANGELOG
* Prevent blinking of hamburger menu items on first paint
* Highlight hamburger handle on hover in /sites
* Start showing hotkeys in site picker again
* Sort pinned sites in the order they were pinned
* Update sites list order immediately after pin/unpin toggle
* Refactor and split `Sites.list/3`, extracting `Sites.list_with_invitations/3`
* Cap number of pinned sites at 9 per user
* First pass on visual indication of site cards (dis)appearing
* Apply ellipsis gradient+shadow on card hover
* Fix responsive padding of site cards
* Sort by invitations first, pinned sites second and then the rest
* Revert "Apply ellipsis gradient+shadow on card hover"
This reverts commit 0608796612639030ccbb12df639709f78edc1434.
* Apply more subtle hover effect on the ellipsis menu
* Make error and success flash LV boxes use separate component containers
* Promote `pinned_at` in table migration to a column
* Switch logic to using `pinned_at` as a standard schema field
* Refactor `Sites.list*` getting rid of subquery (h/t @ukutaht)
* Remove migration which is already merged upstream
---------
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* Read feature status from Billing.Feature instead of %Site{}
This commit changes data attributes passed to React. Previously the
controller read feature statuses directly from the %Site{} schema. The
Billing.Feature context is aware of the user plan and the features
available.
* Limit funnels internal API based on site owner plan
* Limit props internal API based on site owner plan
* Use site factory in QueryTest
* Limit custom property filter based on site owner plan
* Limit revenue goals queries based on site owner plan
* Add SSO link with signed JWT token
* Falls back to Nolt URL without SSO if token cannot be generated
* Add profile image (gravatar) to Nolt SSO link
* Improve navbar dropdown
* Add 'contact support' link to nav dropdown
* Add CSS rule to prevent horizontal jumps
* Dark mode styling
* Close dropdown when link is clicked
* Clarify links in dropdown
* Clarify CSS comment
* Use Alpine.data() over window
* Rename suggestions_dropdown -> combo-box
* Mix format
* Make logout link look good on dark mode
* Use proxy for gravatar
* Do not use Gravatar proxy in self-hosted
* Changelog
* Add Github Repo link to nav dropdown
* Make dialyzer happy
* Add proxy for Gravatar
* Update assets/css/app.css
Co-authored-by: hq1 <hq@mtod.org>
* Update lib/plausible_web/controllers/avatar_controller.ex
Co-authored-by: hq1 <hq@mtod.org>
* Fix alpine <> Liveview integration
---------
Co-authored-by: hq1 <hq@mtod.org>
This pull request implements limits to funnels, revenue goals and custom props based on the site owner plan. It extends the current "premium feature" notice to account for the new plans, trials and the on-going private preview. Stats API is not in the context of this pull request, but will be implemented likewise.
* Add zxcvbn dependency
* Change password length range requirement from 6-64 to 12-128
* Reimplement register form in LV
* Implement server-side check for password strength
* Add rudimentary strength meter
* Make password input with strength a separate component and improve it
* Fix existing tests to provide strong enough password
* Apply formatting
* Replace existing registration form with new one
* Hide built-in label in `.input` component when none provided
* Crop password to first 32 chars for analysis by zxcvbn
* Add tests for new form components
* Integrate hCaptcha into LV
* Fix existing AuthController tests
* Add tests for Live.RegisterForm
* Hide strength meter when password input is empty
* Randomize client IP in headers during tests to avoid hitting rate limit
* Apply auxilliary formatting fixes to AuthController
* Integrate registration from invitation into LV registration logic
* Fix existing password set and reset forms
* Make `password_length_hint` component more customizable
* Optimize `Auth.User.set_password/2`
* Remove unnecessary attribute from registration form
* Move password set and reset forms to LV
* Add tests for SetPasswordForm LV component
* Add tests for password checks in `Auth.User`
* Document code a bit
* Implement simpler approach to hCaptcha integration
* Update CHANGELOG.md
* Improve consistency of color scheme
* Introduce debounce across all text inputs in registration and password forms
* Fix email input background in register form
* Ensure only single error is rendered for empty password confirmation case
* Remove `/password` form entirely in favor of preferred password reset
* Remove unnecessary `router` option from `live_render` calls
* Make expensive assigns in LV with `assign_new` (h/t @aerosol)
* Accept passwords longer than 32 bytes uniformly as very strong
* Avoid displaying blank error side by side with weak password error
* Make register actions handle errors gracefully
* Render only a single piece of feedback to reduce noise
* Make register and password reset forms pw manager friendly (h/t @cnkk)
* Move registration forms to live routes
* Delete no longer used deadviews
* Adjust registration form in accordance to changes in #3290
* Reintroduce dogfood page path for invitation form from #3290
* Use alternative approach to submitting plausible metrics from LV form
* Rename metrics events and extend tests to account for them