Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dashboard empty states #2068

Merged
merged 9 commits into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions frontend/public/empty-line-graph-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions frontend/public/empty-line-graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion frontend/src/scenes/dashboard/DashboardItem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import './DashboardItems.scss'
import { Link } from 'lib/components/Link'
import { useActions, useValues } from 'kea'
import { Dropdown, Menu, Tooltip, Alert } from 'antd'
import { Dropdown, Menu, Tooltip, Alert, Button } from 'antd'
import { combineUrl, router } from 'kea-router'
import { deleteWithUndo, Loading } from 'lib/utils'
import React, { useEffect, useState } from 'react'
Expand Down Expand Up @@ -133,6 +134,11 @@ export function DashboardItem({
{...longPressProps}
data-attr={'dashboard-item-' + index}
>
{item.is_sample && (
<div className="sample-dasbhoard-overlay">
<Button onClick={() => router.actions.push(link)}>Configure</Button>
</div>
)}
Comment on lines +137 to +141
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's sort of annoying that this Configure overlay just pops in on hover with no warning. I think it should be clear that this needs configuration before attempting to interact + the overlay should be less surprising and intrusive (also, something like a 200ms transition would do a lot here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup agreed, just updated, wdyt? the delay would be great, but I prefer to keep this in CSS to simplify

<div className={`dashboard-item-container ${className}`}>
<div className="dashboard-item-header" style={{ cursor: inSharedMode ? 'auto' : 'move' }}>
<div className="dashboard-item-title">
Expand All @@ -149,6 +155,7 @@ export function DashboardItem({
router.actions.push(link)
}
}}
style={{ fontSize: 16, fontWeight: 'bold' }}
paolodamico marked this conversation as resolved.
Show resolved Hide resolved
>
{item.name}
</Link>
Expand Down Expand Up @@ -307,6 +314,10 @@ export function DashboardItem({
</div>
)}
</div>
{item.description && (
<div style={{ padding: '0 16px', marginBottom: 16, fontSize: 12 }}>{item.description}</div>
)}

Comment on lines +317 to +320
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really should allow for editing now IMO, as the descriptions will become irrelevant and confusing when the user updates the dashboard item with some other insight than the initial one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I've opened #2075 to tackle this as an improvement to be able to get this in before the code freeze in the meantime.

<div className="dashboard-item-content">
{Element ? (
<Alert.ErrorBoundary message="Error rendering graph!">
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/scenes/dashboard/DashboardItems.scss
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,23 @@
}
}
}

.sample-dasbhoard-overlay {
background-color: rgba(0, 0, 0, 0.7);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
align-items: center;
justify-content: center;
z-index: 100;
}

&:hover .sample-dasbhoard-overlay {
display: flex;
}
}

