Skip to content
Next
Projects
Groups
Snippets
Help
Sign in / Register
Toggle navigation
Minds Frontend
Project
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
804
Merge Requests
51
CI / CD
Security & Compliance
Packages
Wiki
Snippets
Members
Collapse sidebar
Close sidebar
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Minds
Minds Frontend
Compare Revisions
409ccf047976e995e69794f912591f469f10cd3b...f03e30f6f3380583b0f38a99ba17e43037cd0153
Source
f03e30f6f3380583b0f38a99ba17e43037cd0153
...
Target
409ccf047976e995e69794f912591f469f10cd3b
Compare
Commits (2)
Analytics v2 finetune
· b3044bc3
Olivia Madrid
authored
1 hour ago
b3044bc3
Merge branch 'analytics-v2-finetune-2089' into 'master'
· f03e30f6
Mark Harding
authored
1 hour ago
Analytics v2 finetune Closes
ux#3
,
#1007
,
#2127
,
#2054
,
#2126
, and
#2089
See merge request
!614
f03e30f6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
43 changed files
with
2203 additions
and
1151 deletions
+2203
-1151
src/app/common/common.module.ts
View file @
f03e30f6
...
...
@@ -113,6 +113,9 @@ import { MarketingComponent } from './components/marketing/marketing.component';
import
{
MarketingFooterComponent
}
from
'
./components/marketing/footer.component
'
;
import
{
ToggleComponent
}
from
'
./components/toggle/toggle.component
'
;
import
{
MarketingAsFeaturedInComponent
}
from
'
./components/marketing/as-featured-in.component
'
;
import
{
SidebarMenuComponent
}
from
'
./components/sidebar-menu/sidebar-menu.component
'
;
import
{
ChartV2Component
}
from
'
./components/chart-v2/chart-v2.component
'
;
import
{
MiniChartComponent
}
from
'
./components/mini-chart/mini-chart.component
'
;
@
NgModule
({
imports
:
[
...
...
@@ -215,6 +218,9 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur
MarketingComponent
,
MarketingFooterComponent
,
MarketingAsFeaturedInComponent
,
SidebarMenuComponent
,
ChartV2Component
,
MiniChartComponent
,
],
exports
:
[
MINDS_PIPES
,
...
...
@@ -305,6 +311,7 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur
ToggleComponent
,
MarketingComponent
,
MarketingAsFeaturedInComponent
,
SidebarMenuComponent
,
],
providers
:
[
SiteService
,
...
...
This diff is collapsed.
src/app/common/components/chart-v2/chart-v2.component.html
0 → 100644
View file @
f03e30f6
<!-- <div
#chartContainer
class="m-chartV2__chartContainer"
[ngClass]="{ isTouchDevice: isTouchDevice }"
>
<plotly-plot
*ngIf="init"
#graphDiv
id="graphDiv"
[data]="data"
[layout]="layout"
[config]="config"
[useResizeHandler]="true"
[style]="{ position: 'relative' }"
(hover)="onHover($event)"
(unhover)="onUnhover($event)"
(plotly_click)="onClick($event)"
>
</plotly-plot>
</div>
<div #hoverInfoDiv id="hoverInfoDiv" class="m-chartV2__hoverInfoDiv">
<i *ngIf="isTouchDevice" class="material-icons" (click)="onUnhover($event)"
>close</i
>
<div class="m-chartV2__hoverInfo__row">
{{ hoverInfo.date | utcDate | date: datePipe }}
</div>
<div
[ngSwitch]="selectedMetric?.unit"
class="m-chartV2__hoverInfo__row--primary"
>
<ng-template ngSwitchCase="number">
{{ hoverInfo.value | number }} {{ selectedMetric.label | lowercase }}
</ng-template>
<ng-template ngSwitchCase="usd">
{{ hoverInfo.value | currency }} USD
</ng-template>
<ng-template ngSwitchDefault>
{{ hoverInfo.value | number: '1.1-3' }} {{ selectedMetric?.unit }}
</ng-template>
</div>
<div class="m-chartV2__hoverInfo__row" *ngIf="isComparison">
vs
<ng-container
[ngSwitch]="selectedMetric?.unit"
class="m-chartV2__hoverInfo__row"
>
<ng-template ngSwitchCase="number">
{{ hoverInfo.comparisonValue | number }}
</ng-template>
<ng-template ngSwitchCase="usd">
{{ hoverInfo.comparisonValue | currency }}
</ng-template>
<ng-template ngSwitchDefault>
{{ hoverInfo.comparisonValue | number: '1.1-3' }}
</ng-template>
</ng-container>
on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }}
</div>
</div> -->
This diff is collapsed.
src/app/
modules/analytics/v2/layouts/layout-table/table
.component.scss
→
src/app/
common/components/chart-v2/chart-v2
.component.scss
View file @
f03e30f6
File moved
This diff is collapsed.
src/app/
modules/analytics/v2/components/menu/menu
.component.spec.ts
→
src/app/
common/components/chart-v2/chart-v2
.component.spec.ts
View file @
f03e30f6
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
AnalyticsMenuComponent
}
from
'
./menu
.component
'
;
import
{
ChartV2Component
}
from
'
./chart-v2
.component
'
;
describe
(
'
AnalyticsMenu
Component
'
,
()
=>
{
let
component
:
AnalyticsMenu
Component
;
let
fixture
:
ComponentFixture
<
AnalyticsMenu
Component
>
;
describe
(
'
ChartV2
Component
'
,
()
=>
{
let
component
:
ChartV2
Component
;
let
fixture
:
ComponentFixture
<
ChartV2
Component
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
AnalyticsMenu
Component
],
declarations
:
[
ChartV2
Component
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
AnalyticsMenu
Component
);
fixture
=
TestBed
.
createComponent
(
ChartV2
Component
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
x
it
(
'
should create
'
,
()
=>
{
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
This diff is collapsed.
src/app/common/components/chart-v2/chart-v2.component.ts
0 → 100644
View file @
f03e30f6
This diff is collapsed.
Click to expand it.
src/app/common/components/mini-chart/mini-chart.component.html
0 → 100644
View file @
f03e30f6
<p>
mini-chart works!
</p>
This diff is collapsed.
src/app/common/components/mini-chart/mini-chart.component.scss
0 → 100644
View file @
f03e30f6
This diff is collapsed.
src/app/
modules/analytics/v2/layouts/layout-table/layout-table
.component.spec.ts
→
src/app/
common/components/mini-chart/mini-chart
.component.spec.ts
View file @
f03e30f6
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
AnalyticsLayoutTableComponent
}
from
'
./layout-table
.component
'
;
import
{
MiniChartComponent
}
from
'
./mini-chart
.component
'
;
describe
(
'
AnalyticsLayoutTable
Component
'
,
()
=>
{
let
component
:
AnalyticsLayoutTable
Component
;
let
fixture
:
ComponentFixture
<
AnalyticsLayoutTable
Component
>
;
describe
(
'
MiniChart
Component
'
,
()
=>
{
let
component
:
MiniChart
Component
;
let
fixture
:
ComponentFixture
<
MiniChart
Component
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
AnalyticsLayoutTable
Component
],
declarations
:
[
MiniChart
Component
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
AnalyticsLayoutTable
Component
);
fixture
=
TestBed
.
createComponent
(
MiniChart
Component
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
x
it
(
'
should create
'
,
()
=>
{
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
This diff is collapsed.
src/app/
modules/analytics/v2/layouts/layout-table/layout-table
.component.ts
→
src/app/
common/components/mini-chart/mini-chart
.component.ts
View file @
f03e30f6
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-
analytics__layout--table
'
,
templateUrl
:
'
./
layout-table
.component.html
'
,
selector
:
'
m-
miniChart
'
,
templateUrl
:
'
./
mini-chart
.component.html
'
,
})
export
class
AnalyticsLayoutTable
Component
implements
OnInit
{
export
class
MiniChart
Component
implements
OnInit
{
constructor
()
{}
ngOnInit
()
{}
...
...
This diff is collapsed.
src/app/common/components/sidebar-menu/categories.default.ts
0 → 100644
View file @
f03e30f6
const
sidebarMenuCategories
=
[
{
category
:
{
id
:
'
analytics
'
,
label
:
'
Analytics
'
,
path
:
'
/analytics/dashboard/
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
},
subcategories
:
[
// {
// id: 'summary',
// label: 'Summary',
// permissions: ['admin', 'user'],
// },
{
id
:
'
traffic
'
,
label
:
'
Traffic
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
},
{
id
:
'
earnings
'
,
label
:
'
Earnings
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
},
// {
// id: 'engagement',
// label: 'Engagement',
// permissions: ['admin', 'user'],
// },
{
id
:
'
trending
'
,
label
:
'
Trending
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
},
// {
// id: 'referrers',
// label: 'Referrers',
// permissions: ['admin', 'user'],
// },
// {
// id: 'plus',
// label: 'Plus',
// permissions: ['admin'],
// },
// {
// id: 'pro',
// label: 'Pro',
// permissions: ['admin'],
// {
// id: 'boost',
// label: 'Boost',
// permissions: ['admin'],
// },
// {
// id: 'nodes',
// label: 'Nodes',
// permissions: ['admin'],
// },
],
},
// {
// category: {
// id: 'test1',
// label: 'Test1',
// permissions: ['admin', 'user'],
// path: '/somepath/bork',
// },
// subcategories: [
// {
// id: 'nodes',
// label: 'Nodes',
// permissions: ['admin'],
// },
// {
// id: 'nodes2',
// label: 'Nodes2',
// permissions: ['admin'],
// },
// ],
// },
// {
// category: {
// id: 'test2',
// label: 'Test2 no subcats',
// path: '/anotherpath/test2',
// },
// },
];
export
default
sidebarMenuCategories
;
This diff is collapsed.
src/app/common/components/sidebar-menu/sidebar-menu.component.html
0 → 100644
View file @
f03e30f6
<section
class=
"m-sidebarMenu"
>
<div
class=
"m-sidebarMenu__topbar"
>
<i
class=
"material-icons"
(click)=
"mobileMenuExpanded = true"
>
menu
</i>
<div
class=
"m-sidebarMenu__topbarCatLabel"
*ngIf=
"activeCat"
>
{{ activeCat.category.label }}
</div>
</div>
<div
class=
"m-sidebarMenu__overlay"
[ngClass]=
"{ mobileMenuExpanded: mobileMenuExpanded }"
(click)=
"mobileMenuExpanded = false"
></div>
<div
class=
"m-sidebarMenu__sidebar"
[ngClass]=
"{ mobileMenuExpanded: mobileMenuExpanded }"
>
<a
class=
"m-sidebarMenu__userWrapper"
[routerLink]=
"['/', user.username]"
>
<img
class=
"m-sidebarMenu__userAvatar"
[src]=
"minds.cdn_url + 'icon/' + user.guid + '/small/' + user.icontime"
/>
<div
class=
"m-sidebarMenu__userDetails"
>
<div
class=
"m-sidebarMenu__userDetails__name"
>
{{ user.name }}
</div>
<div
class=
"m-sidebarMenu__userDetails__username"
>
@{{ user.username }}
</div>
<!-- TODO: get subscriberCount and remove username -->
<!-- <div class="m-sidebarMenu__userDetails__subscribers">
{{ user.subscribers_count | abbr }} subscribers
</div> -->
</div>
</a>
<ng-container
*ngFor=
"let cat of cats"
>
<div
class=
"m-sidebarMenu__catContainer"
*ngIf=
"cat.category.permissionGranted"
[ngClass]=
"{ expanded: cat.category.expanded }"
>
<div
class=
"m-sidebarMenu__catLabel"
>
<h3>
{{ cat.category.label }}
</h3>
<i
class=
"material-icons"
*ngIf=
"cat.category.expanded && cat.subcategories"
(click)=
"cat.category.expanded = false"
>
keyboard_arrow_up
</i
>
<i
class=
"material-icons"
*ngIf=
"!cat.category.expanded && cat.subcategories"
(click)=
"cat.category.expanded = true"
>
keyboard_arrow_down
</i
>
</div>
<div
class=
"m-sidebarMenu__subcatContainer"
*ngIf=
"cat.subcategories"
>
<div
class=
"m-sidebarMenu__subcat"
*ngFor=
"let subcat of cat.subcategories"
>
<a
*ngIf=
"subcat.permissionGranted"
class=
"m-sidebarMenu__subcatLabel"
(click)=
"mobileMenuExpanded = false"
[routerLink]=
"'../' + subcat.id"
routerLinkActive=
"selected"
>
{{ subcat.label }}
</a
>
</div>
</div>
</div>
</ng-container>
</div>
</section>
This diff is collapsed.
src/app/
modules/analytics/v2/components/menu/
menu.component.scss
→
src/app/
common/components/sidebar-menu/sidebar-
menu.component.scss
View file @
f03e30f6
// .m-sidebarMarkers__container,
// m-v2-topbar {
// display: none;
// }
m-sidebarMenu
{
display
:
block
;
// min-width: 180px;
// padding: 16px 16px 16px 80px;
// flex: 1 1 0px;
.m-sidebarMenu
{
padding
:
16px
16px
16px
80px
;
}
i
{
display
:
none
;
cursor
:
pointer
;
}
.m-sidebarMenu__topbar
,
.m-sidebarMenu__userWrapper
{
display
:
none
;
}
.m-sidebarMenu__catContainer
{
.m-sidebarMenu__subcatContainer
{
display
:
block
;
cursor
:
pointer
;
}
}
// .m-sidebarMenu__sidebar {
// position: relative;
// position: -webkit-sticky;
// position: sticky;
// top: 0;
// }
.page.isMobile
m-analytics__menu
{
margin-right
:
-32px
;
flex
:
0
1
0px
;
}
.m-sidebarMenu__catLabel
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
i
{
display
:
none
;
}
}
m-analytics__menu
{
display
:
block
;
max-width
:
160px
;
// ----------------------------------------
// MOBILE
.m-sidebarMenu__subcatContainer
{
cursor
:
pointer
;
display
:
none
;
.m-sidebarMenu__subcat
{
a
{
display
:
block
;
padding
:
8px
0
;
text-decoration
:
none
;
font-weight
:
400
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
a
.selected
,
&
:hover
a
{
@include
m-theme
()
{
color
:
themed
(
$m-blue
);
}
}
}
}
}
// --------------------------------------------------
// TABLET & MOBILE
// --------------------------------------------------
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-sidebarMenu
{
margin-right
:
-32px
;
flex
:
0
1
0px
;
padding
:
0
;
.m-sidebarMenu
{
padding
:
0
8px
;
}
.isMobile
{
.topbar
{
.m-sidebarMenu__topbar
{
display
:
block
;
z-index
:
99999
;
position
:
fixed
;
top
:
0
;
...
...
@@ -24,7 +80,7 @@ m-analytics__menu {
padding
:
16px
;
text-align
:
center
;
@include
m-theme
()
{
background-color
:
themed
(
$m-grey-
10
0
);
background-color
:
themed
(
$m-grey-
5
0
);
color
:
themed
(
$m-grey-800
);
}
...
...
@@ -35,34 +91,32 @@ m-analytics__menu {
left
:
16px
;
transform
:
translateY
(
-50%
);
@include
m-theme
()
{
background-color
:
themed
(
$m-grey-100
);
color
:
themed
(
$m-grey-700
);
color
:
themed
(
$m-grey-300
);
}
}
.
pageTitle
{
.
m-sidebarMenu__topbarCatLabel
{
font-size
:
20px
;
margin
:
0
;
margin
:
0
0
0
-24px
;
min-height
:
20px
;
}
}
.overlay
{
.
m-sidebarMenu__
overlay
{
position
:
fixed
;
top
:
0
;
bottom
:
0
;
left
:
0
;
right
:
0
;
z-index
:
-1
;
// display: none;
background-color
:
transparent
;
transition
:
background-color
0
.5s
cubic-bezier
(
0
.075
,
0
.82
,
0
.165
,
1
);
&
.expanded
{
// display: block;
&
.mobileMenuExpanded
{
z-index
:
999998
;
@include
m-theme
()
{
background-color
:
rgba
(
themed
(
$m-grey-700
)
,
0
.2
);
}
}
}
.sidebar
{
.
m-sidebarMenu__
sidebar
{
z-index
:
999999
;
position
:
fixed
;
top
:
0
;
...
...
@@ -76,50 +130,66 @@ m-analytics__menu {
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
}
&
.
e
xpanded
{
&
.
mobileMenuE
xpanded
{
left
:
0
;
}
.sidebarTitle
{
.m-sidebarMenu__catContainer
{
.m-sidebarMenu__subcatContainer
{
display
:
none
;
}
&
.expanded
{
.m-sidebarMenu__subcatContainer
{
display
:
block
;
.m-sidebarMenu__subcat
{
a
{
padding
:
6px
0
;
}
}
}
}
}
.m-sidebarMenu__catLabel
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
h3
{
font-size
:
20px
;
margin
:
0
;
margin
:
16px
0
;
}
i
{
font-size
:
20px
;
display
:
inline-block
;
font-size
:
26px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
}
}
.
profile
{
.
m-sidebarMenu__userWrapper
{
display
:
flex
;
text-decoration
:
none
;
margin
:
24px
0
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
.
a
vatar
{
.
m-sidebarMenu__userA
vatar
{
border-radius
:
50%
;
margin-right
:
16px
;
}
.
d
etails
{
.
m-sidebarMenu__userD
etails
{
&
>
{
padding
:
8px
0
;
}
.name
{
.
m-sidebarMenu__userDetails__
name
{
font-weight
:
bold
;
}
.username
{
.
m-sidebarMenu__userDetails__
username
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
}
.subscribers
{
.
m-sidebarMenu__userDetails__
subscribers
{
font-size
:
11px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
...
...
@@ -129,32 +199,4 @@ m-analytics__menu {
}
}
}
// ----------------------------------------
padding
:
16px
16px
16px
16px
;
flex
:
1
1
0px
;
i
{
display
:
none
;
}
.catContainer
{
cursor
:
pointer
;
.cat
{
a
{
display
:
block
;
padding
:
6px
0
;
text-decoration
:
none
;
font-weight
:
400
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
}
a
.selected
,
&
:hover
a
{
@include
m-theme
()
{
color
:
themed
(
$m-blue
);
}
}
}
}
}
This diff is collapsed.
src/app/common/components/sidebar-menu/sidebar-menu.component.spec.ts
0 → 100644
View file @
f03e30f6
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
RouterTestingModule
}
from
'
@angular/router/testing
'
;
import
{
Session
}
from
'
../../../services/session
'
;
import
{
sessionMock
}
from
'
../../../../tests/session-mock.spec
'
;
import
{
SidebarMenuComponent
}
from
'
./sidebar-menu.component
'
;
describe
(
'
SidebarMenuComponent
'
,
()
=>
{
let
component
:
SidebarMenuComponent
;
let
fixture
:
ComponentFixture
<
SidebarMenuComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
SidebarMenuComponent
],
imports
:
[
RouterTestingModule
],
providers
:
[{
provide
:
Session
,
useValue
:
sessionMock
}],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
SidebarMenuComponent
);
component
=
fixture
.
componentInstance
;
// component.user = sessionMock.user;
fixture
.
detectChanges
();
});
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
This diff is collapsed.
src/app/common/components/sidebar-menu/sidebar-menu.component.ts
0 → 100644
View file @
f03e30f6
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
ActivatedRoute
}
from
'
@angular/router
'
;
import
{
Session
}
from
'
../../../services/session
'
;
import
menuCategories
from
'
./categories.default
'
;
interface
MenuCategory
{
category
:
MenuLink
;
subcategories
?:
MenuLink
[];
expanded
?:
boolean
;
}
export
{
MenuCategory
};
interface
MenuLink
{
id
:
string
;
label
:
string
;
permissions
?:
string
[];
permissionGranted
?:
boolean
;
path
?:
string
;
}
export
{
MenuLink
};
@
Component
({
selector
:
'
m-sidebarMenu
'
,
templateUrl
:
'
./sidebar-menu.component.html
'
,
})
export
class
SidebarMenuComponent
implements
OnInit
{
cats
:
MenuCategory
[]
=
menuCategories
;
mobileMenuExpanded
=
false
;
activeCat
;
minds
:
Minds
;
user
;
userRoles
:
string
[]
=
[
'
user
'
];
constructor
(
public
route
:
ActivatedRoute
,
public
session
:
Session
)
{}
ngOnInit
()
{
this
.
minds
=
window
.
Minds
;
this
.
user
=
this
.
session
.
getLoggedInUser
();
this
.
getUserRoles
();
this
.
grantPermissionsAndFindActiveCat
();
}
getUserRoles
()
{
if
(
this
.
session
.
isAdmin
())
{
this
.
userRoles
.
push
(
'
admin
'
);
}
// TODO: define & handle other userRole options, e.g. pro, loggedIn
}
grantPermissionsAndFindActiveCat
()
{
this
.
cats
.
forEach
(
catObj
=>
{
catObj
.
category
[
'
permissionGranted
'
]
=
catObj
.
category
.
permissions
?
this
.
checkForRoleMatch
(
catObj
.
category
.
permissions
)
:
true
;
if
(
catObj
.
subcategories
)
{
catObj
.
subcategories
.
forEach
(
subCat
=>
{
subCat
[
'
permissionGranted
'
]
=
subCat
.
permissions
?
this
.
checkForRoleMatch
(
subCat
.
permissions
)
:
true
;
});
}
if
(
location
.
pathname
.
indexOf
(
catObj
.
category
.
path
)
!==
-
1
)
{
catObj
.
category
[
'
expanded
'
]
=
true
;
this
.
activeCat
=
catObj
;
}
else
{
catObj
.
category
[
'
expanded
'
]
=
false
;
}
});
}
checkForRoleMatch
(
permissionsArray
)
{
return
permissionsArray
.
some
(
role
=>
this
.
userRoles
.
includes
(
role
));
}
}
This diff is collapsed.
src/app/modules/analytics/analytics.module.ts
View file @
f03e30f6
...
...
@@ -51,7 +51,6 @@ import { PageviewsCardComponent } from './components/cards/pageviews/pageviews.c
import
{
PageviewsChartComponent
}
from
'
./components/charts/pageviews/pageviews.component
'
;
import
{
AnalyticsDashboardComponent
}
from
'
./v2/dashboard.component
'
;
import
{
AnalyticsLayoutChartComponent
}
from
'
./v2/layouts/layout-chart/layout-chart.component
'
;
import
{
AnalyticsLayoutTableComponent
}
from
'
./v2/layouts/layout-table/layout-table.component
'
;
import
{
AnalyticsLayoutSummaryComponent
}
from
'
./v2/layouts/layout-summary/layout-summary.component
'
;
import
{
AnalyticsMetricsComponent
}
from
'
./v2/components/metrics/metrics.component
'
;
import
{
AnalyticsFiltersComponent
}
from
'
./v2/components/filters/filters.component
'
;
...
...
@@ -63,7 +62,6 @@ import { SearchModule } from '../search/search.module';
import
{
AnalyticsSearchComponent
}
from
'
./v2/components/search/search.component
'
;
import
{
FormsModule
}
from
'
@angular/forms
'
;
import
{
AnalyticsSearchSuggestionsComponent
}
from
'
./v2/components/search-suggestions/search-suggestions.component
'
;
import
{
AnalyticsMenuComponent
}
from
'
./v2/components/menu/menu.component
'
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
...
...
@@ -163,7 +161,6 @@ const routes: Routes = [
Graph
,
AnalyticsDashboardComponent
,
AnalyticsLayoutChartComponent
,
AnalyticsLayoutTableComponent
,
AnalyticsLayoutSummaryComponent
,
AnalyticsMetricsComponent
,
AnalyticsFiltersComponent
,
...
...
@@ -172,7 +169,6 @@ const routes: Routes = [
AnalyticsTableComponent
,
AnalyticsSearchComponent
,
AnalyticsSearchSuggestionsComponent
,
AnalyticsMenuComponent
,
],
providers
:
[
AnalyticsDashboardService
],
})
...
...
This diff is collapsed.
src/app/modules/analytics/v2/categories.default.ts
deleted
100644 → 0
View file @
409ccf04
const
categories
:
Array
<
any
>
=
[
// {
// id: 'summary',
// label: 'Summary',
// permissions: ['admin', 'user'],
// metrics: [],
// },
{
id
:
'
traffic
'
,
label
:
'
Traffic
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
metrics
:
[
'
active_users
'
,
'
signups
'
,
'
unique_visitors
'
,
'
pageviews
'
,
'
impressions
'
,
'
retention
'
,
],
},
{
id
:
'
earnings
'
,
label
:
'
Earnings
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
metrics
:
[
'
total
'
,
'
pageviews
'
,
'
active_referrals
'
,
'
customers
'
],
},
// {
// id: 'engagement',
// label: 'Engagement',
// permissions: ['admin', 'user'],
// metrics: ['posts', 'votes', 'comments', 'reminds', 'subscribers', 'tags'],
// },
{
id
:
'
trending
'
,
label
:
'
Trending
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
metrics
:
[
'
top_content
'
,
'
top_channels
'
],
},
// {
// id: 'referrers',
// label: 'Referrers',
// permissions: ['admin', 'user'],
// metrics: ['top_referrers'],
// },
// {
// id: 'plus',
// label: 'Plus',
// permissions: ['admin'],
// metrics: ['transactions', 'users', 'revenue_usd', 'revenue_tokens'],
// },
// {
// id: 'pro',
// label: 'Pro',
// permissions: ['admin'],
// metrics: ['transactions', 'users', 'revenue_usd', 'revenue_tokens'],
// },
// {
// id: 'boost',
// label: 'Boost',
// permissions: ['admin'],
// metrics: ['transactions', 'users', 'revenue_tokens'],
// },
// {
// id: 'nodes',
// label: 'Nodes',
// permissions: ['admin'],
// metrics: ['transactions', 'users', 'revenue_usd', 'revenue_tokens'],
// },
];
export
default
categories
;
This diff is collapsed.
src/app/modules/analytics/v2/chart-palette.default.ts
View file @
f03e30f6
const
chartPalette
:
Array
<
any
>
=
[
{
id
:
'
m-white
'
,
themeMap
:
[
'
#fff
'
,
'
#161616
'
],
},
{
id
:
'
m-transparent
'
,
themeMap
:
[
'
rgba(0,0,0,0)
'
,
'
rgba(0,0,0,0)
'
],
},
{
id
:
'
m-grey-50
'
,
themeMap
:
[
'
rgba(232,232,232,1)
'
,
'
rgba(53,53,53,1)
'
],
},
{
id
:
'
m-grey-70
'
,
themeMap
:
[
'
#eee
'
,
'
#333
'
],
},
{
id
:
'
m-grey-130
'
,
themeMap
:
[
'
#ccc
'
,
'
#555
'
],
},
{
id
:
'
m-grey-160
'
,
themeMap
:
[
'
#bbb
'
,
'
#555
'
],
},
{
id
:
'
m-grey-300
'
,
themeMap
:
[
'
#999
'
,
'
#666
'
],
},
{
id
:
'
m-blue
'
,
themeMap
:
[
'
#4690df
'
,
'
#44aaff
'
],
},
{
id
:
'
m-red-dark
'
,
themeMap
:
[
'
#c62828
'
,
'
#e57373
'
],
},
{
id
:
'
m-amber-dark
'
,
themeMap
:
[
'
#ffa000
'
,
'
#ffecb3
'
],
},
{
id
:
'
m-green-dark
'
,
themeMap
:
[
'
#388e3c
'
,
'
#8bc34a
'
],
},
{
id
:
'
m-blue-grey-500
'
,
themeMap
:
[
'
#607d8b
'
,
'
#607d8b
'
],
},
];
const
chartPalette
=
{
segmentColorIds
:
[
// Colors for up to 6 segments
'
m-blue
'
,
'
m-grey-160
'
,
'
m-amber-dark
'
,
'
m-green-dark
'
,
'
m-red-dark
'
,
'
m-blue-grey-500
'
,
],
themeMaps
:
[
{
id
:
'
m-white
'
,
themeMap
:
[
'
#fff
'
,
'
#232323
'
],
},
{
id
:
'
m-grey-50
'
,
themeMap
:
[
'
rgba(232,232,232,1)
'
,
'
rgba(47,47,47,1)
'
],
// 222
},
{
id
:
'
m-grey-70
'
,
themeMap
:
[
'
#eee
'
,
'
#404040
'
],
// 333 before 5% lighten
},
{
id
:
'
m-grey-130
'
,
themeMap
:
[
'
#ccc
'
,
'
#515151
'
],
// 444
},
{
id
:
'
m-grey-160
'
,
themeMap
:
[
'
#bbb
'
,
'
#626262
'
],
// 555
},
{
id
:
'
m-grey-300
'
,
themeMap
:
[
'
#999
'
,
'
#737373
'
],
// 666
},
{
id
:
'
m-blue
'
,
themeMap
:
[
'
#4690df
'
,
'
#5db6ff
'
],
// 44aaff
},
{
id
:
'
m-red-dark
'
,
themeMap
:
[
'
#c62828
'
,
'
#e98989
'
],
// e57373
},
{
id
:
'
m-amber-dark
'
,
themeMap
:
[
'
#ffa000
'
,
'
#fff2cc
'
],
// ffecb3
},
{
id
:
'
m-green-dark
'
,
themeMap
:
[
'
#388e3c
'
,
'
#97c95d
'
],
// 8bc34a
},
{
id
:
'
m-blue-grey-500
'
,
themeMap
:
[
'
#607d8b
'
,
'
#6b8a99
'
],
// 607d8b
},
],
};
export
default
chartPalette
;
This diff is collapsed.
src/app/modules/analytics/v2/components/chart/chart.component.html
View file @
f03e30f6
<!-- TODO: Make this into a different component -->
<!-- <m-chart [buckets]="(vm$.thecurrentvisualisation" | async)></m-chart> -->
<!-- TODO: then all this becomes m-plotlyChart -->
<!-- <div *ngIf="vm$ | async as vm"> -->
<div>
<div
#graphDiv
id=
"graphDiv"
></div>
<!-- <plotly-plot
<div
#chartContainer
class=
"m-analyticsChart__chartContainer"
[ngClass]=
"{ isTouchDevice: isTouchDevice }"
>
<plotly-plot
*ngIf=
"init"
#graphDiv
id=
"graphDiv"
[divId]="graphDiv"
[data]=
"data"
[layout]=
"layout"
[config]=
"config"
[useResizeHandler]="true"
[style]=
"{ position: 'relative' }"
[useResizeHandler]=
"true"
(hover)=
"onHover($event)"
(unhover)=
"onUnhover($event)"
(
afterPlot)="afterPlot(
)"
(
plotly_click)=
"onClick($event
)"
>
</plotly-plot> -->
<!-- <div class="hoverInfo__row">
{{ hoverInfo.date | date: selectedTimespan.datePipe }}
</div> -->
</plotly-plot>
</div>
<div
#hoverInfoDiv
id=
"hoverInfoDiv"
class=
"hoverInfoDiv"
>
<div
class=
"hoverInfo__row"
>
{{ hoverInfo.date | utcDate | date: datePipe }}
</div>
<div
[ngSwitch]=
"selectedMetric.unit"
class=
"hoverInfo__row--primary"
>
<div
#hoverInfoDiv
id=
"hoverInfoDiv"
class=
"m-analyticsChart__hoverInfoDiv"
>
<i
*ngIf=
"isTouchDevice"
class=
"material-icons"
(click)=
"onUnhover($event)"
>
close
</i
>
<div
class=
"m-analyticsChart__hoverInfo__row"
>
{{ hoverInfo.date | utcDate | date: datePipe }}
</div>
<div
[ngSwitch]=
"selectedMetric?.unit"
class=
"m-analyticsChart__hoverInfo__row--primary"
>
<ng-template
ngSwitchCase=
"number"
>
{{ hoverInfo.value | number }} {{ selectedMetric.label | lowercase }}
</ng-template>
<ng-template
ngSwitchCase=
"usd"
>
{{ hoverInfo.value | currency }} USD
</ng-template>
<ng-template
ngSwitchDefault
>
{{ hoverInfo.value | number: '1.1-3' }} {{ selectedMetric?.unit }}
</ng-template>
</div>
<div
class=
"m-analyticsChart__hoverInfo__row"
*ngIf=
"isComparison"
>
vs
<ng-container
[ngSwitch]=
"selectedMetric?.unit"
class=
"m-analyticsChart__hoverInfo__row"
>
<ng-template
ngSwitchCase=
"number"
>
{{ hoverInfo.
value | number }} {{ selectedMetric.label | lowercase
}}
{{ hoverInfo.
comparisonValue | number
}}
</ng-template>
<ng-template
ngSwitchCase=
"usd"
>
{{ hoverInfo.
value | currency }} USD
{{ hoverInfo.
comparisonValue | currency }}
</ng-template>
<ng-template
ngSwitchDefault
>
{{ hoverInfo.
value | number: '1.1-3' }} {{ selectedMetric.unit
}}
{{ hoverInfo.
comparisonValue | number: '1.1-3'
}}
</ng-template>
</div>
<div
class=
"hoverInfo__row"
*ngIf=
"isComparison"
>
vs
<ng-container
[ngSwitch]=
"selectedMetric.unit"
class=
"hoverInfo__row"
>
<ng-template
ngSwitchCase=
"number"
>
{{ hoverInfo.comparisonValue | number }}
</ng-template>
<ng-template
ngSwitchCase=
"usd"
>
{{ hoverInfo.comparisonValue | currency }} USD
</ng-template>
<ng-template
ngSwitchDefault
>
{{ hoverInfo.comparisonValue | number: '1.1-3' }}
{{ selectedMetric.unit }}
</ng-template>
</ng-container>
on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }}
</div>
</ng-container>
on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }}
</div>
</div>
This diff is collapsed.
src/app/modules/analytics/v2/components/chart/chart.component.scss
View file @
f03e30f6
m-analytics__chart
{
display
:
block
;
position
:
relative
;
margin-left
:
40px
;
.js-plotly-plot
,
.plot-container
{
height
:
44vh
;
min-height
:
44vh
;
display
:
block
;
}
}
#graphDiv
{
display
:
block
;
position
:
relative
;
g
,
g
>
*
{
...
...
@@ -24,7 +28,7 @@ m-analytics__chart {
}
}
.hoverInfoDiv
{
.
m-analyticsChart__
hoverInfoDiv
{
width
:
160px
;
padding
:
12px
;
position
:
absolute
;
...
...
@@ -37,20 +41,49 @@ m-analytics__chart {
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
box-shadow
:
0
0
4px
rgba
(
themed
(
$m-black
)
,
0
.3
);
color
:
themed
(
$m-grey-
2
00
);
color
:
themed
(
$m-grey-
3
00
);
}
[
class
*=
'hoverInfo__row'
]
{
[
class
*=
'
m-analyticsChart__
hoverInfo__row'
]
{
padding-bottom
:
4px
;
font-weight
:
300
;
&
:last-of-type
{
padding-top
:
2px
;
}
}
.hoverInfo__row--primary
{
.m-analyticsChart__hoverInfo__row--primary
{
font-weight
:
400
;
font-size
:
15px
;
// font-weight: bold;
@include
m-theme
()
{
color
:
themed
(
$m-grey-600
);
}
}
i
{
display
:
none
;
font-size
:
15px
;
position
:
absolute
;
cursor
:
pointer
;
top
:
10px
;
right
:
10px
;
transition
:
color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
&
:hover
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-500
);
}
}
}
}
.isTouchDevice
.m-analyticsChart__hoverInfoDiv
i
{
display
:
block
;
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-analytics__chart
{
margin-left
:
16px
;
}
}
This diff is collapsed.
src/app/modules/analytics/v2/components/chart/chart.component.ts
View file @
f03e30f6
This diff is collapsed.
Click to expand it.
src/app/modules/analytics/v2/components/filter/filter.component.html
View file @
f03e30f6
<div
class=
"
filterLabelWrapper"
*ngIf=
"filter.id !== 'timespan'
"
>
<div
class=
"
m-analyticsFilter__labelWrapper"
*ngIf=
"showLabel
"
>
<span>
{{ filter.label }}
</span>
<m-tooltip
icon=
"help"
>
<div
class=
"filterDesc"
>
{{ filter?.description }}
</div>
<ul
class=
"filterOptions__descContainer"
>
<div>
{{ filter?.description }}
</div>
<ul>
<ng-container
*ngFor=
"let option of filter.options"
>
<li
class=
"filterOption__desc"
>
<span
class=
"filterOption__descLabel"
>
{{ option.label }}
</span
><span
class=
"filterOption__desc"
*ngIf=
"option.description"
>
: {{ option.description }}
</span
>
<li>
<span>
{{ option.label }}
</span
><span
*ngIf=
"option.description"
>
: {{ option.description }}
</span>
</li>
</ng-container>
</ul>
</m-tooltip>
</div>
<div
class=
"
filterW
rapper"
class=
"
m-analyticsFilter__w
rapper"
[ngClass]=
"{
expanded: expanded,
isMobile: isMobile,
dropUp: dropUp
}"
(focus)=
"expanded = true"
(blur)=
"expanded = false"
tabindex=
"0"
>
<div
class=
"filterHeader"
(click)=
"expanded = !expanded"
>
<div
class=
"row"
>
<span
class=
"option option--selected"
>
{{ selectedOption.label }}
</span>
<i
class=
"material-icons"
*ngIf=
"!expanded"
>
keyboard_arrow_down
</i>
<i
class=
"material-icons"
*ngIf=
"expanded"
>
keyboard_arrow_up
</i>
</div>
<div
class=
"m-analyticsFilter__header m-analyticsFilter__row"
(click)=
"expanded = !expanded"
>
<span
class=
"m-analyticsFilter__option m-analyticsFilter__option--selected"
>
{{ selectedOption.label }}
</span>
<i
class=
"material-icons"
*ngIf=
"!expanded"
>
keyboard_arrow_down
</i>
<i
class=
"material-icons"
*ngIf=
"expanded"
>
keyboard_arrow_up
</i>
</div>
<div
class=
"
unselectedO
ptionsContainer"
>
<div
class=
"
m-analyticsFilter__o
ptionsContainer"
>
<ng-container
*ngFor=
"let option of filter.options"
>
<div
class=
"
option
row"
class=
"
m-analyticsFilter__option m-analyticsFilter__
row"
(click)=
"updateFilter(option)"
[ngClass]=
"{
unavailable: option.available === false
}"
>
<span>
{{ option.label }}
</span>
{{ option.label }}
<!-- <span>{{ option.label }}</span> -->
</div>
</ng-container>
</div>
...
...
This diff is collapsed.
src/app/modules/analytics/v2/components/filter/filter.component.scss
View file @
f03e30f6
...
...
@@ -3,18 +3,19 @@ $rounded-bottom: 0 0 3px 3px;
m-analytics__filter
{
position
:
relative
;
margin
:
0
36px
0
0
;
margin
:
0
24px
36px
0
;
z-index
:
2
;
display
:
block
;
}
.
filterL
abelWrapper
{
.
m-analyticsFilter__l
abelWrapper
{
position
:
absolute
;
bottom
:
11
0
%
;
bottom
:
11
5
%
;
white-space
:
nowrap
;
@include
m-theme
()
{
color
:
rgba
(
themed
(
$m-grey-200
)
,
0
.9
);
color
:
themed
(
$m-grey-300
);
}
m-tooltip
{
margin-
righ
t
:
4px
;
margin-
lef
t
:
4px
;
}
>
*
{
display
:
inline-block
;
...
...
@@ -23,75 +24,84 @@ m-analytics__filter {
i
{
font-size
:
12px
;
@include
m-theme
()
{
color
:
rgba
(
themed
(
$m-grey-
2
00
)
,
0
.7
);
color
:
rgba
(
themed
(
$m-grey-
3
00
)
,
0
.7
);
}
}
.m-tooltip--bubble
{
letter-spacing
:
1
.2px
;
line-height
:
16px
;
z-index
:
9999
;
}
.m-tooltip--bubble
{
letter-spacing
:
1
.2px
;
line-height
:
16px
;
z-index
:
9999
;
font-size
:
11px
;
bottom
:
110%
;
left
:
0
;
width
:
160px
;
@include
m-theme
()
{
color
:
themed
(
$m-white
);
background-color
:
themed
(
$m-blue
);
}
>
*
{
font-size
:
11px
;
bottom
:
85%
;
left
:
100%
;
@include
m-theme
()
{
color
:
themed
(
$m-white
);
background-color
:
themed
(
$m-blue
);
}
>
*
{
font-size
:
11px
;
font-weight
:
300
;
line-height
:
inherit
;
letter-spacing
:
inherit
;
}
ul
{
padding-inline-start
:
16px
;
margin-block-end
:
4px
;
li
{
padding-bottom
:
8px
;
.filterOption__descLabel
{
// font-weight: bold;
}
}
font-weight
:
300
;
line-height
:
inherit
;
letter-spacing
:
inherit
;
}
ul
{
padding-inline-start
:
16px
;
margin-block-end
:
4px
;
li
{
padding-bottom
:
8px
;
}
}
}
}
.
filterW
rapper
{
.
m-analyticsFilter__w
rapper
{
cursor
:
pointer
;
&
:focus
{
outline
:
0
;
}
>
*
{
width
:
180px
;
box-sizing
:
border-box
;
}
.m-analyticsFilter__optionsContainer
{
padding
:
8px
0
;
.m-analyticsFilter__option
{
transform
:
translateY
(
25%
);
}
}
&
.expanded
{
@include
m-theme
()
{
box-shadow
:
0px
1px
15px
0
rgba
(
themed
(
$m-black
)
,
0
.15
);
}
.
filterH
eader
{
.
m-analyticsFilter__h
eader
{
@include
m-theme
()
{
border-color
:
themed
(
$m-blue
);
}
}
.unselectedOptionsContainer
{
visibility
:
visible
;
// @include m-theme() {
// box-shadow: 0px 1px 15px 0 rgba(themed($m-black), 0.15);
// }
.m-analyticsFilter__optionsContainer
{
display
:
block
;
}
&
:not
(
.dropUp
)
{
.
filterH
eader
{
.
m-analyticsFilter__h
eader
{
@include
m-theme
()
{
border-radius
:
$rounded-top
;
}
}
.
unselectedO
ptionsContainer
{
.
m-analyticsFilter__o
ptionsContainer
{
border-top
:
none
;
border-radius
:
$rounded-bottom
;
}
}
&
.dropUp
{
.
filterH
eader
{
.
m-analyticsFilter__h
eader
{
border-radius
:
$rounded-bottom
;
}
.
unselectedO
ptionsContainer
{
.
m-analyticsFilter__o
ptionsContainer
{
bottom
:
100%
;
border-radius
:
$rounded-top
;
border-bottom
:
none
;
...
...
@@ -99,40 +109,36 @@ m-analytics__filter {
}
}
.
filterH
eader
{
.
m-analyticsFilter__h
eader
{
position
:
relative
;
width
:
100%
;
padding
:
8px
6px
6px
10px
;
border-radius
:
3px
;
transition
:
all
0
.3s
cubic-bezier
(
0
.075
,
0
.82
,
0
.165
,
1
);
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
color
:
rgba
(
themed
(
$m-grey-200
)
,
0
.9
);
color
:
themed
(
$m-grey-300
);
}
@include
m-theme
()
{
border
:
1px
solid
themed
(
$m-grey-100
);
}
.
filterL
abel
{
.
m-analyticsFilter__l
abel
{
margin-right
:
10px
;
}
i
{
flex-grow
:
0
;
width
:
24px
;
height
:
24px
;
}
.option--selected
{
margin-right
:
8px
;
.m-analyticsFilter__option--selected
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-500
);
}
}
}
.
unselectedO
ptionsContainer
{
.
m-analyticsFilter__o
ptionsContainer
{
position
:
absolute
;
// display: none;
visibility
:
hidden
;
width
:
100%
;
padding
:
8px
6px
6px
10px
;
display
:
none
;
border-radius
:
3px
;
left
:
0px
;
transition
:
box-shadow
0
.3s
cubic-bezier
(
0
.075
,
0
.82
,
0
.165
,
1
);
...
...
@@ -141,21 +147,29 @@ m-analytics__filter {
border-top
:
1px
solid
themed
(
$m-blue
);
background-color
:
themed
(
$m-white
);
}
.option
{
padding
:
5px
0
;
}
}
.row
{
.
m-analyticsFilter__
row
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
height
:
46px
;
padding
:
0
20px
;
&
.m-analyticsFilter__header
{
padding-right
:
10px
;
}
}
.option
{
.m-analyticsFilter__option
{
display
:
inline-block
;
box-sizing
:
border-box
;
width
:
inherit
;
border-radius
:
3px
;
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
color
:
rgba
(
themed
(
$m-grey-200
)
,
0
.9
);
color
:
themed
(
$m-grey-300
);
}
&
.unavailable
{
...
...
@@ -166,19 +180,45 @@ m-analytics__filter {
}
&
:hover:not
(
.unavailable
)
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-
5
00
);
color
:
themed
(
$m-grey-
6
00
);
}
}
}
}
.filterWrapper.isMobile
{
.filterHeader
{
i
{
display
:
none
;
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-analytics__filter
{
.m-analyticsFilter__labelWrapper
{
.m-tooltip--bubble
{
width
:
120px
;
}
}
.m-analyticsFilter__wrapper
{
>
*
{
width
:
140px
;
}
}
}
.option--selected
{
margin-right
:
0
;
}
@media
screen
and
(
max-width
:
$max-mobile
)
{
m-analytics__filter
{
.m-analyticsFilter__wrapper
{
.m-analyticsFilter__header
{
i
{
display
:
none
;
}
}
.m-analyticsFilter__row
{
padding
:
0
18px
;
height
:
40px
;
&
.m-analyticsFilter__header
{
padding-right
:
10px
;
}
}
.m-analyticsFilter__option--selected
{
margin-right
:
0
;
}
}
}
}
This diff is collapsed.
src/app/modules/analytics/v2/components/filter/filter.component.ts
View file @
f03e30f6
...
...
@@ -9,19 +9,9 @@ import {
import
{
Observable
}
from
'
rxjs
'
;
import
{
AnalyticsDashboardService
,
Category
,
Response
,
Dashboard
,
Filter
,
Option
,
Metric
,
Summary
,
Visualisation
,
Bucket
,
Timespan
,
UserState
,
}
from
'
../../dashboard.service
'
;
import
isMobileOrTablet
from
'
../../../../../helpers/is-mobile-or-tablet
'
;
import
{
Session
}
from
'
../../../../../services/session
'
;
@
Component
({
...
...
@@ -32,8 +22,8 @@ import { Session } from '../../../../../services/session';
export
class
AnalyticsFilterComponent
implements
OnInit
{
@
Input
()
filter
:
Filter
;
@
Input
()
dropUp
:
boolean
=
false
;
@
Input
()
showLabel
:
boolean
=
true
;
isMobile
:
boolean
;
expanded
=
false
;
options
:
Array
<
any
>
=
[];
selectedOption
:
Option
;
...
...
@@ -43,39 +33,37 @@ export class AnalyticsFilterComponent implements OnInit {
)
{}
ngOnInit
()
{
// this.subscription = this.analyticsService.timespan$.subscribe(timespan => {
// if (this.filter.id === 'timespan') {
// this.selectedOption =
// this.filter.options.find(option => option.id === timespan) ||
// this.filter.options[0];
// // TODO: make selected option at top of array?
// } else {
// this.selectedOption =
// this.filter.options.find(option => option.selected === true) ||
// this.filter.options[0];
// }
// });
this
.
selectedOption
=
this
.
filter
.
options
.
find
(
option
=>
option
.
selected
===
true
)
||
this
.
filter
.
options
[
0
];
this
.
isMobile
=
isMobileOrTablet
();
}
updateFilter
(
option
:
Option
)
{
this
.
expanded
=
false
;
if
(
'
available
'
in
option
&&
!
option
.
available
)
{
return
;
}
this
.
selectedOption
=
option
;
if
(
this
.
filter
.
id
===
'
timespan
'
)
{
this
.
analyticsService
.
updateTimespan
(
option
.
id
);
console
.
log
(
'
upDateFilter
'
,
option
.
id
);
return
;
}
if
(
!
this
.
selectedOption
.
available
)
{
return
;
}
const
selectedFilterStr
=
`
${
this
.
filter
.
id
}
::
${
option
.
id
}
`
;
this
.
analyticsService
.
updateFilter
(
selectedFilterStr
);
}
// clickHeader() {
// if (this.expanded) {
// console.log('its expanded');
// setTimeout(() => {
// this.expanded = false;
// });
// } else {
// console.log('itsnot expanded');
// }
// document.getElementById("myAnchor").blur();
// }
}
This diff is collapsed.
src/app/modules/analytics/v2/components/filters/filters.component.html
View file @
f03e30f6
<div
class=
"filtersContainer"
>
<div
class=
"
m-analytics__
filtersContainer"
>
<!-- <ng-container *ngFor="let filter of filters$ | async"> -->
<ng-container
*ngFor=
"let filter of filters"
>
<m-analytics
__filter
...
...
This diff is collapsed.
src/app/modules/analytics/v2/components/filters/filters.component.scss
View file @
f03e30f6
.filtersContainer
{
m-analytics__filters
{
display
:
block
;
}
.m-analytics__filtersContainer
{
display
:
flex
;
flex-wrap
:
wrap
;
padding
:
16px
;
padding
:
16px
16px
16px
0
;
position
:
relative
;
margin-top
:
36px
;
margin
:
36px
0
0
40px
;
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-analytics__filtersContainer
{
margin-left
:
16px
;
}
}
This diff is collapsed.
src/app/modules/analytics/v2/components/filters/filters.component.ts
View file @
f03e30f6
...
...
@@ -29,6 +29,7 @@ export class AnalyticsFiltersComponent implements OnInit, OnDestroy {
// Temporarily remove channel search from channel filter options
this
.
analyticsService
.
filters$
.
subscribe
(
filters
=>
{
this
.
filters
=
filters
;
const
channelFilter
=
filters
.
find
(
filter
=>
filter
.
id
===
'
channel
'
);
channelFilter
.
options
=
channelFilter
.
options
.
filter
(
option
=>
{
...
...
This diff is collapsed.
src/app/modules/analytics/v2/components/menu/menu.component.html
deleted
100644 → 0
View file @
409ccf04
<section
class=
"menu"
[ngClass]=
"{ isMobile: isMobile }"
>
<div
class=
"topbar"
*ngIf=
"isMobile"
>
<i
class=
"material-icons"
(click)=
"expanded = true"
>
menu
</i>
<div
class=
"pageTitle"
>
Analytics
</div>
</div>
<div
class=
"overlay"
[ngClass]=
"{ expanded: expanded }"
(click)=
"expanded = false"
></div>
<div
class=
"sidebar"
[ngClass]=
"{ expanded: expanded }"
>
<a
class=
"profile"
*ngIf=
"isMobile"
[routerLink]=
"['/', user.username]"
>
<img
class=
"avatar"
[src]=
"minds.cdn_url + 'icon/' + user.guid + '/small/' + user.icontime"
/>
<div
class=
"details"
>
<div
class=
"name"
>
{{ user.name }}
</div>
<!-- TODO: remove username once subscriberCount is working -->
<div
class=
"username"
>
@{{ user.username }}
</div>
<!-- TODO: get subscriberCount -->
<!-- <div class="subscribers">
{{ user.subscribers_count | abbr }} subscribers
</div> -->
</div>
</a>
<div
class=
"sidebarTitle"
>
<h3>
Analytics
</h3>
<i
class=
"material-icons"
*ngIf=
"isMobile"
(click)=
"expanded = false"
>
keyboard_arrow_up
</i
>
</div>
<div
class=
"catContainer"
>
<!-- TODO: apply permissions from categories.default to cats sidebar -->
<div
class=
"cat"
*ngFor=
"let cat of cats"
>
<a
(click)=
"expanded = false"
[routerLink]=
"'../' + cat.id"
routerLinkActive=
"selected"
>
{{ cat?.label }}
</a
>
</div>
</div>
</div>
</section>
This diff is collapsed.
src/app/modules/analytics/v2/components/menu/menu.component.ts
deleted
100644 → 0
View file @
409ccf04
import
{
Component
,
OnInit
,
OnDestroy
,
Input
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
}
from
'
@angular/core
'
;
import
{
ActivatedRoute
,
Router
,
ParamMap
,
RoutesRecognized
,
}
from
'
@angular/router
'
;
import
{
Subscription
,
Observable
}
from
'
rxjs
'
;
import
{
Client
}
from
'
../../../../../services/api
'
;
import
{
Session
}
from
'
../../../../../services/session
'
;
import
{
AnalyticsDashboardService
,
Category
,
UserState
,
}
from
'
../../dashboard.service
'
;
import
categories
from
'
../../categories.default
'
;
import
isMobileOrTablet
from
'
../../../../../helpers/is-mobile-or-tablet
'
;
@
Component
({
selector
:
'
m-analytics__menu
'
,
templateUrl
:
'
./menu.component.html
'
,
})
export
class
AnalyticsMenuComponent
implements
OnInit
{
isMobile
:
boolean
;
expanded
:
boolean
=
false
;
minds
;
user
;
cats
=
categories
;
// subscription: Subscription;
// paramsSubscription: Subscription;
// category$ = this.analyticsService.category$;
selectedCat
:
string
;
constructor
(
// public client: Client,
public
route
:
ActivatedRoute
,
// private router: Router,
// public analyticsService: AnalyticsDashboardService,
// private cd: ChangeDetectorRef
public
session
:
Session
)
{}
ngOnInit
()
{
this
.
minds
=
window
.
Minds
;
this
.
isMobile
=
isMobileOrTablet
();
this
.
user
=
this
.
session
.
getLoggedInUser
();
}
// updateCategory(categoryId) {
// this.analyticsService.updateCategory(categoryId);
// }
// detectChanges() {
// this.cd.markForCheck();
// this.cd.detectChanges();
// }
}
This diff is collapsed.
src/app/modules/analytics/v2/components/metrics/metrics.component.html
View file @
f03e30f6
<section
class=
"metricsSection"
[ngClass]=
"{ isMobile: isMobile }"
>
<!-- <div class="overflowFade--left"></div>
<div class="overflowScrollButton--left">
<section
class=
"m-analytics__metricsSection"
>
<div
class=
"m-analytics__metricsWrapper"
#metricsWrapper
>
<div
*ngIf=
"isOverflown && !isAtScrollStart"
class=
"m-analytics__metricsOverflowFade--left"
></div>
<div
[ngClass]=
"{ showButton: showButton.left }"
class=
"m-analytics__metricsOverflowScrollButton--left"
(click)=
"slide('left')"
>
<i
class=
"material-icons"
>
chevron_left
</i>
</div>
<div
#metricsContainer
*ngIf=
"metrics$ | async as metrics"
class=
"m-analytics__metricsContainer disable-scrollbars"
(scroll)=
"onScroll($event)"
>
<ng-container
*ngFor=
"let metric of metrics"
>
<div
class=
"m-analytics__metric"
(click)=
"updateMetric(metric)"
[ngClass]=
"{ active: metric.visualisation }"
*ngIf=
"metric.permissionGranted"
>
<div
class=
"m-analytics__metricLabel"
>
<span>
{{ metric.label }}
</span>
<m-tooltip
[anchor]=
"top"
icon=
"help"
>
{{ metric.description }}
</m-tooltip>
</div>
<div
class=
"m-analytics__metricSummary"
*ngIf=
"metric.summary"
>
<ng-container
*ngIf=
"metric.unit === 'number'"
>
{{ metric.summary.current_value | number }}
</ng-container>
<ng-container
*ngIf=
"metric.unit === 'usd'"
>
<span>
$
</span
>
{{ metric.summary.current_value / 100 | number: '1.2-2' }}
</ng-container>
</div>
<div
*ngIf=
"metric.summary"
class=
"m-analytics__metricDelta"
[ngClass]=
"{
goodChange: metric.hasChanged && metric.positiveTrend,
badChange: metric.hasChanged && !metric.positiveTrend
}"
>
<i
class=
"material-icons"
*ngIf=
"metric.delta > 0"
>
arrow_upward
</i>
<i
class=
"material-icons"
*ngIf=
"metric.delta < 0"
>
arrow_downward
</i
>
<span>
{{ metric.delta | percent: '1.0-1' }}
</span>
</div>
</div>
</ng-container>
</div>
<div
*ngIf=
"isOverflown && !isAtScrollEnd"
class=
"m-analytics__metricsOverflowFade--right"
></div>
<div
[ngClass]=
"{ showButton: showButton.right }"
class=
"m-analytics__metricsOverflowScrollButton--right"
(click)=
"slide('right')"
>
<i
class=
"material-icons"
>
chevron_right
</i>
</div>
</div>
</section>
<!--
<section class="m-analytics__metricsSection">
<div
*ngIf="isOverflown && !isAtScrollStart"
class="m-analytics__metricsOverflowFade--left"
></div>
<div
[ngClass]="{ showButton: showButton.left }"
class="m-analytics__metricsOverflowScrollButton--left"
(click)="slide('left')"
>
<i class="material-icons">chevron_left</i>
</div> -->
<div
class=
"metricsWrapper"
>
<div
class=
"metricsContainer"
*ngIf=
"metrics$ | async as metrics"
>
</div>
<div class="m-analytics__metricsWrapper" #metricsWrapper>
<div
#metricsContainer
*ngIf="metrics$ | async as metrics"
class="m-analytics__metricsContainer disable-scrollbars"
(scroll)="onScroll($event)"
>
<ng-container *ngFor="let metric of metrics">
<div
class=
"metric"
class="m
-analytics__m
etric"
(click)="updateMetric(metric)"
[ngClass]="{ active: metric.visualisation }"
*ngIf="metric.permissionGranted"
>
<div
class=
"metricLabel"
>
<div class="m
-analytics__m
etricLabel">
<span>{{ metric.label }}</span>
<m-tooltip [anchor]="top" icon="help">
{{ metric.description }}
</m-tooltip>
</div>
<div
class=
"metricSummary"
*ngIf=
"metric.summary"
>
<div class="m
-analytics__m
etricSummary" *ngIf="metric.summary">
<ng-container *ngIf="metric.unit === 'number'">
{{ metric.summary.current_value | number }}
</ng-container>
...
...
@@ -30,7 +116,7 @@
<div
*ngIf="metric.summary"
class=
"metricDelta"
class="m
-analytics__m
etricDelta"
[ngClass]="{
goodChange: metric.hasChanged && metric.positiveTrend,
badChange: metric.hasChanged && !metric.positiveTrend
...
...
@@ -46,8 +132,15 @@
</ng-container>
</div>
</div>
<!-- <div class="overflowFade--right"></div>
<div class="overflowScrollButton--right">
<div
*ngIf="isOverflown && !isAtScrollEnd"
class="m-analytics__metricsOverflowFade--right"
></div>
<div
[ngClass]="{ showButton: showButton.right }"
class="m-analytics__metricsOverflowScrollButton--right"
(click)="slide('right')"
>
<i class="material-icons">chevron_right</i>
</div>
-->
</section>
</div>
</section>
-->
This diff is collapsed.
src/app/modules/analytics/v2/components/metrics/metrics.component.scss
View file @
f03e30f6
m-analytics__metrics
{
.metricsSection
{
display
:
block
;
.m-analytics__metricsSection
{
position
:
relative
;
[
class
*=
'
o
verflowFade--'
]
{
[
class
*=
'
m-analytics__metricsO
verflowFade--'
]
{
position
:
absolute
;
top
:
0
;
bottom
:
0
;
width
:
24px
;
z-index
:
1
;
&
.
o
verflowFade--right
{
z-index
:
2
;
&
.
m-analytics__metricsO
verflowFade--right
{
@include
m-theme
()
{
right
:
0
;
background
:
linear-gradient
(
...
...
@@ -18,7 +19,7 @@ m-analytics__metrics {
);
}
}
&
.
o
verflowFade--left
{
&
.
m-analytics__metricsO
verflowFade--left
{
@include
m-theme
()
{
left
:
0
;
background
:
linear-gradient
(
...
...
@@ -30,14 +31,18 @@ m-analytics__metrics {
}
}
[
class
*=
'
o
verflowScrollButton--'
]
{
[
class
*=
'
m-analytics__metricsO
verflowScrollButton--'
]
{
position
:
absolute
;
top
:
50%
;
border-radius
:
50%
;
box-sizing
:
border-box
;
z-index
:
2
;
transform
:
translateY
(
-50%
);
transition
:
all
0
.2s
ease-in
;
opacity
:
0
;
transition
:
all
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
&
.showButton
{
opacity
:
1
;
}
cursor
:
pointer
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
...
...
@@ -49,10 +54,10 @@ m-analytics__metrics {
border
:
1px
solid
themed
(
$m-blue
);
}
}
&
.
o
verflowScrollButton--right
{
&
.
m-analytics__metricsO
verflowScrollButton--right
{
right
:
-12
;
}
&
.
o
verflowScrollButton--left
{
&
.
m-analytics__metricsO
verflowScrollButton--left
{
left
:
-12
;
}
i
{
...
...
@@ -63,40 +68,43 @@ m-analytics__metrics {
}
}
}
.metricsWrapper
{
.m
-analytics__m
etricsWrapper
{
position
:
relative
;
// overflow: hidden;
width
:
100%
;
z-index
:
1
;
@include
m-theme
()
{
box-shadow
:
0
7px
15px
-7px
rgba
(
themed
(
$m-black-always
)
,
0
.1
);
}
}
.metricsContainer
{
scroll-snap-type
:
x
mandatory
;
position
:
relative
;
.m-analytics__metricsContainer
{
overflow-x
:
hidden
;
overflow-y
:
hidden
;
display
:
flex
;
flex-wrap
:
nowrap
;
// overflow-x: auto;
// padding: 0 16px;
transition
:
all
0
.5s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
// &.metricsContainer::-webkit-scrollbar {
// display: none;
// }
&
.disable-scrollbars
{
scrollbar-width
:
none
;
/* Firefox */
-ms-overflow-style
:
none
;
/* IE 10+ */
&
:
:-
webkit-scrollbar
{
width
:
0px
;
background
:
transparent
;
/* Chrome/Safari/Webkit */
}
}
.metric
{
.m
-analytics__m
etric
{
cursor
:
pointer
;
scroll-snap-align
:
start
;
flex
:
0
0
auto
;
width
:
20%
;
width
:
160px
;
padding
:
24px
20px
20px
20px
;
font-size
:
14px
;
box-sizing
:
border-box
;
overflow
:
visible
;
@include
m-theme
()
{
border-bottom
:
8px
solid
themed
(
$m-white
);
}
@include
m-theme
()
{
color
:
themed
(
$m-grey-
2
00
);
color
:
themed
(
$m-grey-
3
00
);
}
&
.active
{
@include
m-theme
()
{
...
...
@@ -105,34 +113,34 @@ m-analytics__metrics {
}
}
&
:first-child
{
margin-left
:
16
px
;
margin-left
:
40
px
;
}
&
:last-child
{
margin-right
:
16
px
;
margin-right
:
40
px
;
}
&
:hover:not
(
.active
)
{
transition
:
background-color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
background-color
:
rgba
(
themed
(
$m-grey-100
)
,
0
.2
);
border-bottom
:
8px
solid
rgba
(
0
,
0
,
0
,
0
);
transition
:
background-color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
}
}
.metricLabel
{
.m
-analytics__m
etricLabel
{
white-space
:
nowrap
;
}
m-tooltip
{
vertical-align
:
middle
;
margin-left
:
4px
;
}
.metricSummary
{
.m
-analytics__m
etricSummary
{
font-size
:
17px
;
margin-top
:
8px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
.metricDelta
{
.m
-analytics__m
etricDelta
{
display
:
flex
;
align-items
:
baseline
;
padding-top
:
4px
;
...
...
@@ -156,12 +164,13 @@ m-analytics__metrics {
i
{
font-size
:
12px
;
@include
m-theme
()
{
color
:
rgba
(
themed
(
$m-grey-
2
00
)
,
0
.7
);
color
:
rgba
(
themed
(
$m-grey-
3
00
)
,
0
.7
);
}
}
.m-tooltip--bubble
{
z-index
:
9999
;
font-size
:
11px
;
width
:
160px
;
@include
m-theme
()
{
color
:
themed
(
$m-white
);
background-color
:
themed
(
$m-blue
);
...
...
@@ -169,10 +178,25 @@ m-analytics__metrics {
}
}
}
.metricsSection.isMobile
{
.metricsContainer
{
.metric
{
flex
:
1
0
auto
;
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-analytics__metricsSection
{
[
class
*=
'm-analytics__metricsOverflowScrollButton--'
]
{
display
:
none
;
}
.m-analytics__metricsContainer
{
overflow-x
:
scroll
;
position
:
relative
;
scroll-snap-type
:
x
mandatory
;
.m-analytics__metric
{
scroll-snap-align
:
start
;
&
:first-child
{
margin-left
:
16px
;
}
&
:last-child
{
margin-right
:
16px
;
}
}
}
}
}
This diff is collapsed.
src/app/modules/analytics/v2/components/metrics/metrics.component.ts
View file @
f03e30f6
import
{
Component
,
OnInit
,
AfterViewInit
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
OnDestroy
,
ViewChild
,
ElementRef
,
HostListener
,
}
from
'
@angular/core
'
;
import
{
Observable
,
Subscription
}
from
'
rxjs
'
;
import
{
Subscription
}
from
'
rxjs
'
;
import
{
map
}
from
'
rxjs/operators
'
;
import
{
AnalyticsDashboardService
,
Category
,
Response
,
Dashboard
,
Filter
,
Option
,
Metric
as
MetricBase
,
Summary
,
Visualisation
,
Bucket
,
Timespan
,
UserState
,
}
from
'
../../dashboard.service
'
;
import
{
Session
}
from
'
../../../../../services/session
'
;
import
isMobileOrTablet
from
'
../../../../../helpers/is-mobile-or-tablet
'
;
interface
MetricExtended
extends
MetricBase
{
delta
:
number
;
...
...
@@ -38,15 +30,24 @@ export { MetricExtended as Metric };
templateUrl
:
'
./metrics.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
AnalyticsMetricsComponent
implements
OnInit
,
OnDestroy
{
export
class
AnalyticsMetricsComponent
implements
OnInit
,
AfterViewInit
{
@
ViewChild
(
'
metricsContainer
'
,
{
static
:
false
})
metricsContainerEl
:
ElementRef
;
metricsContainer
;
data
;
subscription
:
Subscription
;
isMobile
:
boolean
;
user
;
userRoles
:
string
[]
=
[
'
user
'
];
init
=
false
;
metrics$
;
isOverflown
=
{
left
:
false
,
right
:
false
};
metricClientWidth
:
number
;
faderWidth
=
24
;
isOverflown
:
boolean
=
false
;
isAtScrollEnd
=
false
;
isAtScrollStart
=
true
;
showButton
=
{
left
:
false
,
right
:
false
};
constructor
(
private
analyticsService
:
AnalyticsDashboardService
,
...
...
@@ -66,7 +67,6 @@ export class AnalyticsMetricsComponent implements OnInit, OnDestroy {
this
.
metrics$
=
this
.
analyticsService
.
metrics$
.
pipe
(
map
(
_metrics
=>
{
const
metrics
=
_metrics
.
map
(
metric
=>
({
...
metric
}));
// Clone to avoid updating
for
(
const
metric
of
metrics
)
{
metric
[
'
permissionGranted
'
]
=
metric
.
permissions
.
some
(
role
=>
this
.
userRoles
.
includes
(
role
)
...
...
@@ -95,27 +95,89 @@ export class AnalyticsMetricsComponent implements OnInit, OnDestroy {
}
}
}
return
metrics
;
})
);
this
.
isMobile
=
isMobileOrTablet
();
// TODO: if selected metric is not fully visible, slide() until it is
}
ngAfterViewInit
()
{
this
.
checkOverflow
();
}
updateMetric
(
metric
)
{
// TODO: if clicked metric is not fully visible, slide() until it is
this
.
analyticsService
.
updateMetric
(
metric
.
id
);
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
c
d
.
detectChanges
();
@
HostListener
(
'
window:resize
'
)
onResize
()
{
this
.
c
heckOverflow
();
}
ngOnDestroy
(
)
{
// this.subscription.unsubscribe
();
onScroll
(
$event
)
{
this
.
checkOverflow
();
}
checkOverflow
()
{
// element.scrollWidth - element.clientWidth
const
firstMetric
=
document
.
querySelector
(
'
.m-analytics__metric
'
);
this
.
metricClientWidth
=
firstMetric
.
clientWidth
;
this
.
metricsContainer
=
this
.
metricsContainerEl
.
nativeElement
;
this
.
isOverflown
=
this
.
metricsContainer
.
scrollWidth
-
this
.
metricsContainer
.
clientWidth
>
0
;
this
.
isAtScrollStart
=
this
.
metricsContainer
.
scrollLeft
<
this
.
faderWidth
;
this
.
showButton
.
left
=
this
.
isOverflown
&&
!
this
.
isAtScrollStart
;
this
.
isAtScrollEnd
=
!
this
.
isOverflown
||
this
.
metricsContainer
.
scrollWidth
-
(
this
.
metricsContainer
.
scrollLeft
+
this
.
metricsContainer
.
clientWidth
)
<
this
.
faderWidth
;
this
.
showButton
.
right
=
this
.
isOverflown
&&
this
.
metricsContainer
.
scrollLeft
>=
0
&&
!
this
.
isAtScrollEnd
;
this
.
detectChanges
();
}
slide
(
direction
)
{
let
currentScrollLeft
=
this
.
metricsContainer
.
scrollLeft
;
let
targetScrollLeft
;
let
scrollEndOffset
=
0
;
const
partiallyVisibleMetricWidth
=
this
.
metricsContainer
.
clientWidth
%
this
.
metricClientWidth
;
const
completelyVisibleMetricsWidth
=
this
.
metricsContainer
.
clientWidth
-
partiallyVisibleMetricWidth
;
if
(
direction
===
'
right
'
)
{
if
(
currentScrollLeft
<
this
.
faderWidth
)
{
currentScrollLeft
=
this
.
faderWidth
;
}
targetScrollLeft
=
Math
.
min
(
currentScrollLeft
+
completelyVisibleMetricsWidth
,
this
.
metricsContainer
.
scrollWidth
-
completelyVisibleMetricsWidth
);
}
else
{
if
(
this
.
isAtScrollEnd
)
{
scrollEndOffset
=
partiallyVisibleMetricWidth
-
this
.
faderWidth
;
}
targetScrollLeft
=
Math
.
max
(
currentScrollLeft
-
completelyVisibleMetricsWidth
+
scrollEndOffset
,
0
);
}
this
.
metricsContainer
.
scrollTo
({
top
:
0
,
left
:
targetScrollLeft
,
behavior
:
'
smooth
'
,
});
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
This diff is collapsed.
src/app/modules/analytics/v2/components/table/table.component.html
View file @
f03e30f6
<div
class=
"tableWrapper"
[hidden]=
"loading"
[ngClass]=
"{ isMobile: isMobile }"
>
<div
class=
"row--header"
>
<div
*ngFor=
"let col of columns | slice: 0:1"
class=
"col--entity cell"
>
<div
class=
"m-analyticsTable__wrapper"
[hidden]=
"loading"
>
<div
class=
"m-analyticsTable__row--header"
>
<div
*ngFor=
"let col of columns | slice: 0:1"
class=
"m-analyticsTable__col--entity m-analyticsTable__cell"
>
{{ col.label }}
</div>
<div
class=
"col--values"
>
<div
class=
"
m-analyticsTable__
col--values"
>
<ng-container
*ngFor=
"let col of columns | slice: 1"
>
<div
class=
"subCol--value cell"
>
{{ col.label }}
</div>
<div
class=
"m-analyticsTable__subCol--value m-analyticsTable__cell"
>
{{ col.label }}
</div>
</ng-container>
</div>
</div>
<ng-container
*ngFor=
"let row of reformattedBuckets"
>
<a
class=
"row--data"
[routerLink]=
"row.entity.route"
>
<div
class=
"col--entity cell"
*ngIf=
"row.entity"
>
<div
class=
"entityTitle"
>
<span>
{{ row.entity.title }}
</span>
<i
class=
"material-icons"
>
open_in_new
</i>
</div>
<div
class=
"entityDetails"
>
<span
class=
"usernameWrapper"
>
<a
[routerLink]=
"'/' + row.entity.name"
>
@{{ row.entity.username }}
</a
<a
class=
"m-analyticsTable__row--data"
[routerLink]=
"row.entity.route"
>
<div
class=
"m-analyticsTable__col--entity m-analyticsTable__cell"
*ngIf=
"row.entity"
>
<div
class=
"m-analyticsTable__entityWrapper"
>
<div
class=
"m-analyticsTable__entityTitle"
>
<span>
{{ row.entity.title }}
</span>
<i
class=
"material-icons"
>
open_in_new
</i>
</div>
<div
class=
"m-analyticsTable__entityDetails"
>
<span
class=
"m-analyticsTable__usernameWrapper"
>
<a
[routerLink]=
"'/' + row.entity.name"
>
@{{ row.entity.username }}
</a
>
</span>
<span
class=
"m-analyticsTable__entityType"
>
{{
row.entity.type | titlecase
}}
</span>
<span
class=
"m-analyticsTable__entityPublishDate"
>
Published {{ row.entity.time_created * 1000 | date }}
</span
>
</span>
<span
*ngIf=
"!isMobile"
>
{{ row.entity.type | titlecase }}
</span>
<span
*ngIf=
"!isMobile"
>
Published {{ row.entity.time_created * 1000 | date }}
</span
>
</div>
</div>
</div>
<div
class=
"col--values"
>
<div
class=
"
m-analyticsTable__
col--values"
>
<ng-container
*ngFor=
"let value of row.values"
>
<div
class=
"subCol--value cell"
>
{{ value | abbr }}
</div>
<div
class=
"m-analyticsTable__subCol--value m-analyticsTable__cell"
>
{{ value | abbr }}
</div>
</ng-container>
</div>
</a>
...
...
This diff is collapsed.
src/app/modules/analytics/v2/components/table/table.component.scss
View file @
f03e30f6
.tableWrapper
{
// * {
// border: 1px solid salmon;
// }
.m-analyticsTable__wrapper
{
font-size
:
13px
;
font-weight
:
400
;
font-weight
:
300
;
overflow-x
:
scroll
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
a
{
text-decoration
:
none
;
font-weight
:
normal
;
font-weight
:
300
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
[
class
*=
'row'
]
{
display
:
flex
;
}
.m-analyticsTable__cell
{
display
:
flex
;
overflow
:
hidden
;
white-space
:
nowrap
;
height
:
76px
;
}
.m-analyticsTable__subCol--value
{
white-space
:
normal
;
align-items
:
center
;
display
:
flex
;
justify-content
:
center
;
min-width
:
50px
;
}
[
class
*=
'm-analyticsTable__row'
]
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
justify-content
:
space-between
;
transition
:
background-color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
}
// ***********************************************
.m-analyticsTable__row--header
{
@include
m-theme
()
{
border-bottom
:
1px
solid
themed
(
$m-grey-50
);
color
:
themed
(
$m-grey-200
);
}
.m-analyticsTable__col--entity
{
flex-direction
:
row
;
align-items
:
center
;
justify-content
:
space-between
;
transition
:
background-color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
&
.row--header
{
@include
m-theme
()
{
border-bottom
:
1px
solid
themed
(
$m-grey-50
);
color
:
themed
(
$m-grey-200
);
}
.col--entity
{
flex-direction
:
row
;
align-items
:
flex-end
;
}
.col--values
{
.subCol--value.cell
{
align-items
:
flex-end
;
}
}
}
.m-analyticsTable__col--values
{
.m-analyticsTable__subCol--value
{
white-space
:
normal
;
text-align
:
center
;
}
&
.row--data
{
&
:hover
{
@include
m-theme
()
{
background-color
:
rgba
(
themed
(
$m-blue-grey-50
)
,
0
.5
);
}
.col--entity
.entityTitle
i
{
display
:
inline-block
;
}
}
.col--entity
{
@include
m-theme
()
{
border-right
:
1px
solid
themed
(
$m-grey-50
);
}
}
}
}
// .col--entity,
// .col--entity *,
// .col--values,
// .col--values *,
[
class
*=
'col'
],
[
class
*=
'col'
]
*
{
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
// .subCol--value {
// align-items: center;
// }
// ***********************************************
.m-analyticsTable__row--data
{
&
:hover
{
@include
m-theme
()
{
background-color
:
rgba
(
themed
(
$m-blue-grey-50
)
,
0
.5
);
}
.cell
{
.m-analyticsTable__col--entity
.m-analyticsTable__entityTitle
i
{
visibility
:
visible
;
}
}
.m-analyticsTable__col--entity
{
flex-direction
:
row
;
align-items
:
center
;
@include
m-theme
()
{
border-right
:
1px
solid
themed
(
$m-grey-50
);
}
.m-analyticsTable__entityWrapper
{
display
:
flex
;
overflow
:
hidden
;
flex-direction
:
column
;
width
:
87%
;
}
}
[
class
*=
'm-analyticsTable__col'
],
[
class
*=
'm-analyticsTable__col'
]
*
{
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
}
// ***********************************************
.m-analyticsTable__col--values
{
display
:
flex
;
flex-direction
:
row
;
flex-wrap
:
nowrap
;
.m-analyticsTable__subCol--value
{
flex
:
1
1
0
;
align-items
:
center
;
&
:last-of-type
{
padding-right
:
50px
;
}
}
}
// ***********************************************
.m-analyticsTable__col--entity
{
flex-direction
:
column
;
padding-left
:
50px
;
min-width
:
170px
;
.m-analyticsTable__usernameWrapper
a
{
font-weight
:
300
;
text-decoration
:
none
;
}
.m-analyticsTable__entityTitle
{
display
:
flex
;
>
*
{
display
:
inline-block
;
}
span
{
max-width
:
90%
;
}
i
{
font-size
:
12px
;
margin
:
3px
0
0
3px
;
visibility
:
hidden
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
}
.m-analyticsTable__entityDetails
{
display
:
inline
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
>
*
{
margin-right
:
$minds-margin
;
}
.m-analyticsTable__usernameWrapper
{
white-space
:
nowrap
;
height
:
50px
;
padding
:
8px
8px
8px
0
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
a
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
}
}
.col--entity
{
flex-direction
:
column
;
padding-left
:
24px
;
// flex-basis: 20vw;
// ***********************************************
.usernameWrapper
a
{
font-weight
:
400
;
text-decoration
:
none
;
.m-analyticsTable__col--entity
{
flex
:
2
3
0
;
}
.m-analyticsTable__col--values
{
flex
:
2
2
0
;
}
// ***********************************************
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-analyticsTable__wrapper
{
.m-analyticsTable__col--entity
{
flex
:
3
1
0
;
.m-analyticsTable__entityType
,
.m-analyticsTable__entityPublishDate
{
display
:
none
;
}
.entityTitle
{
display
:
flex
;
>
*
{
display
:
inline-block
;
max-width
:
200px
;
}
}
.m-analyticsTable__col--values
{
flex
:
2
2
0
;
i
{
font-size
:
12px
;
margin
:
3px
0
0
3px
;
display
:
none
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
.m-analyticsTable__subCol--value
:last-of-type
{
padding-right
:
16px
;
}
.entityDetails
{
display
:
inline
;
.m-analyticsTable__row--header
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
>
*
{
margin-right
:
$minds-margin
;
border
:
none
!
important
;
}
.usernameWrapper
{
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
a
{
}
.m-analyticsTable__row--data
{
.m-analyticsTable__col--entity
{
padding-left
:
16px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
)
;
border
:
none
!
important
;
}
}
}
}
.col--values
{
display
:
flex
;
flex-direction
:
row
;
flex-wrap
:
nowrap
;
.subCol--value
{
flex
:
1
1
16vw
;
&
:first-of-type
{
padding-left
:
24px
;
}
&
:last-of-type
{
padding-right
:
16px
;
}
.m-analyticsTable__cell
{
height
:
48px
;
}
}
}
}
.col--entity
{
flex
:
2
3
0
;
}
.col--values
{
flex
:
1
2
0
;
}
// MOBILE /////////////////////
.tableWrapper.isMobile
{
.col--entity
{
flex
:
1
3
0
;
}
.col--values
{
flex
:
2
1
0
;
}
.row--header
{
border
:
none
!
important
;
}
.row--data
{
.col--entity.cell
{
border
:
none
!
important
;
@media
screen
and
(
max-width
:
$max-mobile
)
{
.m-analyticsTable__wrapper
{
.m-analyticsTable__col--entity
{
flex
:
2
1
0
;
padding-left
:
24px
;
}
}
}
///////////////////////////@at-root @media screen and (max-width: 800px) {
// @media screen and (max-width: 910px) {
// .m-referrals-dashboard__row.m-referrals-dashboard__headerRow {
// span {
// white-space: normal !important;
// max-width: 35px;
// }
// .m-referrals-dashboard__registerCol,
// .m-referrals-dashboard__rewardsCol {
// align-items: flex-start !important;
// }
// .m-referrals-dashboard__rewardsCol span {
// max-width: 46px;
// }
// }
// .m-referrals-dashboard__cell.m-referrals-dashboard__rewardsCol {
// flex: 2 3 0;
// .m-referrals-dashboard__pingButtonContainer button {
// padding: 8px;
// span {
// display: none;
// }
// }
// }
// }
// .m-referrals-dashboard__cell.m-referrals-dashboard__registerCol {
// display: none;
// }
// .m-referrals-dashboard__userCol {
// min-width: 100px;
// }
// .m-referrals-dashboard__statusCol {
// min-width: 60px;
// }
// .m-referrals-dashboard__rewardsCol {
// max-width: 75px;
// }
// }
This diff is collapsed.
src/app/modules/analytics/v2/components/table/table.component.ts
View file @
f03e30f6
...
...
@@ -13,7 +13,6 @@ import {
AnalyticsDashboardService
,
Visualisation
,
}
from
'
../../dashboard.service
'
;
import
isMobileOrTablet
from
'
../../../../../helpers/is-mobile-or-tablet
'
;
@
Component
({
selector
:
'
m-analytics__table
'
,
...
...
@@ -28,7 +27,6 @@ export class AnalyticsTableComponent implements OnInit, OnDestroy {
reformattedBuckets
:
Array
<
any
>
=
[];
minds
=
window
.
Minds
;
user
;
isMobile
:
boolean
;
loadingSubscription
:
Subscription
;
loading
:
boolean
;
valueColCount
:
number
=
1
;
...
...
@@ -39,14 +37,12 @@ export class AnalyticsTableComponent implements OnInit, OnDestroy {
})
);
selectedMetric
;
constructor
(
private
analyticsService
:
AnalyticsDashboardService
,
protected
cd
:
ChangeDetectorRef
// public session: Session
protected
cd
:
ChangeDetectorRef
)
{}
ngOnInit
()
{
this
.
isMobile
=
isMobileOrTablet
();
this
.
metricSubscription
=
this
.
selectedMetric$
.
subscribe
(
metric
=>
{
this
.
selectedMetric
=
metric
;
this
.
visualisation
=
metric
.
visualisation
;
...
...
@@ -71,7 +67,9 @@ export class AnalyticsTableComponent implements OnInit, OnDestroy {
const
reformattedBucket
=
{};
const
reformattedValues
=
[];
if
(
!
bucket
.
values
[
'
entity
'
])
return
;
if
(
!
bucket
.
values
[
'
entity
'
])
{
return
;
}
this
.
columns
.
forEach
((
column
,
i
)
=>
{
if
(
i
===
0
)
{
...
...
This diff is collapsed.
src/app/modules/analytics/v2/dashboard.component.html
View file @
f03e30f6
<div
class=
"page"
[ngClass]=
"{ isMobile: isMobile }"
>
<m-analytics
__menu
></m-analytics
__menu
>
<section
class=
"main"
*ngIf=
"ready$ | async"
[ngClass]=
"{ isMobile: isMobile }"
>
<!-- <section class="main" [ngClass]="{ isMobile: isMobile }"> -->
<div
class=
"mainHeader"
>
<div
class=
"dashboardTitle"
>
<h3
class=
"selectedCatLabel"
>
<div
class=
"m-analytics__dashboard"
>
<m-sidebarMenu></m-sidebarMenu>
<section
class=
"m-analytics__main"
*ngIf=
"ready$ | async"
>
<div
class=
"m-analytics__mainHeader"
>
<div
class=
"m-analytics__dashboardTitle"
>
<h3
class=
"m-analytics__selectedCatLabel"
>
{{ category$ | async | titlecase }}
</h3>
<p
class=
"selectedCatDescription"
*ngIf=
"description$ | async as description"
>
{{ description }}
<ng-container
*ngIf=
"(category$ | async) === 'earnings'"
>
<a
*ngIf=
"!session.getLoggedInUser().pro"
routerLink=
"/pro"
>
Upgrade to PRO
</a
>
<a
*ngIf=
"
session.getLoggedInUser().pro &&
!(
session.getLoggedInUser().merchant &&
session.getLoggedInUser().merchant['id']
)
"
routerLink=
"/wallet/usd"
>
Enable payouts
</a
>
.
</ng-container>
</p>
</div>
<div
class=
"globalFilters"
>
<!-- <div *ngIf="session.isAdmin()" class="channelSearch"> -->
<!-- <div class="channelSearch">
<div
class=
"
m-analytics__
globalFilters"
>
<!-- <div *ngIf="session.isAdmin()" class="
m-analytics__
channelSearch"> -->
<!-- <div class="
m-analytics__
channelSearch">
<m-analytics__search></m-analytics__search>
</div> -->
<
div
class=
"
channelFilter"
*ngIf=
"session.isAdmin()"
>
<
!-- <div class="m-analytics__
channelFilter" *ngIf="session.isAdmin()">
<m-analytics__filter [filter]="channelFilter"></m-analytics__filter>
</div>
<div
class=
"timespanFilter"
>
<m-analytics
__filter
[filter]=
"timespanFilter"
></m-analytics
__filter
>
</div> -->
<div
class=
"m-analytics__timespanFilter"
>
<m-analytics
__filter
[filter]=
"timespanFilter"
[showLabel]=
"false"
></m-analytics
__filter
>
</div>
</div>
</div>
<div
class=
"layoutWrapper"
>
<p
class=
"m-analytics__selectedCatDescription"
*ngIf=
"description$ | async as description"
>
{{ description }}
<ng-container
*ngIf=
"(category$ | async) === 'earnings'"
>
<a
*ngIf=
"!session.getLoggedInUser().pro"
routerLink=
"/pro"
>
Upgrade to PRO
</a
>
<a
*ngIf=
"
session.getLoggedInUser().pro &&
!(
session.getLoggedInUser().merchant &&
session.getLoggedInUser().merchant['id']
)
"
routerLink=
"/wallet/usd"
>
Enable payouts
</a
>
.
</ng-container>
</p>
<div
class=
"m-analytics__layoutWrapper"
>
<m-analytics
__layout--chart
class=
"m-analytics__layout"
></m-analytics
__layout--chart
>
<!-- <m-analytics__layout--table
class="m-analytics__layout"
*ngIf="(category$ | async).type === 'table'"
></m-analytics__layout--table>
<m-analytics__layout--summary
<!-- <m-analytics__layout--summary
class="m-analytics__layout"
*ngIf="(category$ | async).type === 'summary'"
></m-analytics__layout--summary> -->
...
...
This diff is collapsed.
src/app/modules/analytics/v2/dashboard.component.scss
View file @
f03e30f6
m-analytics__dashboard
{
display
:
block
;
position
:
relative
;
width
:
100%
;
}
// ----------------------------------------
// MOBILE
.isMobile
{
&
.page
{
padding
:
0
;
.main
{
padding
:
0
;
.mainHeader
{
padding-left
:
24px
;
display
:
block
;
}
.layoutWrapper
{
box-shadow
:
none
;
padding
:
0
;
}
}
}
.m-analytics__menu
{
padding
:
0
8px
;
}
}
// ----------------------------------------
.page
{
.m-analytics__dashboard
{
padding
:
16px
;
display
:
flex
;
box-sizing
:
border-box
;
flex-direction
:
row
;
height
:
100%
;
// display: flex;
// box-sizing: border-box;
// flex-direction: row;
width
:
100%
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
...
...
@@ -42,41 +18,44 @@ m-analytics__dashboard {
h3
{
font-size
:
26px
;
font-weight
:
500
;
margin
:
24px
16px
24px
0
;
}
}
.main
{
flex
:
4
1
0px
;
padding
:
16px
;
m-sidebarMenu
{
display
:
inline-block
;
vertical-align
:
top
;
width
:
29%
;
}
.mainHeader
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
flex-start
;
.m-analytics__main
{
display
:
inline-block
;
width
:
65%
;
// flex: 4 1 0px;
padding
:
16px
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
}
}
.m-analytics__mainHeader
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
flex-start
;
// h3 {
// line-height: 0;
// margin-top: 40px;
// }
p
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
a
{
@include
m-theme
()
{
color
:
themed
(
$m-blue
);
}
text-decoration
:
none
;
m-analytics__filter
{
margin
:
0
;
.m-analyticsFilter__wrapper
{
>
*
{
width
:
180px
;
}
}
}
.globalFilters
{
.
m-analytics__
globalFilters
{
margin
:
24px
0
;
display
:
flex
;
align-items
:
baseline
;
.channelSearch
{
// border-radius: 5px;
.m-analytics__channelSearch
{
margin-right
:
8px
;
@include
m-theme
()
{
border
:
themed
(
$m-grey-50
);
...
...
@@ -84,46 +63,93 @@ m-analytics__dashboard {
}
}
m-analytics__filter
{
display
:
table
;
}
.timespanFilter
{
.filterWrapper
{
.m-analytics__timespanFilter
{
.m-analytics__filterWrapper
{
margin-top
:
0px
;
}
.filterLabel
{
.
m-analytics__
filterLabel
{
display
:
none
;
}
}
}
.layoutWrapper
{
}
.m-analytics__selectedCatDescription
{
margin
:
8px
16px
32px
0
;
font-weight
:
400
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
a
{
font-weight
:
400
;
text-decoration
:
none
;
@include
m-theme
()
{
box-shadow
:
0px
0px
10px
-3px
rgba
(
themed
(
$m-black-always
)
,
0
.3
);
color
:
themed
(
$m-blue
);
}
}
.m-analytics__layout
{
position
:
relative
;
display
:
block
;
width
:
100%
;
}
.m-analytics__layoutWrapper
{
@include
m-theme
()
{
box-shadow
:
0px
0px
10px
-3px
rgba
(
themed
(
$m-black-always
)
,
0
.3
);
}
}
// *************************************
.m-analytics__layout
{
position
:
relative
;
display
:
block
;
width
:
100%
;
}
// @media screen and (max-width: $min-tablet) {
@media
screen
and
(
max-width
:
300px
)
{
.page
{
flex-direction
:
column
;
.sidebar
{
.catContainer
{
@include
m-theme
()
{
background-color
:
themed
(
$m-grey-200
);
color
:
themed
(
$m-white
);
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-analytics__dashboard
{
.m-analytics__dashboard
{
display
:
block
;
padding
:
0
;
// flex-direction: column;
.m-analytics__main
{
padding
:
0
;
max-width
:
none
;
width
:
100%
;
.m-analytics__mainHeader
{
padding-left
:
24px
;
m-analytics__filter
{
margin
:
0
32px
8px
0
;
.m-analyticsFilter__wrapper
{
>
*
{
width
:
160px
;
}
}
}
}
.m-analytics__selectedCatDescription
{
margin
:
0
24px
24px
24px
;
}
.m-analytics__layoutWrapper
{
padding
:
0
;
@include
m-theme
()
{
box-shadow
:
none
;
}
}
}
}
}
}
// :(
@media
screen
and
(
max-width
:
$max-mobile
)
{
m-analytics__dashboard
{
.m-analytics__dashboard
{
.m-analytics__main
{
.m-analytics__mainHeader
{
m-analytics__filter
{
.m-analyticsFilter__wrapper
{
>
*
{
width
:
140px
;
}
}
}
}
}
}
}
}
This diff is collapsed.
src/app/modules/analytics/v2/dashboard.component.ts
View file @
f03e30f6
...
...
@@ -17,9 +17,6 @@ import { Session } from '../../../services/session';
import
{
AnalyticsDashboardService
}
from
'
./dashboard.service
'
;
import
{
Filter
}
from
'
./../../../interfaces/dashboard
'
;
// import categories from './categories.default';
import
isMobileOrTablet
from
'
../../../helpers/is-mobile-or-tablet
'
;
@
Component
({
selector
:
'
m-analytics__dashboard
'
,
templateUrl
:
'
./dashboard.component.html
'
,
...
...
@@ -27,9 +24,6 @@ import isMobileOrTablet from '../../../helpers/is-mobile-or-tablet';
providers
:
[
AnalyticsDashboardService
],
})
export
class
AnalyticsDashboardComponent
implements
OnInit
,
OnDestroy
{
isMobile
:
boolean
;
// subscription: Subscription;
paramsSubscription
:
Subscription
;
ready$
=
this
.
analyticsService
.
ready$
;
...
...
@@ -56,12 +50,10 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
)
{}
ngOnInit
()
{
// TODO: why wasn't this working? didn't reroute
if
(
!
this
.
session
.
isLoggedIn
())
{
this
.
router
.
navigate
([
'
/login
'
]);
return
;
}
this
.
isMobile
=
isMobileOrTablet
();
this
.
title
.
setTitle
(
'
Analytics
'
);
...
...
@@ -105,8 +97,7 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
}
updateTimespan
(
timespanId
)
{
// TODO
// update url
// TODO: update url
// this.analyticsService.updateTimespan(timespanId);
}
...
...
@@ -120,6 +111,8 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
}
ngOnDestroy
()
{
if
(
this
.
paramsSubscription
)
this
.
paramsSubscription
.
unsubscribe
();
if
(
this
.
paramsSubscription
)
{
this
.
paramsSubscription
.
unsubscribe
();
}
}
}
This diff is collapsed.
src/app/modules/analytics/v2/dashboard.service.ts
View file @
f03e30f6
...
...
@@ -45,6 +45,7 @@ export interface Filter {
label
:
string
;
options
:
Option
[];
description
:
string
;
expanded
?:
boolean
;
}
export
interface
Option
{
...
...
@@ -118,14 +119,8 @@ let _state: UserState = fakeData[0];
const
deepDiff
=
(
prev
,
curr
)
=>
JSON
.
stringify
(
prev
)
===
JSON
.
stringify
(
curr
);
// **********************************************************************
// **********************************************************************
@
Injectable
()
export
class
AnalyticsDashboardService
{
/**
* Initialize the state subject and make it an observable
*/
private
store
=
new
BehaviorSubject
<
UserState
>
(
_state
);
private
state$
=
this
.
store
.
asObservable
();
...
...
@@ -282,8 +277,8 @@ export class AnalyticsDashboardService {
}
else
{
filter
.
push
(
selectedFilterStr
);
}
console
.
log
(
'
update filter called:
'
+
selectedFilterStr
);
console
.
log
(
filter
);
//
console.log('update filter called: ' + selectedFilterStr);
//
console.log(filter);
this
.
updateState
({
...
_state
,
filter
});
}
...
...
@@ -292,7 +287,7 @@ export class AnalyticsDashboardService {
/** Update internal state cache and emit from store... */
private
updateState
(
state
:
UserState
)
{
console
.
log
(
'
update state called
'
);
//
console.log('update state called');
this
.
store
.
next
((
_state
=
state
));
}
...
...
@@ -315,8 +310,4 @@ export class AnalyticsDashboardService {
map
(
response
=>
response
)
);
}
getData
()
{
console
.
warn
(
'
call was made to legacy function DashboardService.getData()
'
);
}
}
This diff is collapsed.
src/app/modules/analytics/v2/fake-data.ts
View file @
f03e30f6
...
...
@@ -3,22 +3,21 @@ const fakeData: Array<any> = [
// CHART TESTS
loading
:
false
,
category
:
'
traffic
'
,
description
:
'
imma traffic description
'
,
timespan
:
'
30d
'
,
timespans
:
[
{
id
:
'
30d
'
,
label
:
'
Last 30 days
'
,
interval
:
'
day
'
,
comparison_interval
:
28
,
comparison_interval
:
30
,
from_ts_ms
:
1567296000000
,
from_ts_iso
:
'
2019-09-01T00:00:00+00:00
'
,
selected
:
tru
e
,
selected
:
fals
e
,
},
{
id
:
'
1
y
'
,
label
:
'
1 year ago
'
,
interval
:
'
month
'
,
id
:
'
1
2m
'
,
label
:
'
Last 12 months
'
,
interval
:
'
day
'
,
comparison_interval
:
365
,
from_ts_ms
:
1538352000000
,
from_ts_iso
:
'
2018-10-01T00:00:00+00:00
'
,
...
...
@@ -117,10 +116,25 @@ const fakeData: Array<any> = [
'
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentiuti atque corrupti quos dolores
'
,
visualisation
:
null
,
},
{
id
:
'
active_users
'
,
label
:
'
Active UsersA
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
summary
:
{
current_value
:
120962
,
comparison_value
:
120962
,
comparison_interval
:
28
,
comparison_positive_inclination
:
true
,
},
unit
:
'
number
'
,
description
:
'
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentiuti atque corrupti quos dolores
'
,
visualisation
:
null
,
},
{
id
:
'
signups
'
,
label
:
'
Signups
'
,
permissions
:
[
'
admin
'
],
permissions
:
[
'
admin
'
,
'
user
'
],
summary
:
{
current_value
:
53060
,
comparison_value
:
60577
,
...
...
@@ -173,7 +187,7 @@ const fakeData: Array<any> = [
{
key
:
1567641600000
,
date
:
'
2019-09-05T00:00:00+00:00
'
,
value
:
5
,
value
:
1
,
},
{
key
:
1567296000000
,
...
...
@@ -345,7 +359,7 @@ const fakeData: Array<any> = [
{
id
:
'
all
'
,
label
:
'
All
'
,
available
:
true
,
selected
:
false
},
{
id
:
'
browser
'
,
label
:
'
Browser
'
,
label
:
'
Browser
BrowserBrowserBrowserBrowserBrowser
'
,
available
:
true
,
selected
:
false
,
},
...
...
@@ -498,7 +512,7 @@ const fakeData: Array<any> = [
],
columns
:
[
{
id
:
'
entity
'
,
label
:
'
Views
'
},
{
id
:
'
views::total
'
,
label
:
'
Total
'
},
{
id
:
'
views::total
'
,
label
:
'
Total
Views
'
},
{
id
:
'
views::organic
'
,
label
:
'
Organic
'
},
{
id
:
'
views::single
'
,
label
:
'
Single
'
},
],
...
...
This diff is collapsed.
src/app/modules/analytics/v2/layouts/layout-chart/layout-chart.component.html
View file @
f03e30f6
<div
class=
"spinnerContainer"
*ngIf=
"loading$ | async"
>
<div
class=
"
m-analytics__
spinnerContainer"
*ngIf=
"loading$ | async"
>
<div
class=
"mdl-spinner mdl-js-spinner is-active"
[
mdl
]
></div>
</div>
<ng-container
*ngIf=
"selectedMetric && selectedMetric.visualisation"
>
...
...
@@ -6,7 +6,7 @@
*ngIf=
"selectedMetric.visualisation.type === 'chart'"
></m-analytics
__metrics
>
<div
class=
"filterableChartWrapper"
class=
"
m-analytics__
filterableChartWrapper"
[ngClass]=
"{ isTable: isTable, isMobile: isMobile }"
>
<m-analytics
__chart
...
...
This diff is collapsed.
src/app/modules/analytics/v2/layouts/layout-chart/layout-chart.component.scss
View file @
f03e30f6
.filterableChartWrapper
{
.
m-analytics__
filterableChartWrapper
{
position
:
relative
;
padding
:
16px
;
// width: 80%;
margin-bottom
:
48px
;
@include
m-theme
()
{
border-top
:
1px
solid
themed
(
$m-grey-50
);
border-top
:
1px
solid
rgba
(
themed
(
$m-grey-50
)
,
0
.5
);
background-color
:
themed
(
$m-white
);
}
&
.isTable
{
padding
:
0
;
width
:
100%
;
}
&
.isMobile
{
border-top
:
none
;
min-width
:
420px
;
}
}
.spinnerContainer
{
.
m-analytics__
spinnerContainer
{
height
:
30%
;
width
:
100%
;
display
:
flex
;
...
...
This diff is collapsed.
src/app/modules/analytics/v2/layouts/layout-chart/layout-chart.component.ts
View file @
f03e30f6
...
...
@@ -3,18 +3,18 @@ import {
OnInit
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
OnDestroy
,
}
from
'
@angular/core
'
;
import
{
Observable
,
Subscription
,
combineLatest
}
from
'
rxjs
'
;
import
{
map
}
from
'
rxjs/operators
'
;
import
{
AnalyticsDashboardService
}
from
'
../../dashboard.service
'
;
import
isMobileOrTablet
from
'
../../../../../helpers/is-mobile-or-tablet
'
;
@
Component
({
selector
:
'
m-analytics__layout--chart
'
,
templateUrl
:
'
./layout-chart.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
AnalyticsLayoutChartComponent
implements
OnInit
{
export
class
AnalyticsLayoutChartComponent
implements
OnInit
,
OnDestroy
{
subscription
:
Subscription
;
loading$
=
this
.
analyticsService
.
loading$
;
selectedMetric$
=
combineLatest
(
...
...
@@ -28,7 +28,6 @@ export class AnalyticsLayoutChartComponent implements OnInit {
);
selectedMetric
;
isTable
:
boolean
=
false
;
isMobile
:
boolean
;
constructor
(
private
analyticsService
:
AnalyticsDashboardService
,
...
...
@@ -37,7 +36,6 @@ export class AnalyticsLayoutChartComponent implements OnInit {
ngOnInit
()
{
this
.
subscription
=
this
.
selectedMetric$
.
subscribe
(
metric
=>
{
console
.
log
(
'
new metric
'
);
this
.
selectedMetric
=
metric
;
this
.
isTable
=
...
...
@@ -46,7 +44,6 @@ export class AnalyticsLayoutChartComponent implements OnInit {
this
.
selectedMetric
.
visualisation
.
type
===
'
table
'
;
this
.
detectChanges
();
});
this
.
isMobile
=
isMobileOrTablet
();
}
detectChanges
()
{
...
...
This diff is collapsed.
src/app/modules/analytics/v2/layouts/layout-table/layout-table.component.html
deleted
100644 → 0
View file @
409ccf04
<p>
analytics__layout--table works!
</p>
This diff is collapsed.