Browse Source

Google Analytis Support.

pull/118/head
Sebastian Stehle 9 years ago
parent
commit
8f2a698250
  1. 6
      src/Squidex/app/app.module.ts
  2. 4
      src/Squidex/app/framework/configurations.ts
  3. 3
      src/Squidex/app/framework/declarations.ts
  4. 6
      src/Squidex/app/framework/module.ts
  5. 14
      src/Squidex/app/framework/plattform.ts
  6. 51
      src/Squidex/app/framework/services/analytics.service.ts
  7. 4
      src/Squidex/app/shared/services/app-clients.service.spec.ts
  8. 13
      src/Squidex/app/shared/services/app-clients.service.ts
  9. 4
      src/Squidex/app/shared/services/app-contributors.service.spec.ts
  10. 10
      src/Squidex/app/shared/services/app-contributors.service.ts
  11. 5
      src/Squidex/app/shared/services/app-languages.service.spec.ts
  12. 13
      src/Squidex/app/shared/services/app-languages.service.ts
  13. 4
      src/Squidex/app/shared/services/apps.service.spec.ts
  14. 7
      src/Squidex/app/shared/services/apps.service.ts
  15. 4
      src/Squidex/app/shared/services/assets.service.spec.ts
  16. 12
      src/Squidex/app/shared/services/assets.service.ts
  17. 4
      src/Squidex/app/shared/services/contents.service.spec.ts
  18. 34
      src/Squidex/app/shared/services/contents.service.ts
  19. 4
      src/Squidex/app/shared/services/plans.service.spec.ts
  20. 7
      src/Squidex/app/shared/services/plans.service.ts
  21. 4
      src/Squidex/app/shared/services/schemas.service.spec.ts
  22. 46
      src/Squidex/app/shared/services/schemas.service.ts
  23. 4
      src/Squidex/app/shared/services/webhooks.service.spec.ts
  24. 16
      src/Squidex/app/shared/services/webhooks.service.ts

6
src/Squidex/app/app.module.ts

@ -13,6 +13,7 @@ import { DndModule } from 'ng2-dnd';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { import {
AnalyticsIdConfig,
ApiUrlConfig, ApiUrlConfig,
CurrencyConfig, CurrencyConfig,
DecimalSeparatorConfig, DecimalSeparatorConfig,
@ -34,6 +35,10 @@ export function configTitles() {
return new TitlesConfig({}, undefined, 'Squidex Headless CMS'); return new TitlesConfig({}, undefined, 'Squidex Headless CMS');
} }
export function configAnalyticsId() {
return new AnalyticsIdConfig('UA-99989790-2');
}
export function configDecimalSeparator() { export function configDecimalSeparator() {
return new DecimalSeparatorConfig('.'); return new DecimalSeparatorConfig('.');
} }
@ -60,6 +65,7 @@ export function configUserReport() {
AppComponent AppComponent
], ],
providers: [ providers: [
{ provide: AnalyticsIdConfig, useFactory: configAnalyticsId },
{ provide: ApiUrlConfig, useFactory: configApiUrl }, { provide: ApiUrlConfig, useFactory: configApiUrl },
{ provide: CurrencyConfig, useFactory: configCurrency }, { provide: CurrencyConfig, useFactory: configCurrency },
{ provide: DecimalSeparatorConfig, useFactory: configDecimalSeparator }, { provide: DecimalSeparatorConfig, useFactory: configDecimalSeparator },

4
src/Squidex/app/framework/configurations.ts

@ -34,6 +34,10 @@ export class CurrencyConfig {
} }
} }
export class AnalyticsIdConfig {
constructor(public value: string) { }
}
export class DecimalSeparatorConfig { export class DecimalSeparatorConfig {
constructor(public readonly value: string) { } constructor(public readonly value: string) { }
} }

3
src/Squidex/app/framework/declarations.ts

@ -51,6 +51,7 @@ export * from './angular/user-report.component';
export * from './angular/validators'; export * from './angular/validators';
export * from './configurations'; export * from './configurations';
export * from './services/analytics.service';
export * from './services/clipboard.service'; export * from './services/clipboard.service';
export * from './services/dialog.service'; export * from './services/dialog.service';
export * from './services/local-store.service'; export * from './services/local-store.service';
@ -61,8 +62,6 @@ export * from './services/root-view.service';
export * from './services/shortcut.service'; export * from './services/shortcut.service';
export * from './services/title.service'; export * from './services/title.service';
export * from './plattform';
export * from './utils/date-helper'; export * from './utils/date-helper';
export * from './utils/date-time'; export * from './utils/date-time';
export * from './utils/duration'; export * from './utils/duration';

