Commit 497fa48c authored by Mark Harding's avatar Mark Harding
Browse files

Merge branch 'master' of https://gitlab.com/Minds/front into feat/2511-activity-v2

parents ad2261e2 14445689
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -11,6 +11,12 @@
    flex-wrap: wrap;
  }

  &.m-topbar--navigation__centered {
    max-width: 100%;
    justify-content: center;
    flex-wrap: wrap;
  }

  &:not(.m-topbar--navigation--text-only) .m-topbar--navigation--item span {
    @media screen and (max-width: 840px) {
      display: none;
+11 −1
Original line number Diff line number Diff line
<div class="m-toolbar">
  <div class="m-topbar--row">
    <div class="m-topbar--navigation m-topbar--navigation--text-only">
    <div
      class="m-topbar--navigation m-topbar--navigation__centered m-topbar--navigation--text-only"
    >
      <a
        class="m-topbar--navigation--item"
        routerLink="/analytics/admin"
@@ -99,6 +101,13 @@
      >
        <span i18n="@@M__ADMIN_NAV__REPORTS">Reports</span>
      </a>
      <a
        class="m-topbar--navigation--item"
        routerLink="/admin/features"
        routerLinkActive="m-topbar--navigation--item-active"
      >
        <span i18n="@@M__ADMIN_NAV__FEATURES">Features</span>
      </a>
    </div>
  </div>
</div>
@@ -122,3 +131,4 @@
<m-admin--reports-download
  *ngIf="filter == 'reports-download'"
></m-admin--reports-download>
<m-admin--features *ngIf="filter == 'features'"></m-admin--features>
+47 −0
Original line number Diff line number Diff line
<div class="m-adminFeatures">
  <ng-container *ngIf="!isLoading && !error">
    <div class="m-adminFeatures--label" i18n>
      <b>Environment</b>: {{ environment }}
    </div>

    <div class="m-adminFeatures--label" i18n>
      <b>Features for</b>: {{ readableFor }}
    </div>

    <table class="m-adminFeatures--table" cellspacing="0" cellpadding="0">
      <thead>
        <tr>
          <th class="m-adminFeaturesTable--cell__first">Feature</th>
          <th *ngFor="let service of services">{{ service }}</th>
        </tr>
      </thead>

      <tbody>
        <tr *ngFor="let feature of features">
          <td class="m-adminFeaturesTable--cell__first">{{ feature.name }}</td>
          <td
            *ngFor="let service of services"
            class="m-adminFeaturesTable--cell__value"
            [class.m-adminFeaturesTable--cell__bestValue]="
              isBestService(service, feature.services)
            "
          >
            {{ labelForValue(feature.services[service]) }}
          </td>
        </tr>
      </tbody>
    </table>
  </ng-container>

  <ng-container *ngIf="isLoading">
    <div class="m-adminFeatures--loader">
      <div class="mdl-spinner mdl-js-spinner is-active" [mdl]></div>
    </div>
  </ng-container>

  <ng-container *ngIf="error">
    <div class="m-adminFeatures--error">
      {{ error }}
    </div>
  </ng-container>
</div>
+82 −0
Original line number Diff line number Diff line
.m-adminFeatures {
  max-width: 960px;
  margin: 0 auto;
  padding: 16px;

  .m-adminFeatures--label {
    margin-bottom: 8px;
    padding: 0 4px;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 0.5px;

    @include m-theme() {
      color: themed($m-grey-400);
    }
  }

  .m-adminFeatures--table {
    width: 100%;
    margin-top: 24px;

    th,
    td {
      text-align: center;

      &.m-adminFeaturesTable--cell__first {
        text-align: left;
      }
    }

    th {
      padding: 4px;
      font-size: 14px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      border-bottom: 1px solid;

      @include m-theme() {
        color: themed($m-grey-400);
        border-color: themed($m-black);
      }
    }

    td {
      padding: 8px 4px;

      &.m-adminFeaturesTable--cell__value {
        font-size: 14px;
        text-transform: uppercase;
        letter-spacing: 0.5px;

        @include m-theme() {
          color: themed($m-grey-400);
        }
      }

      &.m-adminFeaturesTable--cell__bestValue {
        font-weight: bold;

        @include m-theme() {
          text-shadow: 0 0 3px rgba(themed($m-blue), 0.6);
          color: themed($m-black);
        }
      }
    }
  }

  .m-adminFeatures--loader {
    text-align: center;
    margin: 64px 0;
  }

  .m-adminFeatures--error {
    text-align: center;
    margin: 100px 0;
    font-size: 28px;

    @include m-theme() {
      color: themed($m-red);
    }
  }
}
+123 −0
Original line number Diff line number Diff line
import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { Client } from '../../../services/api/client';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';

type ServicesEntityStruc = {
  [service: string]: boolean | null;
};

type ResponseFeaturesStruc = Array<{
  name: string;
  services: ServicesEntityStruc;
}>;

@Component({
  selector: 'm-admin--features',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: 'admin-features.component.html',
})
export class AdminFeaturesComponent implements OnInit, OnDestroy {
  isLoading: boolean;

  for: string;

  environment: string;

  services: Array<string>;

  features: ResponseFeaturesStruc;

  error: string;

  protected params$: Subscription;

  constructor(
    protected client: Client,
    protected cd: ChangeDetectorRef,
    protected route: ActivatedRoute
  ) {}

  ngOnInit(): void {
    this.params$ = this.route.params.subscribe(params => {
      if (typeof params.for !== 'undefined') {
        this.for = params.for;
        this.load();
      }
    });

    this.load();
  }

  ngOnDestroy(): void {
    this.params$.unsubscribe();
  }

  async load(): Promise<void> {
    this.isLoading = true;
    this.error = '';
    this.detectChanges();

    try {
      const response: any = await this.client.get('api/v2/admin/features', {
        for: this.for || '',
      });

      this.environment = response.environment;
      this.for = response.for;
      this.services = response.services;
      this.features = response.features;
    } catch (e) {
      this.error = (e && e.message) || 'Internal server error';
    }

    this.isLoading = false;
    this.detectChanges();
  }

  get readableFor(): string {
    if (!this.for) {
      return 'Anonymous user';
    }

    return `@${this.for}`;
  }

  isBestService(
    currentService: string,
    services: ServicesEntityStruc
  ): boolean {
    let bestService = this.services[0];

    for (const service of this.services) {
      if (services[service] !== null) {
        bestService = service;
      }
    }

    return currentService == bestService;
  }

  labelForValue(value: any): string {
    if (value === false) {
      return 'OFF';
    } else if (value === null) {
      return '\xa0';
    } else if (!value) {
      return '???';
    }

    return 'ON';
  }

  detectChanges(): void {
    this.cd.markForCheck();
    this.cd.detectChanges();
  }
}
Loading