Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • omadrid/front
  • minds/front
  • joe59/front
  • markharding/front
  • eiennohi/front
  • edgebal/front
  • msantang78/front
  • bhayward93/front
  • xorgy/front
  • duyquoc/front
  • benhayward.ben/front
  • mnurzia/front
  • priestd09/front
  • dknunn/front
  • Yersinia/front
  • literalpie/front
  • maruthi-adithya/front
  • javanick/front
  • juanmsolaro/front
  • ascenderking/front
  • fabiolalombardim/front
  • jim-toth/front
  • Shivathanu/front
  • pestixaba/front
  • project_connection/front
  • mul53/front
  • iamonuwa/front
  • manishoo/front
  • namesty/front
  • AaronTheBruce/front
  • bedriguler/front
  • th2tran/front
  • jun784/front
  • mdstevens044/front
  • CodingNagger/front
  • heenachauhan201/front
  • diazairic/front
  • m994/front
  • webprodev/minds_front
  • chaoukiammar/front
  • benn7/front
  • ung1807/front
  • vinliao/front-patch-1
  • suhailkakar/front
  • theokeist/minds-blog
45 results
Show changes
Commits on Source (13)
Showing
with 353 additions and 56 deletions
......@@ -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;
......
<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>
<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>
.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);
}
}
}
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();
}
}
......@@ -14,6 +14,7 @@ import { AdminInteractions } from './controllers/admin/interactions/interactions
import { InteractionsTableComponent } from './controllers/admin/interactions/table/table.component';
import { AdminPurchasesComponent } from './controllers/admin/purchases/purchases.component';
import { AdminWithdrawals } from './controllers/admin/withdrawals/withdrawals.component';
import { AdminFeaturesComponent } from './controllers/admin/features/admin-features.component';
export const MINDS_DECLARATIONS: any[] = [
// Components
......@@ -35,4 +36,5 @@ export const MINDS_DECLARATIONS: any[] = [
AdminPurchasesComponent,
AdminWithdrawals,
AdminReportsDownload,
AdminFeaturesComponent,
];
......@@ -45,7 +45,7 @@
<h2>Experiments</h2>
<ul class="m-canaryExperiments__list">
<li>
Discovery algorithm by post age - 11th December '19
Server Side Rendering - 5th Feb 2020
</li>
</ul>
</div>
......
<ng-container *ngIf="error || channel; else loader">
<ng-container
*ngIf="
error || !proEnabled || !channel.pro_published || isOwner || isAdmin;
error ||
!proEnabled ||
!showPro ||
!channel.pro_published ||
isOwner ||
isAdmin;
else isProChannel
"
>
......
......@@ -28,6 +28,7 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
channel: MindsUser;
protected username: string;
protected showPro: boolean;
protected param$: Subscription;
......@@ -50,10 +51,11 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
this.param$ = this.route.params.subscribe(params => {
if (params['username']) {
this.username = params['username'];
this.showPro = !params['pro'] || params['pro'] !== '0';
if (
this.username &&
(!this.channel || this.channel.username != this.username)
(!this.channel || this.channel.username !== this.username)
) {
this.load();
}
......@@ -74,7 +76,7 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
}
async load() {
if (!this.username) {
if (!this.username || this.showPro === undefined) {
return;
}
......@@ -88,6 +90,7 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
this.channel = response.channel;
const shouldRedirectToProHandler =
this.showPro &&
!this.site.isProDomain &&
this.channel.pro_published &&
!this.isOwner &&
......
......@@ -2,7 +2,7 @@ import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule as NgCommonModule } from '@angular/common';
import { CommonModule } from '../../common/common.module';
import { Client } from '../../common/api/client.service';
import { Storage } from '../../services/storage';
import { CookieService } from '../../common/services/cookie.service';
import { ExperimentDirective } from './experiment.directive';
import { ExperimentsService } from './experiments.service';
......@@ -14,9 +14,9 @@ import { ExperimentsService } from './experiments.service';
providers: [
{
provide: ExperimentsService,
useFactory: (_client, _storage) =>
new ExperimentsService(_client, _storage),
deps: [Client, Storage],
useFactory: (_client, cookieService) =>
new ExperimentsService(_client, cookieService),
deps: [Client, CookieService],
},
],
})
......
......@@ -18,7 +18,7 @@
*ngIf="group && (group['is:member'] || group.membership == 2)"
>
<!-- Sidebar -->
<div class="m-groupGrid__left">
<div class="m-groupGrid__left" *mIfBrowser>
<m-videochat></m-videochat>
<header
......@@ -328,7 +328,7 @@
<div class="m-groupGrid__right" [hidden]="!showRight">
<!-- Conversation filter -->
<minds-groups-profile-conversation [group]="group">
<minds-groups-profile-conversation [group]="group" *mIfBrowser>
</minds-groups-profile-conversation>
<!-- END: Conversation filter -->
</div>
......
......@@ -183,8 +183,9 @@ export class GroupsProfile {
}
async load() {
if (isPlatformServer(this.platformId)) return;
this.resetMarkers();
if (isPlatformBrowser(this.platformId)) {
this.resetMarkers();
}
this.error = '';
this.group = null;
......@@ -199,38 +200,41 @@ export class GroupsProfile {
if (this.updateMarkersSubscription)
this.updateMarkersSubscription.unsubscribe();
this.updateMarkersSubscription = this.updateMarkers
.getByEntityGuid(this.guid)
.subscribe(
(marker => {
// this.updateMarkersSubscription = this.updateMarkers.markers.subscribe(markers => {
if (!marker) return;
this.group.hasGathering$ = interval(1000).pipe(
throttle(() => interval(2000)), //only allow once per 2 seconds
startWith(0),
map(
() =>
[marker].filter(
marker =>
marker.entity_guid == this.group.guid &&
marker.marker == 'gathering-heartbeat' &&
marker.updated_timestamp > Date.now() / 1000 - 60 //1 minute tollerance
).length > 0
)
);
let hasMarker =
marker.read_timestamp < marker.updated_timestamp &&
marker.entity_guid == this.group.guid &&
marker.marker != 'gathering-heartbeat';
if (hasMarker) this.resetMarkers();
}).bind(this)
);
// Check for comment updates
this.joinCommentsSocketRoom();
if (isPlatformBrowser(this.platformId)) {
this.updateMarkersSubscription = this.updateMarkers
.getByEntityGuid(this.guid)
.subscribe(
(marker => {
// this.updateMarkersSubscription = this.updateMarkers.markers.subscribe(markers => {
if (!marker) return;
this.group.hasGathering$ = interval(1000).pipe(
throttle(() => interval(2000)), //only allow once per 2 seconds
startWith(0),
map(
() =>
[marker].filter(
marker =>
marker.entity_guid == this.group.guid &&
marker.marker == 'gathering-heartbeat' &&
marker.updated_timestamp > Date.now() / 1000 - 60 //1 minute tollerance
).length > 0
)
);
let hasMarker =
marker.read_timestamp < marker.updated_timestamp &&
marker.entity_guid == this.group.guid &&
marker.marker != 'gathering-heartbeat';
if (hasMarker) this.resetMarkers();
}).bind(this)
);
// Check for comment updates
this.joinCommentsSocketRoom();
}
this.updateMeta();
this.context.set('activity', {
......
......@@ -37,6 +37,12 @@
</div>
<div class="m-proChannelFooter__items m-proChannelFooter__socialItems">
<a [routerLink]="['/' + user.username + '/feed', { pro: '0' }]">
<img
alt="Minds"
src="https://cdn-assets.minds.com/front/dist/en/assets/logos/bulb.svg"
/>
</a>
<span *ngFor="let profile of footerSocialProfiles">
<a
*ngIf="profile.key && profile.value"
......
......@@ -3,10 +3,17 @@
margin-bottom: 24px;
color: var(--m-pro--text-color);
.m-proChannelFooter__items > * {
display: inline-block;
margin: 8px 16px;
vertical-align: middle;
.m-proChannelFooter__items {
> * {
display: inline-block;
margin: 8px 16px;
vertical-align: middle;
}
img {
height: 24px;
filter: grayscale(100%);
}
}
.m-proChannelFooter__socialItems {
......@@ -14,9 +21,13 @@
font-size: 1.5em;
}
.m-proChannelFooter__text {
text-transform: uppercase;
letter-spacing: 0.1em;
.m-proChannelFooter__static {
margin-bottom: 16px;
.m-proChannelFooter__text {
text-transform: uppercase;
letter-spacing: 0.1em;
}
}
a {
......
......@@ -21,7 +21,7 @@ export class SocketsService {
subscriptions: any = {};
rooms: string[] = [];
debug: boolean = false;
public error$: BehaviorSubject<boolean>;
public error$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor(
public session: Session,
......@@ -71,9 +71,7 @@ export class SocketsService {
setUpDefaultListeners() {
this.socket.on('connect', () => {
this.error$
? this.error$.next(false)
: (this.error$ = new BehaviorSubject<boolean>(false));
this.error$.next(false);
this.nz.run(() => {
if (this.debug)
console.log(`[ws]::connected to ${this.SOCKET_IO_SERVER}`);
......
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.