6
src/Squidex/app/framework/module.ts

@ -6,12 +6,13 @@
*/ */
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { ModuleWithProviders, NgModule } from '@angular/core'; import { ModuleWithProviders, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { import {
AnalyticsService,
AutocompleteComponent, AutocompleteComponent,
CanDeactivateGuard, CanDeactivateGuard,
ClipboardService, ClipboardService,
@ -185,6 +186,7 @@ export class SqxFrameworkModule {
return { return {
ngModule: SqxFrameworkModule, ngModule: SqxFrameworkModule,
providers: [ providers: [
AnalyticsService,
CanDeactivateGuard, CanDeactivateGuard,
ClipboardService, ClipboardService,
DialogService, DialogService,

14
src/Squidex/app/framework/plattform.ts

@ -1,14 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Observable } from 'rxjs/Observable';
export abstract class AppStore {
public abstract select<T>(pathOrMapFn: any, ...paths: string[]): Observable<T>;
public abstract next(action: any): void;
}

51
src/Squidex/app/framework/services/analytics.service.ts

@ -0,0 +1,51 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Injectable } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { AnalyticsIdConfig } from '../configurations';
import { ResourceLoaderService } from './resource-loader.service';
// tslint:disable:only-arrow-functions
export const AnalyticsServiceFactory = (analyticsId: AnalyticsIdConfig, router: Router, resourceLoader: ResourceLoaderService) => {
return new AnalyticsService(analyticsId, router, resourceLoader);
}
@Injectable()
export class AnalyticsService {
private readonly gtag: any;
constructor(analyticsId?: AnalyticsIdConfig, router?: Router, resourceLoader?: ResourceLoaderService) {
window['dataLayer'] = window['dataLayer'] || [];
this.gtag = function () {
window['dataLayer'].push(arguments);
};
if (analyticsId && router && resourceLoader && window.location.hostname !== 'localhost') {
this.gtag('config', analyticsId.value);
router.events.filter(e => e instanceof NavigationEnd)
.subscribe(() => {
this.gtag('config', analyticsId.value, { page_path: window.location.pathname });
});
resourceLoader.loadScript(`https://www.googletagmanager.com/gtag/js?id=${analyticsId.value}`);
}
}
public trackEvent(category: string, action: string, label?: string, value?: number) {
this.gtag('event', 'user-action', {
event_category: category,
event_action: action,
event_label: label,
value: value
});
}
}

4
src/Squidex/app/shared/services/app-clients.service.spec.ts

@ -10,6 +10,7 @@ import { inject, TestBed } from '@angular/core/testing';
import { import {
AccessTokenDto, AccessTokenDto,
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
AppClientDto, AppClientDto,
AppClientsService, AppClientsService,
@ -44,7 +45,8 @@ describe('AppClientsService', () => {
], ],
providers: [ providers: [
AppClientsService, AppClientsService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

13
src/Squidex/app/shared/services/app-clients.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
HTTP, HTTP,
Version Version
@ -62,7 +63,8 @@ export class AccessTokenDto {
export class AppClientsService { export class AppClientsService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -95,6 +97,9 @@ export class AppClientsService {
response.secret, response.secret,
response.isReader); response.isReader);
}) })
.do(() => {
this.analytics.trackEvent('Client', 'Created', appName);
})
.pretifyError('Failed to add client. Please reload.'); .pretifyError('Failed to add client. Please reload.');
} }
@ -102,6 +107,9 @@ export class AppClientsService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Client', 'Updated', appName);
})
.pretifyError('Failed to revoke client. Please reload.'); .pretifyError('Failed to revoke client. Please reload.');
} }
@ -109,6 +117,9 @@ export class AppClientsService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`);
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => {
this.analytics.trackEvent('Client', 'Deleted', appName);
})
.pretifyError('Failed to revoke client. Please reload.'); .pretifyError('Failed to revoke client. Please reload.');
} }

4
src/Squidex/app/shared/services/app-contributors.service.spec.ts

@ -9,6 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
AppContributorDto, AppContributorDto,
AppContributorsDto, AppContributorsDto,
@ -35,7 +36,8 @@ describe('AppContributorsService', () => {
], ],
providers: [ providers: [
AppContributorsService, AppContributorsService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

10
src/Squidex/app/shared/services/app-contributors.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
HTTP, HTTP,
Version Version
@ -41,7 +42,8 @@ export class AppContributorsDto {
export class AppContributorsService { export class AppContributorsService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -67,6 +69,9 @@ export class AppContributorsService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`);
return HTTP.postVersioned(this.http, url, dto, version) return HTTP.postVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Contributor', 'Configured', appName);
})
.pretifyError('Failed to add contributors. Please reload.'); .pretifyError('Failed to add contributors. Please reload.');
} }
@ -74,6 +79,9 @@ export class AppContributorsService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors/${contributorId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors/${contributorId}`);
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => {
this.analytics.trackEvent('Contributor', 'Deleted', appName);
})
.pretifyError('Failed to delete contributors. Please reload.'); .pretifyError('Failed to delete contributors. Please reload.');
} }
} }

5
src/Squidex/app/shared/services/app-languages.service.spec.ts

@ -10,6 +10,7 @@ import { inject, TestBed } from '@angular/core/testing';
import { import {
AddAppLanguageDto, AddAppLanguageDto,
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
AppLanguageDto, AppLanguageDto,
AppLanguagesService, AppLanguagesService,
@ -17,7 +18,6 @@ import {
Version Version
} from './../'; } from './../';
describe('AppLanguageDto', () => { describe('AppLanguageDto', () => {
it('should update properties when updating', () => { it('should update properties when updating', () => {
const language_1 = new AppLanguageDto('de', 'English', false, false, []); const language_1 = new AppLanguageDto('de', 'English', false, false, []);
@ -39,7 +39,8 @@ describe('AppLanguagesService', () => {
], ],
providers: [ providers: [
AppLanguagesService, AppLanguagesService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

13
src/Squidex/app/shared/services/app-languages.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
HTTP, HTTP,
Version Version
@ -52,7 +53,8 @@ export class UpdateAppLanguageDto {
export class AppLanguagesService { export class AppLanguagesService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -87,6 +89,9 @@ export class AppLanguagesService {
response.isOptional === true, response.isOptional === true,
response.fallback || []); response.fallback || []);
}) })
.do(() => {
this.analytics.trackEvent('Language', 'Added', appName);
})
.pretifyError('Failed to add language. Please reload.'); .pretifyError('Failed to add language. Please reload.');
} }
@ -94,6 +99,9 @@ export class AppLanguagesService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Language', 'Updated', appName);
})
.pretifyError('Failed to change language. Please reload.'); .pretifyError('Failed to change language. Please reload.');
} }
@ -101,6 +109,9 @@ export class AppLanguagesService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`);
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => {
this.analytics.trackEvent('Language', 'Deleted', appName);
})
.pretifyError('Failed to add language. Please reload.'); .pretifyError('Failed to add language. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/apps.service.spec.ts

@ -9,6 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
AppDto, AppDto,
AppsService, AppsService,
@ -26,7 +27,8 @@ describe('AppsService', () => {
], ],
providers: [ providers: [
AppsService, AppsService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

7
src/Squidex/app/shared/services/apps.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
DateTime, DateTime,
HTTP HTTP
@ -39,7 +40,8 @@ export class CreateAppDto {
export class AppsService { export class AppsService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -71,6 +73,9 @@ export class AppsService {
return new AppDto(response.id, dto.name, 'Owner', now, now); return new AppDto(response.id, dto.name, 'Owner', now, now);
}) })
.do(() => {
this.analytics.trackEvent('App', 'Created', dto.name);
})
.pretifyError('Failed to create app. Please reload.'); .pretifyError('Failed to create app. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/assets.service.spec.ts

@ -9,6 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
AssetsDto, AssetsDto,
AssetDto, AssetDto,
@ -66,7 +67,8 @@ describe('AssetsService', () => {
providers: [ providers: [
AssetsService, AssetsService,
LocalCacheService, LocalCacheService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

12
src/Squidex/app/shared/services/assets.service.ts

@ -10,6 +10,7 @@ import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
DateTime, DateTime,
LocalCacheService, LocalCacheService,
@ -102,6 +103,7 @@ export class AssetsService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig, private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService,
private readonly localCache: LocalCacheService private readonly localCache: LocalCacheService
) { ) {
} }
@ -193,6 +195,8 @@ export class AssetsService {
} }
}) })
.do(dto => { .do(dto => {
this.analytics.trackEvent('Asset', 'Uploaded', appName);
if (dto instanceof AssetDto) { if (dto instanceof AssetDto) {
this.localCache.set(`asset.${dto.id}`, dto, 5000); this.localCache.set(`asset.${dto.id}`, dto, 5000);
} }
@ -266,6 +270,9 @@ export class AssetsService {
return dto; return dto;
} }
}) })
.do(() => {
this.analytics.trackEvent('Analytics', 'Replaced', appName);
})
.pretifyError('Failed to replace asset. Please reload.'); .pretifyError('Failed to replace asset. Please reload.');
} }
@ -274,6 +281,8 @@ export class AssetsService {
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => { .do(() => {
this.analytics.trackEvent('Analytics', 'Deleted', appName);
this.localCache.remove(`asset.${id}`); this.localCache.remove(`asset.${id}`);
}) })
.pretifyError('Failed to delete asset. Please reload.'); .pretifyError('Failed to delete asset. Please reload.');
@ -283,6 +292,9 @@ export class AssetsService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Analytics', 'Updated', appName);
})
.pretifyError('Failed to delete asset. Please reload.'); .pretifyError('Failed to delete asset. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/contents.service.spec.ts

@ -9,6 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
ContentDto, ContentDto,
ContentsDto, ContentsDto,
@ -91,7 +92,8 @@ describe('ContentsService', () => {
providers: [ providers: [
ContentsService, ContentsService,
LocalCacheService, LocalCacheService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

34
src/Squidex/app/shared/services/contents.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
DateTime, DateTime,
LocalCacheService, LocalCacheService,
@ -94,6 +95,7 @@ export class ContentsService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig, private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService,
private readonly localCache: LocalCacheService private readonly localCache: LocalCacheService
) { ) {
} }
@ -179,6 +181,13 @@ export class ContentsService {
.pretifyError('Failed to load content. Please reload.'); .pretifyError('Failed to load content. Please reload.');
} }
public getVersionData(appName: string, schemaName: string, id: string, version: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/${version.value}`);
return HTTP.getVersioned(this.http, url, version)
.pretifyError('Failed to load data. Please reload.');
}
public postContent(appName: string, schemaName: string, dto: any, publish: boolean): Observable<ContentDto> { public postContent(appName: string, schemaName: string, dto: any, publish: boolean): Observable<ContentDto> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?publish=${publish}`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?publish=${publish}`);
@ -195,6 +204,8 @@ export class ContentsService {
new Version(response.version.toString())); new Version(response.version.toString()));
}) })
.do(content => { .do(content => {
this.analytics.trackEvent('Content', 'Created', appName);
this.localCache.set(`content.${content.id}`, content, 5000); this.localCache.set(`content.${content.id}`, content, 5000);
}) })
.pretifyError('Failed to create content. Please reload.'); .pretifyError('Failed to create content. Please reload.');
@ -205,6 +216,8 @@ export class ContentsService {
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => { .do(() => {
this.analytics.trackEvent('Content', 'Updated', appName);
this.localCache.set(`content.${id}`, dto, 5000); this.localCache.set(`content.${id}`, dto, 5000);
}) })
.pretifyError('Failed to update content. Please reload.'); .pretifyError('Failed to update content. Please reload.');
@ -215,22 +228,20 @@ export class ContentsService {
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => { .do(() => {
this.analytics.trackEvent('Content', 'Deleted', appName);
this.localCache.remove(`content.${id}`); this.localCache.remove(`content.${id}`);
}) })
.pretifyError('Failed to delete content. Please reload.'); .pretifyError('Failed to delete content. Please reload.');
} }
public getVersionData(appName: string, schemaName: string, id: string, version: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/${version.value}`);
return HTTP.getVersioned(this.http, url, version)
.pretifyError('Failed to load data. Please reload.');
}
public publishContent(appName: string, schemaName: string, id: string, version: Version): Observable<any> { public publishContent(appName: string, schemaName: string, id: string, version: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/publish`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/publish`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Content', 'Published', appName);
})
.pretifyError('Failed to publish content. Please reload.'); .pretifyError('Failed to publish content. Please reload.');
} }
@ -238,6 +249,9 @@ export class ContentsService {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/unpublish`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/unpublish`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Content', 'Unpublished', appName);
})
.pretifyError('Failed to unpublish content. Please reload.'); .pretifyError('Failed to unpublish content. Please reload.');
} }
@ -245,6 +259,9 @@ export class ContentsService {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/archive`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/archive`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Content', 'Archived', appName);
})
.pretifyError('Failed to archive content. Please reload.'); .pretifyError('Failed to archive content. Please reload.');
} }
@ -252,6 +269,9 @@ export class ContentsService {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/restore`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/restore`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Content', 'Restored', appName);
})
.pretifyError('Failed to restore content. Please reload.'); .pretifyError('Failed to restore content. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/plans.service.spec.ts

@ -9,6 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
AppPlansDto, AppPlansDto,
ApiUrlConfig, ApiUrlConfig,
ChangePlanDto, ChangePlanDto,
@ -28,7 +29,8 @@ describe('PlansService', () => {
], ],
providers: [ providers: [
PlansService, PlansService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

7
src/Squidex/app/shared/services/plans.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
HTTP, HTTP,
Version Version
@ -57,7 +58,8 @@ export class ChangePlanDto {
export class PlansService { export class PlansService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -92,6 +94,9 @@ export class PlansService {
.map(response => { .map(response => {
return new PlanChangedDto(response.redirectUri); return new PlanChangedDto(response.redirectUri);
}) })
.do(() => {
this.analytics.trackEvent('Plan', 'Changed', appName);
})
.pretifyError('Failed to change plan. Please reload.'); .pretifyError('Failed to change plan. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/schemas.service.spec.ts

@ -10,6 +10,7 @@ import { inject, TestBed } from '@angular/core/testing';
import { import {
AddFieldDto, AddFieldDto,
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
CreateSchemaDto, CreateSchemaDto,
createProperties, createProperties,
@ -185,7 +186,8 @@ describe('SchemasService', () => {
providers: [ providers: [
LocalCacheService, LocalCacheService,
SchemasService, SchemasService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

46
src/Squidex/app/shared/services/schemas.service.ts

@ -13,6 +13,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
DateTime, DateTime,
LocalCacheService, LocalCacheService,
@ -689,6 +690,7 @@ export class SchemasService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig, private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService,
private readonly localCache: LocalCacheService private readonly localCache: LocalCacheService
) { ) {
} }
@ -795,6 +797,8 @@ export class SchemasService {
response.scriptChange); response.scriptChange);
}) })
.do(schema => { .do(schema => {
this.analytics.trackEvent('Schema', 'Created', appName);
this.localCache.set(`schema.${appName}.${schema.id}`, schema, 5000); this.localCache.set(`schema.${appName}.${schema.id}`, schema, 5000);
this.localCache.set(`schema.${appName}.${schema.name}`, schema, 5000); this.localCache.set(`schema.${appName}.${schema.name}`, schema, 5000);
}) })
@ -815,6 +819,9 @@ export class SchemasService {
dto.partitioning, dto.partitioning,
dto.properties); dto.properties);
}) })
.do(() => {
this.analytics.trackEvent('Schema', 'FieldCreated', appName);
})
.pretifyError('Failed to add field. Please reload.'); .pretifyError('Failed to add field. Please reload.');
} }
@ -825,6 +832,9 @@ export class SchemasService {
.do(() => { .do(() => {
this.localCache.remove(`schema.${appName}.${schemaName}`); this.localCache.remove(`schema.${appName}.${schemaName}`);
}) })
.do(() => {
this.analytics.trackEvent('Schema', 'Deleted', appName);
})
.pretifyError('Failed to delete schema. Please reload.'); .pretifyError('Failed to delete schema. Please reload.');
} }
@ -832,6 +842,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/scripts`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/scripts`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Schema', 'ScriptsConfigured', appName);
})
.pretifyError('Failed to update schema scripts. Please reload.'); .pretifyError('Failed to update schema scripts. Please reload.');
} }
@ -839,6 +852,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Schema', 'Updated', appName);
})
.pretifyError('Failed to update schema. Please reload.'); .pretifyError('Failed to update schema. Please reload.');
} }
@ -846,6 +862,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/ordering`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/ordering`);
return HTTP.putVersioned(this.http, url, { fieldIds: dto }, version) return HTTP.putVersioned(this.http, url, { fieldIds: dto }, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldsReordered', appName);
})
.pretifyError('Failed to reorder fields. Please reload.'); .pretifyError('Failed to reorder fields. Please reload.');
} }
@ -853,6 +872,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'Published', appName);
})
.pretifyError('Failed to publish schema. Please reload.'); .pretifyError('Failed to publish schema. Please reload.');
} }
@ -860,6 +882,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'Unpublished', appName);
})
.pretifyError('Failed to unpublish schema. Please reload.'); .pretifyError('Failed to unpublish schema. Please reload.');
} }
@ -867,6 +892,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldUpdated', appName);
})
.pretifyError('Failed to update field. Please reload.'); .pretifyError('Failed to update field. Please reload.');
} }
@ -874,6 +902,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldEnabled', appName);
})
.pretifyError('Failed to enable field. Please reload.'); .pretifyError('Failed to enable field. Please reload.');
} }
@ -881,6 +912,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldDisabled', appName);
})
.pretifyError('Failed to disable field. Please reload.'); .pretifyError('Failed to disable field. Please reload.');
} }
@ -888,6 +922,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/lock`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/lock`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldLocked', appName);
})
.pretifyError('Failed to lock field. Please reload.'); .pretifyError('Failed to lock field. Please reload.');
} }
@ -895,6 +932,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldShown', appName);
})
.pretifyError('Failed to show field. Please reload.'); .pretifyError('Failed to show field. Please reload.');
} }
@ -902,6 +942,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide`);
return HTTP.putVersioned(this.http, url, {}, version) return HTTP.putVersioned(this.http, url, {}, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldHidden', appName);
})
.pretifyError('Failed to hide field. Please reload.'); .pretifyError('Failed to hide field. Please reload.');
} }
@ -909,6 +952,9 @@ export class SchemasService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => {
this.analytics.trackEvent('Schema', 'FieldDeleted', appName);
})
.pretifyError('Failed to delete field. Please reload.'); .pretifyError('Failed to delete field. Please reload.');
} }
} }

4
src/Squidex/app/shared/services/webhooks.service.spec.ts

@ -10,6 +10,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
CreateWebhookDto, CreateWebhookDto,
DateTime, DateTime,
@ -57,7 +58,8 @@ describe('WebhooksService', () => {
], ],
providers: [ providers: [
WebhooksService, WebhooksService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
] ]
}); });
}); });

16
src/Squidex/app/shared/services/webhooks.service.ts

@ -12,6 +12,7 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions'; import 'framework/angular/http-extensions';
import { import {
AnalyticsService,
ApiUrlConfig, ApiUrlConfig,
DateTime, DateTime,
HTTP, HTTP,
@ -106,7 +107,8 @@ export class UpdateWebhookDto {
export class WebhooksService { export class WebhooksService {
constructor( constructor(
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly apiUrl: ApiUrlConfig private readonly apiUrl: ApiUrlConfig,
private readonly analytics: AnalyticsService
) { ) {
} }
@ -162,6 +164,9 @@ export class WebhooksService {
dto.url, dto.url,
0, 0, 0, 0); 0, 0, 0, 0);
}) })
.do(() => {
this.analytics.trackEvent('Webhook', 'Created', appName);
})
.pretifyError('Failed to create webhook. Please reload.'); .pretifyError('Failed to create webhook. Please reload.');
} }
@ -169,6 +174,9 @@ export class WebhooksService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/${id}`);
return HTTP.putVersioned(this.http, url, dto, version) return HTTP.putVersioned(this.http, url, dto, version)
.do(() => {
this.analytics.trackEvent('Webhook', 'Updated', appName);
})
.pretifyError('Failed to update webhook. Please reload.'); .pretifyError('Failed to update webhook. Please reload.');
} }
@ -176,6 +184,9 @@ export class WebhooksService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/${id}`);
return HTTP.deleteVersioned(this.http, url, version) return HTTP.deleteVersioned(this.http, url, version)
.do(() => {
this.analytics.trackEvent('Webhook', 'Deleted', appName);
})
.pretifyError('Failed to delete webhook. Please reload.'); .pretifyError('Failed to delete webhook. Please reload.');
} }
@ -206,6 +217,9 @@ export class WebhooksService {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/events/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/webhooks/events/${id}`);
return HTTP.putVersioned(this.http, url, {}) return HTTP.putVersioned(this.http, url, {})
.do(() => {
this.analytics.trackEvent('Webhook', 'EventEnqueued', appName);
})
.pretifyError('Failed to enqueue webhook event. Please reload.'); .pretifyError('Failed to enqueue webhook event. Please reload.');
} }
} }
Loading…
Cancel
Save