.react-grid-layout {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/dashboard/Dashboards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function _Dashboards(): JSX.Element {
style={{ cursor: 'pointer' }}
onClick={() =>
addDashboard({
name: 'Default App Dashboard',
name: 'Web App Dashboard',
show: true,
useTemplate: 'DEFAULT_APP',
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/dashboard/NewDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function NewDashboard(): JSX.Element {
Empty Dashboard
</Select.Option>
<Select.Option data-attr="dashboard-select-default-app" value="DEFAULT_APP">
Default Dashboard - App
Default Dashboard - Web App
</Select.Option>
</Select>
</Form.Item>
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/scenes/insights/ActionsLineGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LineGraph } from './LineGraph'
import { useActions, useValues } from 'kea'
import { trendsLogic } from 'scenes/insights/trendsLogic'
import { router } from 'kea-router'
import { LineGraphEmptyState } from './EmptyStates'

export function ActionsLineGraph({
dashboardItemId = null,
Expand Down Expand Up @@ -46,9 +47,7 @@ export function ActionsLineGraph({
}
/>
) : (
<p style={{ textAlign: 'center', paddingTop: '4rem' }}>
We couldn't find any matching events. Try changing dates or pick another action or event.
</p>
<LineGraphEmptyState color={color} />
)
) : (
<Loading />
Expand Down
38 changes: 38 additions & 0 deletions frontend/src/scenes/insights/EmptyStates.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useValues } from 'kea'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import React from 'react'
import imgEmptyLineGraph from 'public/empty-line-graph.svg'
import imgEmptyLineGraphDark from 'public/empty-line-graph-dark.svg'
import { QuestionCircleOutlined } from '@ant-design/icons'

export function LineGraphEmptyState({ color }: { color: string }): JSX.Element {
const { featureFlags } = useValues(featureFlagLogic)
return (
<>
{!featureFlags['1694-dashboards'] && (
<p style={{ textAlign: 'center', paddingTop: '4rem' }}>
We couldn't find any matching events. Try changing dates or pick another action or event.
</p>
)}
{featureFlags['1694-dashboards'] && (
<div className="text-center" style={{ height: '100%' }}>
<img
src={color === 'white' ? imgEmptyLineGraphDark : imgEmptyLineGraph}
alt=""
style={{ maxHeight: '100%', maxWidth: '80%', opacity: 0.5 }}
/>
<div style={{ textAlign: 'center', fontWeight: 'bold', marginTop: 16 }}>
Seems like there's no data to show this graph yet{' '}
<a
target="_blank"
href="https://posthog.com/docs/features/trends"
style={{ color: color === 'white' ? 'rgba(0, 0, 0, 0.85)' : 'white' }}
>
<QuestionCircleOutlined />
</a>
</div>
</div>
)}
</>
)
}
2 changes: 1 addition & 1 deletion latest_migrations.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ admin: 0003_logentry_add_action_flag_choices
auth: 0011_update_proxy_permissions
contenttypes: 0002_remove_content_type_name
ee: 0002_hook
posthog: 0093_remove_user_is_superuser
posthog: 0094_auto_20201028_1208
rest_hooks: 0002_swappable_hook_model
sessions: 0001_initial
social_django: 0008_partial_timestamp
36 changes: 30 additions & 6 deletions posthog/api/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
from distutils.util import strtobool
from typing import Any, Dict

import posthoganalytics
from django.core.cache import cache
from django.db.models import Prefetch, QuerySet
from django.db.models import Model, Prefetch, QuerySet
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from django.utils.timezone import now
from django.views.decorators.clickjacking import xframe_options_exempt
from rest_framework import authentication, request, response, serializers, viewsets
from rest_framework import authentication, response, serializers, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request

from posthog.auth import PersonalAPIKeyAuthentication, PublicTokenAuthentication
from posthog.helpers import create_dashboard_from_template
Expand Down Expand Up @@ -58,6 +60,12 @@ def create(self, validated_data: Dict, *args: Any, **kwargs: Any) -> Dashboard:
team=team,
)

posthoganalytics.capture(
request.user.distinct_id,
"dashboard created",
{**dashboard.get_analytics_metadata(), "from_template": bool(use_template), "template_key": use_template},
)

return dashboard

def update( # type: ignore
Expand All @@ -66,7 +74,15 @@ def update( # type: ignore
validated_data.pop("use_template", None) # Remove attribute if present
if validated_data.get("is_shared") and not instance.share_token:
instance.share_token = secrets.token_urlsafe(22)
return super().update(instance, validated_data)

instance = super().update(instance, validated_data)

if "request" in self.context:
posthoganalytics.capture(
self.context["request"].user.distinct_id, "dashboard updated", instance.get_analytics_metadata()
)

return instance

def get_items(self, dashboard: Dashboard):
if self.context["view"].action == "list":
Expand Down Expand Up @@ -103,7 +119,7 @@ def get_queryset(self) -> QuerySet:

return queryset.filter(team=self.request.user.team)

def retrieve(self, request: request.Request, *args: Any, **kwargs: Any) -> response.Response:
def retrieve(self, request: Request, *args: Any, **kwargs: Any) -> response.Response:
pk = kwargs["pk"]
queryset = self.get_queryset()
dashboard = get_object_or_404(queryset, pk=pk)
Expand All @@ -121,6 +137,7 @@ class Meta:
fields = [
"id",
"name",
"description",
"filters",
"order",
"type",
Expand All @@ -131,8 +148,9 @@ class Meta:
"last_refresh",
"refreshing",
"result",
"created_at",
"is_sample",
"saved",
"created_at",
"created_by",
]

Expand All @@ -155,6 +173,12 @@ def create(self, validated_data: Dict, *args: Any, **kwargs: Any) -> DashboardIt
else:
raise serializers.ValidationError("Dashboard not found")

def update(self, instance: Model, validated_data: Dict) -> DashboardItem:

# Remove is_sample if it's set as user has altered the sample configuration
validated_data.setdefault("is_sample", False)
return super().update(instance, validated_data)

def get_result(self, dashboard_item: DashboardItem):
if not dashboard_item.filters:
return None
Expand Down Expand Up @@ -184,7 +208,7 @@ def get_queryset(self) -> QuerySet:

return queryset.filter(team=self.request.user.team)

def _filter_request(self, request: request.Request, queryset: QuerySet) -> QuerySet:
def _filter_request(self, request: Request, queryset: QuerySet) -> QuerySet:
filters = request.GET.dict()

for key in filters:
Expand Down
Loading