Skip to content

Commit

Permalink
Dashboard empty states (#2068)
Browse files Browse the repository at this point in the history
  • Loading branch information
paolodamico committed Oct 28, 2020
1 parent 4b8b0ec commit e6217f6
Show file tree
Hide file tree
Showing 17 changed files with 428 additions and 53 deletions.
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>
)}
<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: '500' }}
>
{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>
)}

<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;
padding: 32px;
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_description_on_dashboard_items
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

0 comments on commit e6217f6

Please sign in to comment.