Skip to content
Commits on Source (64)
......@@ -39,3 +39,4 @@ cypress/videos
!/.gitlab
!/.githooks
!/.prettierrc
!.gitattributes
image: markharding/minds-front-base
services:
- docker:dind
stages:
- test
- build
......@@ -154,6 +151,8 @@ build:production:i18n:
prepare:review:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
......@@ -179,6 +178,8 @@ prepare:review:sentry:
prepare:production:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
......@@ -261,6 +262,8 @@ review:stop:
.deploy: &deploy
image: minds/ci:latest
services:
- docker:dind
script:
## Sync assets with CDN
- aws s3 sync dist $S3_REPOSITORY_URL
......
......@@ -6,7 +6,7 @@ Minds Front
Front-end web application for Minds. Please run inside of [the Minds repo](https://github.com/minds/minds).
## Documentation
Documentation for Minds can be found at [minds.org/docs](https://www.minds.org/docs)
Please see the documentation on [developers.minds.com](https://developers.minds.com) for instructions on how to [build the Minds Front-end](https://developers.minds.com/docs/guides/frontend).
### Building
Please see the documentation on Minds.org for instructions on how to [build the Minds Front-end](https://www.minds.org/docs/install/preparation.html#front-end).
......
context('Rewards Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const joinRewards = '.m-marketing__mainWrapper .mf-button';
it('should have a join rewards button', () => {
cy.visit('/rewards');
cy.get(joinRewards)
.should('be.visible')
.should('contain', 'Join Rewards')
.click();
cy.location('pathname').should(
'contains',
'/wallet/tokens/contributions'
);
});
});
context('Token Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
cy.visit('/token');
});
it('should have the ability to trigger Buy Tokens modal', () => {
const tokensInput = 'm-blockchain--purchase input[name=amount]';
const buyTokensButton =
'm-blockchain--purchase .m-blockchainTokenPurchase__action .mf-button';
const anyBuyTokensModal =
'm-blockchain--purchase m-modal .m-modal-container';
cy.get(tokensInput)
.focus()
.clear()
.type('0');
cy.get(buyTokensButton).should('be.disabled');
cy.get(tokensInput)
.focus()
.clear()
.type('1');
cy.get(buyTokensButton)
.should('not.be.disabled')
.click();
cy.get('.m-get-metamask--cancel-btn.m-btn').click();
cy.get(anyBuyTokensModal).should('be.visible');
});
it('should have the ability to trigger Buy Eth modal', () => {
const buyEthLink =
'm-blockchain--purchase .m-blockchainTokenPurchase__ethRate a';
const buyEthModal = 'm-blockchain__eth-modal .m-modal-container';
cy.get(buyEthLink).click();
cy.get(buyEthModal).should('be.visible');
});
});
context('Boost Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const createBoostButton = '.m-marketing__mainWrapper .mf-button';
it('should have a create boost button', () => {
cy.visit('/boost');
cy.get(createBoostButton)
.should('be.visible')
.should('contain', 'Create Boost')
.click();
cy.location('pathname').should(
'contains',
'/boost/console/newsfeed/create'
);
});
});
import generateRandomId from '../support/utilities';
context('Newsfeed', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
......@@ -14,7 +16,6 @@ context('Newsfeed', () => {
cy.route('POST', '**/api/v1/media').as('mediaPOST');
cy.route('POST', '**/api/v1/newsfeed/**').as('newsfeedEDIT');
cy.route('POST', '**/api/v1/media/**').as('mediaEDIT');
cy.visit('/newsfeed/subscriptions')
.location('pathname')
.should('eq', '/newsfeed/subscriptions');
......@@ -37,6 +38,19 @@ context('Newsfeed', () => {
cy.get('minds-newsfeed-poster textarea').type(content);
};
const attachRichEmbed = (embedUrl) => {
cy.get('minds-newsfeed-poster').should('be.visible');
cy.get('minds-newsfeed-poster textarea')
.type(embedUrl);
cy.route('GET', `**/api/v1/newsfeed/preview?url=${embedUrl}**`)
.as('previewGET')
.wait('@previewGET')
.then(xhr => {
expect(xhr.status).to.equal(200);
});
}
const attachImageToActivity = () => {
cy.uploadFile(
'#attachment-input-poster',
......@@ -511,4 +525,140 @@ context('Newsfeed', () => {
deleteActivityFromNewsfeed();
});
it('should show a rich embed post from youtube in a modal', () => {
const content = generateRandomId() + " ",
url = 'https://www.youtube.com/watch?v=jNQXAC9IVRw';
// set up post.
newActivityContent(content);
attachRichEmbed(url);
// post and await.
cy.get('.m-posterActionBar__PostButton')
.click()
.wait('@newsfeedPOST').then(xhr => {
expect(xhr.status).to.equal(200);
//get activity, click it.
cy.get(`[minds-data-activity-guid='${xhr.response.body.guid}']`)
.click();
//check modal is open.
cy.get('[data-cy=data-minds-media-modal]')
.contains(content);
// close modal and tidy.
cy.get('.m-overlay-modal--backdrop')
.click({force: true});
deleteActivityFromNewsfeed();
});
});
it('should not open vimeo in a modal', () => {
const content = generateRandomId() + " ",
url = 'https://vimeo.com/8733915';
// set up post.
newActivityContent(content);
attachRichEmbed(url);
// post and await.
cy.get('.m-posterActionBar__PostButton')
.click()
.wait('@newsfeedPOST').then(xhr => {
expect(xhr.status).to.equal(200);
//get activity, make assertions tht would not be true for modals.
cy.get(`[minds-data-activity-guid='${xhr.response.body.guid}']`)
.should('be.visible')
.get('iframe')
.should('be.visible')
.get('.minds-more')
.should('be.visible');
// tidy.
deleteActivityFromNewsfeed();
});
});
it('should not open soundcloud in a modal', () => {
const content = generateRandomId() + " ",
url = 'https://soundcloud.com/richarddjames/piano-un10-it-happened';
// set up post.
newActivityContent(content);
attachRichEmbed(url);
// post and await.
cy.get('.m-posterActionBar__PostButton')
.click()
.wait('@newsfeedPOST').then(xhr => {
expect(xhr.status).to.equal(200);
//get activity, make assertions tht would not be true for modals.
cy.get(`[minds-data-activity-guid='${xhr.response.body.guid}']`)
.should('be.visible')
.get('.m-rich-embed-action-overlay')
.should('be.visible')
.get('.minds-more')
.should('be.visible');
deleteActivityFromNewsfeed();
});
});
it('should not open spotify in a modal', () => {
const content = generateRandomId() + " ",
url = 'https://open.spotify.com/track/2MZSXhq4XDJWu6coGoXX1V?si=nvja0EfwR3q6GMQmYg6gPQ';
// set up post.
newActivityContent(content);
attachRichEmbed(url);
// post and await.
cy.get('.m-posterActionBar__PostButton')
.click()
.wait('@newsfeedPOST').then(xhr => {
expect(xhr.status).to.equal(200);
//get activity, make assertions tht would not be true for modals.
cy.get(`[minds-data-activity-guid='${xhr.response.body.guid}']`)
.should('be.visible')
.get('.m-rich-embed-action-overlay')
.should('be.visible')
.get('.minds-more')
.should('be.visible');
deleteActivityFromNewsfeed();
});
});
it('should not open spotify in a modal', () => {
const content = generateRandomId() + " ",
url = 'http://giphygifs.s3.amazonaws.com/media/IzVquL965ib4s/giphy.gif';
// set up post.
newActivityContent(content);
attachRichEmbed(url);
// post and await.
cy.get('.m-posterActionBar__PostButton')
.click()
.wait('@newsfeedPOST').then(xhr => {
expect(xhr.status).to.equal(200);
//get activity, make assertions tht would not be true for modals.
cy.get(`[minds-data-activity-guid='${xhr.response.body.guid}']`)
.should('be.visible')
.get('.m-rich-embed-action-overlay')
.should('be.visible')
.get('.minds-more')
.should('be.visible');
deleteActivityFromNewsfeed();
});
});
});
context('Pro Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const contactUsButton = '.m-marketing__mainWrapper .mf-button';
it('should have a contact us button', () => {
cy.visit('/nodes', {
onBeforeLoad(_window) {
cy.stub(_window, 'open');
},
});
cy.get(contactUsButton)
.should('be.visible')
.should('contain', 'Contact us for details')
.click();
cy.window()
.its('open')
.should('be.called');
});
});
context('Plus Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const upgradeButton = 'm-plus--subscription .mf-button';
const wirePaymentsComponent = 'm-wire__paymentscreator .m-wire--creator';
it('should open the Wire Payment modal', () => {
cy.visit('/plus');
cy.get(upgradeButton)
.should('be.visible')
.should('contain', 'Upgrade to Plus')
.click();
cy.get(wirePaymentsComponent).should('be.visible');
});
it('should automatically open the Wire Payment modal', () => {
cy.visit('/plus?i=yearly&c=tokens');
cy.get(wirePaymentsComponent).should('be.visible');
});
});
context('Pro Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const upgradeButton = 'm-pro--subscription .mf-button';
const wirePaymentsComponent = 'm-wire__paymentscreator .m-wire--creator';
it('should show a coming soon button', () => {
cy.visit('/pro');
cy.get(upgradeButton)
.should('be.visible')
.should('contain', 'Coming soon')
.click();
});
// it('should open the Wire Payment modal', () => {
//
// cy.visit('/pro');
//
// cy.get(upgradeButton)
// .should('be.visible')
// .should('contain', 'Upgrade to Pro')
// .click();
//
// cy.get(wirePaymentsComponent).should('be.visible');
// });
//
// it('should automatically open the Wire Payment modal', () => {
// cy.visit('/pro?i=yearly&c=tokens');
//
// cy.get(wirePaymentsComponent).should('be.visible');
// });
});
......@@ -21,7 +21,6 @@ context('Pro Settings', () => {
43: '#tile_ratio_4\:3', // 4:3
11: '#tile_ratio_1\:1' , // 1:1
},
logoGuid: '#logo_guid',
}
const hashtags = {
......
context('Upgrades page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
cy.visit('/upgrades');
});
it('should scroll to upgrades table', () => {
cy.viewport(1200, 600); // Only on desktop
const scrollButton = '[data-cy="m-upgrades__upgrade-now-button"]';
const heading = '.m-upgradesUpgradeOptions__header h2';
cy.get(scrollButton)
.should('contain', 'Upgrade now')
.click();
cy.wait(1500);
cy.isInViewport(heading);
});
// TODO: Toggles tests (make them testable)
it('should have the ability to trigger Buy Tokens modal', () => {
const tokensInput = 'm-blockchain--purchase input[name=amount]';
const buyTokensButton =
'm-blockchain--purchase .m-blockchainTokenPurchase__action .mf-button';
const anyBuyTokensModal =
'm-blockchain--purchase m-modal .m-modal-container';
cy.get(tokensInput)
.focus()
.clear()
.type('0');
cy.get(buyTokensButton).should('be.disabled');
cy.get(tokensInput)
.focus()
.clear()
.type('1');
cy.get(buyTokensButton)
.should('not.be.disabled')
.click();
cy.get('.m-get-metamask--cancel-btn.m-btn').click();
cy.get(anyBuyTokensModal).should('be.visible');
});
it('should have the ability to trigger Buy Eth modal', () => {
const buyEthLink =
'm-blockchain--purchase .m-blockchainTokenPurchase__ethRate a';
const buyEthModal = 'm-blockchain__eth-modal .m-modal-container';
cy.get(buyEthLink).click();
cy.get(buyEthModal).should('be.visible');
});
it('should navigate to Plus and trigger a Wire', () => {
const upgradeButton = cy.get(
'[data-cy="m-upgradeOptions__upgrade-to-plus-button"]'
);
upgradeButton.click();
cy.location('pathname').should('contain', '/plus');
});
it('should navigate to Pro and trigger a Wire', () => {
const upgradeButton = cy.get(
'[data-cy="m-upgradeOptions__upgrade-to-pro-button"]'
);
upgradeButton.click();
cy.location('pathname').should('contain', '/pro');
});
it('should navigate to Nodes', () => {
const upgradeButton = cy.get(
'[data-cy="m-upgradeOptions__contact-us-nodes-button"]'
);
upgradeButton.click();
cy.location('pathname').should('contain', '/nodes');
});
});
......@@ -5,10 +5,10 @@
* @desc Spec tests for Wire transactions.
*/
import generateRandomId from "../support/utilities";
import generateRandomId from "../../support/utilities";
// Issue to re-enable https://gitlab.com/minds/front/issues/1846
context.skip('Wire', () => {
context.skip('Wire Creator', () => {
const receiver = {
username: generateRandomId(),
......
context('Pay Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const monetizeChannelButton = '.m-marketing__mainWrapper .mf-button';
it('should have a monetize channel button', () => {
cy.visit('/pay');
cy.get(monetizeChannelButton)
.should('be.visible')
.should('contain', 'Monetize your channel')
.click();
cy.location('pathname').should(
'contains',
'/wallet/tokens/contributions'
);
});
});
......@@ -255,3 +255,36 @@ function b64toBlob(b64Data, contentType, sliceSize = 512) {
blob.lastModifiedDate = new Date();
return blob;
}
/**
* Check if certain element is on viewport
* @param {*} element
*/
Cypress.Commands.add('isInViewport', element => {
cy.get(element).then($el => {
const bottom = Cypress.$(cy.state('window')).height();
const rect = $el[0].getBoundingClientRect();
expect(rect.top).not.to.be.greaterThan(bottom);
expect(rect.bottom).not.to.be.greaterThan(bottom);
expect(rect.top).not.to.be.greaterThan(bottom);
expect(rect.bottom).not.to.be.greaterThan(bottom);
})
});
/**
* Check if certain element is on viewport
* @param {*} element
*/
Cypress.Commands.add('isNotInViewport', element => {
cy.get(element).then($el => {
const bottom = Cypress.$(cy.state('window')).height();
const rect = $el[0].getBoundingClientRect();
expect(rect.top).to.be.greaterThan(bottom);
expect(rect.bottom).to.be.greaterThan(bottom);
expect(rect.top).to.be.greaterThan(bottom);
expect(rect.bottom).to.be.greaterThan(bottom);
})
});
......@@ -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,
......
<!-- <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> -->
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AnalyticsMenuComponent } from './menu.component';
import { ChartV2Component } from './chart-v2.component';
describe('AnalyticsMenuComponent', () => {
let component: AnalyticsMenuComponent;
let fixture: ComponentFixture<AnalyticsMenuComponent>;
describe('ChartV2Component', () => {
let component: ChartV2Component;
let fixture: ComponentFixture<ChartV2Component>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AnalyticsMenuComponent],
declarations: [ChartV2Component],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AnalyticsMenuComponent);
fixture = TestBed.createComponent(ChartV2Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
xit('should create', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {
Component,
OnInit,
OnDestroy,
HostListener,
ChangeDetectionStrategy,
ChangeDetectorRef,
Input,
ViewChild,
ElementRef,
} from '@angular/core';
// import { Subscription } from 'rxjs';
// import { map } from 'rxjs/operators';
// import {
// AnalyticsDashboardService,
// Timespan as TimespanBase,
// Buckets,
// } from '../../dashboard.service';
// import * as Plotly from 'plotly.js';
// import chartPalette from '../../chart-palette.default';
// import { ThemeService } from '../../../../../common/services/theme.service';
// import isMobileOrTablet from '../../../../../helpers/is-mobile-or-tablet';
@Component({
selector: 'm-chartV2',
templateUrl: './chart-v2.component.html',
})
export class ChartV2Component implements OnInit {
constructor() {}
ngOnInit() {}
}
// -------------------------------------------------------------------------
// interface TimespanExtended extends TimespanBase {
// xTickFormat?: string;
// datePipe?: string;
// }
// export { TimespanExtended as Timespan };
// @Component({
// selector: 'm-analytics__chart',
// templateUrl: 'chart.component.html',
// changeDetection: ChangeDetectionStrategy.OnPush,
// })
// export class AnalyticsChartComponent implements OnDestroy, OnInit {
// @ViewChild('graphDiv', { static: true }) graphDiv;
// @ViewChild('hoverInfoDiv', { static: true }) hoverInfoDivEl: ElementRef;
// @ViewChild('chartContainer', { static: true }) chartContainer: ElementRef;
// isTouchDevice: boolean;
// init: boolean = false;
// hoverInfoDiv: any;
// hoverInfo: any = {};
// metricSubscription: Subscription;
// selectedMetric$ = this.analyticsService.metrics$.pipe(
// map(metrics => {
// return metrics.find(metric => metric.visualisation !== null);
// })
// );
// selectedMetric;
// timespansSubscription: Subscription;
// selectedTimespan;
// themeSubscription: Subscription;
// isDark: boolean = false;
// segments: Buckets[];
// isComparison: boolean = false;
// data = [];
// layout;
// config = {
// displayModeBar: false,
// // responsive: true,
// };
// pointsPerSegment = 1;
// hoverPoint: number;
// lineRange: Array<any>;
// newLineRange = true;
// markerFills;
// shapes = [];
// timespanFormats = [
// { interval: 'day', xTickFormat: '%m/%d', datePipe: 'EEE MMM d, y' },
// { interval: 'month', xTickFormat: '%m/%Y', datePipe: 'MMM y' },
// ];
// datePipe: string = this.timespanFormats[0].datePipe;
// xTickFormat: string = this.timespanFormats[0].xTickFormat;
// // yTickPrefix: string = '';
// yTickFormat: string = '';
// // ***********************************************************
// constructor(
// private analyticsService: AnalyticsDashboardService,
// private themeService: ThemeService,
// protected cd: ChangeDetectorRef
// ) {}
// ngOnInit() {
// this.isTouchDevice = isMobileOrTablet();
// this.hoverInfoDiv = this.hoverInfoDivEl.nativeElement;
// this.timespansSubscription = this.analyticsService.timespans$.subscribe(
// timespans => {
// this.selectedTimespan = timespans.find(
// timespan => timespan.selected === true
// );
// const timespanFormat =
// this.timespanFormats.find(
// t => t.interval === this.selectedTimespan.interval
// ) || this.timespanFormats[0];
// this.xTickFormat = timespanFormat.xTickFormat;
// this.datePipe = timespanFormat.datePipe;
// if (this.init) {
// this.layout.xaxis.tickformat = this.xTickFormat;
// }
// this.detectChanges();
// }
// );
// this.themeSubscription = this.themeService.isDark$.subscribe(isDark => {
// this.isDark = isDark;
// if (this.init) {
// this.getData();
// this.getLayout();
// }
// this.detectChanges();
// });
// this.metricSubscription = this.selectedMetric$.subscribe(metric => {
// this.init = false;
// this.selectedMetric = metric;
// if (metric.unit && metric.unit === 'usd') {
// this.yTickFormat = '$.2f';
// }
// try {
// this.initPlot();
// } catch (err) {
// console.log(err);
// }
// this.detectChanges();
// });
// }
// swapSegmentColors() {
// const tempPaletteItem = chartPalette.segmentColorIds[0];
// chartPalette.segmentColorIds[0] = chartPalette.segmentColorIds[1];
// chartPalette.segmentColorIds[1] = tempPaletteItem;
// }
// initPlot() {
// this.segments = this.selectedMetric.visualisation.segments;
// if (this.segments.length === 2) {
// this.isComparison = true;
// // Reverse the segments so comparison line is layered behind current line
// this.segments.reverse();
// console.log(this.segments);
// // Current line should be blue
// this.swapSegmentColors();
// }
// this.pointsPerSegment = this.segments[0].buckets.length;
// for (let i = 0; i < this.pointsPerSegment; i++) {
// this.shapes[i] = {
// type: 'line',
// layer: 'below',
// x0: this.segments[0].buckets[i].date,
// y0: 0,
// x1: this.segments[0].buckets[i].date,
// y1: 0,
// line: {
// color: 'rgba(0, 0, 0, 0)',
// width: 2,
// },
// };
// }
// this.getData();
// this.getLayout();
// this.init = true;
// this.detectChanges();
// }
// getData() {
// this.markerFills = [];
// this.segments.forEach((segment, index) => {
// const segmentMarkerFills = [];
// for (let i = 0; i < this.pointsPerSegment; i++) {
// segmentMarkerFills[i] = this.getColor('m-white');
// }
// this.markerFills.push(segmentMarkerFills);
// });
// const globalSegmentSettings = {
// type: 'scatter',
// mode: 'lines+markers',
// line: {
// width: 1,
// dash: 'solid',
// },
// marker: {
// size: 7,
// },
// showlegend: false,
// hoverinfo: 'text',
// x: this.unpack(this.segments[0].buckets, 'date'),
// };
// this.segments.forEach((s, i) => {
// const segment = {
// ...globalSegmentSettings,
// line: {
// ...globalSegmentSettings.line,
// color: this.getColor(chartPalette.segmentColorIds[i]),
// },
// marker: {
// ...globalSegmentSettings.marker,
// color: this.markerFills[i],
// line: {
// color: this.getColor(chartPalette.segmentColorIds[i]),
// width: 1,
// },
// },
// y: this.unpack(this.segments[i].buckets, 'value'),
// };
// this.data[i] = segment;
// });
// if (this.isComparison) {
// this.data[0].line.dash = 'dot';
// }
// }
// getLayout() {
// this.layout = {
// width: 0,
// height: 0,
// autoexpand: 'true',
// autosize: 'true',
// hovermode: 'x',
// paper_bgcolor: this.getColor('m-white'),
// plot_bgcolor: this.getColor('m-white'),
// font: {
// family: 'Roboto',
// },
// xaxis: {
// tickformat: this.xTickFormat,
// tickmode: 'array',
// tickson: 'labels',
// tickcolor: this.getColor('m-grey-130'),
// tickangle: -45,
// tickfont: {
// color: this.getColor('m-grey-130'),
// },
// showgrid: false,
// showline: true,
// linecolor: this.getColor('m-grey-300'),
// linewidth: 1,
// zeroline: false,
// fixedrange: true,
// // automargin: true,
// // rangemode: 'nonnegative',
// },
// yaxis: {
// ticks: '',
// tickformat: this.yTickFormat,
// tickmode: 'array',
// tickson: 'labels',
// showgrid: true,
// gridcolor: this.getColor('m-grey-70'),
// zeroline: false,
// visible: true,
// side: 'right',
// tickfont: {
// color: this.getColor('m-grey-130'),
// },
// fixedrange: true,
// // automargin: true,
// // rangemode: 'nonnegative',
// },
// margin: {
// t: 16,
// b: 80,
// l: 0,
// r: 80,
// pad: 16,
// },
// shapes: this.shapes,
// };
// }
// onHover($event) {
// console.log($event);
// this.hoverPoint = $event.points[0].pointIndex;
// this.addMarkerFill();
// this.showShape($event);
// this.positionHoverInfo($event);
// this.populateHoverInfo();
// this.hoverInfoDiv.style.opacity = 1;
// this.detectChanges();
// }
// onUnhover($event) {
// this.emptyMarkerFill();
// this.hideShape();
// this.hoverInfoDiv.style.opacity = 0;
// this.detectChanges();
// }
// onClick($event) {
// if (!this.isTouchDevice) {
// return;
// }
// // TODO: use this for non-hover devices
// }
// addMarkerFill() {
// this.data.forEach((segment, i) => {
// this.markerFills[i][this.hoverPoint] = this.getColor(
// chartPalette.segmentColorIds[i]
// );
// });
// }
// emptyMarkerFill() {
// this.data.forEach((segment, i) => {
// this.markerFills[i][this.hoverPoint] = this.getColor('m-white');
// segment.marker.color = this.markerFills[i];
// });
// }
// showShape($event) {
// const hoverLine = this.shapes[this.hoverPoint];
// // Without this, entire graph resizes on every hover
// if (this.newLineRange) {
// this.newLineRange = false;
// this.lineRange = $event.yaxes[0].range;
// }
// hoverLine.y0 = this.lineRange[0];
// hoverLine.y1 = this.lineRange[1] * 0.99;
// hoverLine.line.color = this.getColor('m-grey-70');
// this.layout.shapes = this.shapes;
// }
// hideShape() {
// this.shapes[this.hoverPoint].line.color = 'rgba(0, 0, 0, 0)';
// this.layout.shapes = this.shapes;
// }
// populateHoverInfo() {
// const pt = this.isComparison ? 1 : 0;
// // TODO: format value strings here and remove ngSwitch from template?
// this.hoverInfo['date'] = this.segments[pt].buckets[this.hoverPoint].date;
// this.hoverInfo['value'] =
// this.selectedMetric.unit !== 'usd'
// ? this.segments[pt].buckets[this.hoverPoint].value
// : this.segments[pt].buckets[this.hoverPoint].value / 100;
// if (this.isComparison && this.segments[1]) {
// this.hoverInfo['comparisonValue'] =
// this.selectedMetric.unit !== 'usd'
// ? this.segments[0].buckets[this.hoverPoint].value
// : this.segments[0].buckets[this.hoverPoint].value / 100;
// this.hoverInfo['comparisonDate'] = this.segments[0].buckets[
// this.hoverPoint
// ].date;
// }
// }
// positionHoverInfo($event) {
// const pad = 16,
// pt = this.isComparison ? 1 : 0,
// xAxis = $event.points[pt].xaxis,
// yAxis = $event.points[pt].yaxis,
// pointXDist = xAxis.d2p($event.points[pt].x) + xAxis._offset,
// pointYDist = yAxis.d2p($event.points[pt].y) + yAxis._offset,
// plotRect = document
// .querySelector('.js-plotly-plot')
// .getBoundingClientRect(),
// hoverInfoRect = this.hoverInfoDiv.getBoundingClientRect();
// if (pointYDist < plotRect.height / 2) {
// // If point is in top half of plot, hoverinfo should go beneath it
// this.hoverInfoDiv.style.top = pointYDist + pad + 'px';
// } else {
// this.hoverInfoDiv.style.top =
// pointYDist - pad - hoverInfoRect.height + 'px';
// }
// if (pointXDist < plotRect.width / 2) {
// // If point is in left half of plot, hoverinfo should go on the right
// this.hoverInfoDiv.style.left = pointXDist + pad + 'px';
// } else {
// this.hoverInfoDiv.style.left =
// pointXDist - pad - hoverInfoRect.width + 'px';
// }
// }
// @HostListener('window:resize')
// applyDimensions() {
// if (this.init) {
// console.log(
// 'chartcontainer: W ' +
// this.chartContainer.nativeElement.clientWidth +
// ', H ' +
// this.chartContainer.nativeElement.clientHeight
// );
// this.layout.width = this.chartContainer.nativeElement.clientWidth - 56; //- 32;
// this.layout.height = this.chartContainer.nativeElement.clientHeight;
// // this.layout = {
// // ...this.layout,
// // width: this.chartContainer.nativeElement.clientWidth, // - 32,
// // height: this.chartContainer.nativeElement.clientHeight, // - 32,
// // };
// this.newLineRange = true;
// this.detectChanges();
// }
// }
// // * UTILITY -----------------------------------
// unpack(rows, key) {
// return rows.map(row => {
// if (key === 'date') {
// return row[key].slice(0, 10);
// } else if (this.selectedMetric.unit === 'usd') {
// return row[key] / 100;
// } else {
// return row[key];
// }
// });
// }
// getColor(colorId) {
// const palette = chartPalette.themeMaps;
// let colorCode = '#607d8b';
// if (palette.find(color => color.id === colorId)) {
// colorCode = palette.find(color => color.id === colorId).themeMap[
// +this.isDark
// ];
// }
// return colorCode;
// }
// detectChanges() {
// this.cd.markForCheck();
// this.cd.detectChanges();
// }
// }
/////////////////////////////////////////////////////////////////////
// @Component({
// selector: 'm-graph',
// template: `
// <plotly-plot
// [data]="data"
// [layout]="_layout"
// [config]="_config"
// ></plotly-plot>
// `,
// })
// export class Graph {
// @Input() data;
// @Input() layout;
// @Input() config;
// get _config() {
// return {
// ...this.config,
// ...{
// displayModeBar: false,
// },
// };
// }
// get _layout() {
// return {
// ...this.layout,
// /*...{
// margin: {
// t: 0,
// b: 0,
// },
// },*/
// };
// }