commit
ee9daad783
|
@ -0,0 +1,32 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreSiteFixture } from '@/storybook/stubs/classes/site';
|
||||
|
||||
export const companyLisaSite: CoreSiteFixture = {
|
||||
id: 'companylisasite',
|
||||
info: {
|
||||
version: '2022041900',
|
||||
sitename: 'Company',
|
||||
username: 'lisa',
|
||||
firstname: 'Lisa',
|
||||
lastname: 'Díaz',
|
||||
fullname: 'Lisa Díaz',
|
||||
lang: 'en',
|
||||
userid: 1,
|
||||
siteurl: 'https://company.example.edu',
|
||||
userpictureurl: 'https://i.pravatar.cc/300?user=companylisa',
|
||||
functions: [],
|
||||
},
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
{"id":"123456","info":{"version":"2022041900","sitename":"School","username":"barbara","firstname":"Barbara","lastname":"Gardner","fullname":"Barbara Gardner","lang":"en","userid":1,"siteurl":"https://campus.example.edu","userpictureurl":"","functions":[]}}
|
|
@ -0,0 +1,32 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreSiteFixture } from '@/storybook/stubs/classes/site';
|
||||
|
||||
export const schoolBarbaraSite: CoreSiteFixture = {
|
||||
id: 'schoolbarbarasite',
|
||||
info: {
|
||||
version: '2022041900',
|
||||
sitename: 'School',
|
||||
username: 'barbara',
|
||||
firstname: 'Barbara',
|
||||
lastname: 'Gardner',
|
||||
fullname: 'Barbara Gardner',
|
||||
lang: 'en',
|
||||
userid: 1,
|
||||
siteurl: 'https://campus.example.edu',
|
||||
userpictureurl: 'https://i.pravatar.cc/300?user=schoolbarbara',
|
||||
functions: [],
|
||||
},
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreSiteFixture } from '@/storybook/stubs/classes/site';
|
||||
|
||||
export const schoolJefferySite: CoreSiteFixture = {
|
||||
id: 'schooljefferysite',
|
||||
info: {
|
||||
version: '2022041900',
|
||||
sitename: 'School',
|
||||
username: 'jeffery',
|
||||
firstname: 'Jeffery',
|
||||
lastname: 'Sanders',
|
||||
fullname: 'Jeffery Sanders',
|
||||
lang: 'en',
|
||||
userid: 2,
|
||||
siteurl: 'https://campus.example.edu',
|
||||
userpictureurl: 'https://i.pravatar.cc/300?user=schooljeffery',
|
||||
functions: [],
|
||||
},
|
||||
};
|
|
@ -296,14 +296,18 @@ export class CoreSite {
|
|||
* @returns Site name.
|
||||
*/
|
||||
async getSiteName(): Promise<string> {
|
||||
if (this.isDemoModeSite()) {
|
||||
return CoreConstants.CONFIG.appname;
|
||||
}
|
||||
|
||||
if (this.infos?.sitename) {
|
||||
return this.infos?.sitename;
|
||||
}
|
||||
|
||||
// Fallback.
|
||||
const isSigleFixedSite = await CoreLoginHelper.isSingleFixedSite();
|
||||
const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite();
|
||||
|
||||
if (isSigleFixedSite) {
|
||||
if (isSingleFixedSite) {
|
||||
const sites = await CoreLoginHelper.getAvailableSites();
|
||||
|
||||
return sites[0].name;
|
||||
|
@ -2459,6 +2463,17 @@ export class CoreSite {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site is a demo mode site.
|
||||
*
|
||||
* @returns Whether the site is a demo mode site.
|
||||
*/
|
||||
isDemoModeSite(): boolean {
|
||||
const demoSiteData = CoreLoginHelper.getDemoModeSiteInfo();
|
||||
|
||||
return this.containsUrl(demoSiteData?.url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,6 +65,7 @@ import { CoreGroupSelectorComponent } from './group-selector/group-selector';
|
|||
import { CoreRefreshButtonModalComponent } from './refresh-button-modal/refresh-button-modal';
|
||||
import { CoreSheetModalComponent } from '@components/sheet-modal/sheet-modal';
|
||||
import { CoreCourseImageComponent } from '@components/course-image/course-image';
|
||||
import { CoreSitesListComponent } from './sites-list/sites-list';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -112,6 +113,7 @@ import { CoreCourseImageComponent } from '@components/course-image/course-image'
|
|||
CoreSwipeNavigationTourComponent,
|
||||
CoreRefreshButtonModalComponent,
|
||||
CoreSheetModalComponent,
|
||||
CoreSitesListComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
@ -166,6 +168,7 @@ import { CoreCourseImageComponent } from '@components/course-image/course-image'
|
|||
CoreSwipeNavigationTourComponent,
|
||||
CoreRefreshButtonModalComponent,
|
||||
CoreSheetModalComponent,
|
||||
CoreSitesListComponent,
|
||||
],
|
||||
})
|
||||
export class CoreComponentsModule {}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<ion-list class="core-sites-list" *ngIf="accountsList">
|
||||
<ion-card *ngIf="accountsList.currentSite">
|
||||
<ng-container *ngTemplateOutlet="siteCardHeader; context: {site: accountsList.currentSite, isCurrentSite: true}"></ng-container>
|
||||
|
||||
<ng-container *ngTemplateOutlet="siteItem; context: {site: accountsList.currentSite, isCurrentSite: true}"></ng-container>
|
||||
|
||||
<ng-container *ngFor="let site of accountsList.sameSite">
|
||||
<ng-container *ngTemplateOutlet="siteItem; context: {site: site, isCurrentSite: false}"></ng-container>
|
||||
</ng-container>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngFor="let sites of accountsList.otherSites">
|
||||
<ng-container *ngTemplateOutlet="siteCardHeader; context: {site: sites[0], isCurrentSite: false}"></ng-container>
|
||||
|
||||
<ng-container *ngFor="let site of sites">
|
||||
<ng-container *ngTemplateOutlet="siteItem; context: {site: site, isCurrentSite: false}"></ng-container>
|
||||
</ng-container>
|
||||
</ion-card>
|
||||
|
||||
</ion-list>
|
||||
|
||||
<!-- Template to render the header of a site card. -->
|
||||
<ng-template #siteCardHeader let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
<ion-item-divider sticky="true" *ngIf="site" class="core-sites-list-sitename">
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
||||
</h2>
|
||||
<p *ngIf="!site.isDemoModeSite">
|
||||
<a [href]="site.siteUrl" core-link [autoLogin]="isCurrentSite ? 'yes' : 'no'">
|
||||
{{ site.siteUrlWithoutProtocol }}
|
||||
</a>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
</ng-template>
|
||||
|
||||
<!-- Template to render a site item. -->
|
||||
<ng-template #siteItem let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
<ion-item [attr.button]="isSiteClickable(isCurrentSite) ? true : null" (click)="siteClicked($event, site, isCurrentSite)"
|
||||
[attr.detail]="isSiteClickable(isCurrentSite) ? 'true' : 'false'" [class.item-current]="isCurrentSite">
|
||||
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
<ng-container *ngIf="siteLabelTemplate" [ngTemplateOutlet]="siteLabelTemplate"
|
||||
[ngTemplateOutletContext]="{site: site, isCurrentSite: isCurrentSite}">
|
||||
</ng-container>
|
||||
</ion-label>
|
||||
|
||||
<ng-container *ngIf="siteItemTemplate" [ngTemplateOutlet]="siteItemTemplate"
|
||||
[ngTemplateOutletContext]="{site: site, isCurrentSite: isCurrentSite}">
|
||||
</ng-container>
|
||||
</ion-item>
|
||||
</ng-template>
|
|
@ -1,5 +1,5 @@
|
|||
ion-list.core-sitelist {
|
||||
.core-sitelist-sitename {
|
||||
ion-list.core-sites-list {
|
||||
.core-sites-list-sitename {
|
||||
ion-label {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
|
@ -0,0 +1,80 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } from '@angular/core';
|
||||
|
||||
import { CoreSiteBasicInfo } from '@services/sites';
|
||||
import { CoreAccountsList } from '@features/login/services/login-helper';
|
||||
|
||||
/**
|
||||
* Component to display a list of sites (accounts).
|
||||
*
|
||||
* By default this component will display the avatar and user fullname for each site, but it allows adding more information
|
||||
* in the item and in the label for each site, using #siteItem and #siteLabel ng-templates. These templates will receive the
|
||||
* site being rendered and whether it's the current site or not. Example:
|
||||
*
|
||||
* <core-sites-list [accountsList]="accountsList">
|
||||
* <ng-template #siteLabel let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
* <!-- Content to be placed in the label, after the user full name.
|
||||
* </ng-template>
|
||||
*
|
||||
* <ng-template #siteItem let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
* <!-- Content to be placed in the item.
|
||||
* </ng-template>
|
||||
* </core-sites-list>
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-sites-list',
|
||||
templateUrl: 'sites-list.html',
|
||||
styleUrls: ['sites-list.scss'],
|
||||
})
|
||||
export class CoreSitesListComponent<T extends CoreSiteBasicInfo> {
|
||||
|
||||
@Input() accountsList!: CoreAccountsList<T>;
|
||||
@Input() sitesClickable = false; // Whether the sites are clickable.
|
||||
@Input() currentSiteClickable?: boolean; // If set, specify a different clickable value for current site.
|
||||
@Output() onSiteClicked = new EventEmitter<T>();
|
||||
|
||||
@ContentChild('siteItem') siteItemTemplate?: TemplateRef<unknown>;
|
||||
@ContentChild('siteLabel') siteLabelTemplate?: TemplateRef<unknown>;
|
||||
|
||||
/**
|
||||
* Check whether a site is clickable.
|
||||
*
|
||||
* @param isCurrentSite Whether the site is current site.
|
||||
* @returns Whether it's clickable.
|
||||
*/
|
||||
isSiteClickable(isCurrentSite: boolean): boolean {
|
||||
return isCurrentSite ? this.currentSiteClickable ?? this.sitesClickable : this.sitesClickable;
|
||||
}
|
||||
|
||||
/**
|
||||
* A site was clicked.
|
||||
*
|
||||
* @param ev Event.
|
||||
* @param site Site clicked.
|
||||
* @param isCurrentSite Whether the site is current site.
|
||||
*/
|
||||
siteClicked(ev: Event, site: T, isCurrentSite: boolean): void {
|
||||
if (!this.isSiteClickable(isCurrentSite)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
this.onSiteClicked.emit(site);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,8 @@ import { CoreComponentsModule } from '@components/components.module';
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { CoreCourseImageCardsPageComponent } from '@components/stories/components/course-image-cards-page/course-image-cards-page';
|
||||
import { CoreCourseImageListPageComponent } from '@components/stories/components/course-image-list-page/course-image-list-page';
|
||||
import { CoreSitesListWrapperComponent } from './sites-list-wrapper/sites-list-wrapper';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -28,10 +30,12 @@ import { CoreCourseImageListPageComponent } from '@components/stories/components
|
|||
CoreCourseImageListPageComponent,
|
||||
CoreEmptyBoxPageComponent,
|
||||
CoreEmptyBoxWrapperComponent,
|
||||
CoreSitesListWrapperComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
StorybookModule,
|
||||
CoreDirectivesModule,
|
||||
CoreComponentsModule,
|
||||
CoreSearchComponentsModule,
|
||||
],
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<ion-app>
|
||||
<ion-content class="limited-width">
|
||||
<core-sites-list *ngIf="accountsList" [accountsList]="accountsList" [sitesClickable]="sitesClickable"
|
||||
[currentSiteClickable]="currentSiteClickable" (onSiteClicked)="siteClicked($event)">
|
||||
|
||||
<ng-template *ngIf="extraText !== 'none'" #siteLabel let-site="site">
|
||||
<p *ngIf="extraText === 'text'">Extra text for user {{ site.fullname }}</p>
|
||||
<ion-badge *ngIf="extraText === 'badge'" color="light">{{ site.badge }} MB</ion-badge>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #siteItem let-site="site">
|
||||
<ion-button *ngIf="extraDetails === 'delete-button'" fill="clear" color="danger" slot="end">
|
||||
<ion-icon name="fas-trash" slot="icon-only"></ion-icon>
|
||||
</ion-button>
|
||||
|
||||
<ion-badge *ngIf="extraDetails === 'badge'" slot="end">
|
||||
<span>{{site.badge}}</span>
|
||||
</ion-badge>
|
||||
</ng-template>
|
||||
|
||||
</core-sites-list>
|
||||
</ion-content>
|
||||
</ion-app>
|
|
@ -0,0 +1,60 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { CoreAccountsList, CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreSiteBasicInfo } from '@services/sites';
|
||||
|
||||
@Component({
|
||||
selector: 'core-sites-list-wrapper',
|
||||
templateUrl: 'sites-list-wrapper.html',
|
||||
})
|
||||
export class CoreSitesListWrapperComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() sitesClickable = false;
|
||||
@Input() currentSiteClickableSelect = 'undefined';
|
||||
@Input() extraText: 'text' | 'badge' | 'none' = 'none';
|
||||
@Input() extraDetails: 'delete-button' | 'badge' | 'none' = 'none';
|
||||
|
||||
accountsList?: CoreAccountsList;
|
||||
currentSiteClickable?: boolean;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnChanges(changes: SimpleChanges): Promise<void> {
|
||||
if (changes.currentSiteClickableSelect) {
|
||||
this.currentSiteClickable = this.currentSiteClickableSelect === 'undefined' ?
|
||||
undefined :
|
||||
this.currentSiteClickableSelect === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Site clicked.
|
||||
*
|
||||
* @param site Site.
|
||||
*/
|
||||
siteClicked(site: CoreSiteBasicInfo): void {
|
||||
alert(`clicked on ${site.id} - ${site.fullname}`);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Meta, moduleMetadata } from '@storybook/angular';
|
||||
|
||||
import { story } from '@/storybook/utils/helpers';
|
||||
import { CoreSitesListComponent } from '@components/sites-list/sites-list';
|
||||
import { CoreSitesListWrapperComponent } from './components/sites-list-wrapper/sites-list-wrapper';
|
||||
import { CoreComponentsStorybookModule } from './components/components.module';
|
||||
|
||||
interface Args {
|
||||
sitesClickable: boolean;
|
||||
currentSiteClickable: 'true' | 'false' | 'undefined';
|
||||
extraText: 'text' | 'badge' | 'none';
|
||||
extraDetails: 'delete-button' | 'badge' | 'none';
|
||||
}
|
||||
|
||||
export default <Meta<Args>> {
|
||||
title: 'Core/Sites List',
|
||||
component: CoreSitesListComponent,
|
||||
decorators: [
|
||||
moduleMetadata({ imports: [CoreComponentsStorybookModule] }),
|
||||
],
|
||||
argTypes: {
|
||||
sitesClickable: {
|
||||
control: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
currentSiteClickable: {
|
||||
control: {
|
||||
type: 'select',
|
||||
options: ['true', 'false', 'undefined'],
|
||||
},
|
||||
},
|
||||
extraText: {
|
||||
control: {
|
||||
type: 'select',
|
||||
options: ['text', 'badge', 'none'],
|
||||
},
|
||||
},
|
||||
extraDetails: {
|
||||
control: {
|
||||
type: 'select',
|
||||
options: ['delete-button', 'badge', 'none'],
|
||||
},
|
||||
},
|
||||
},
|
||||
args: {
|
||||
sitesClickable: false,
|
||||
currentSiteClickable: 'undefined',
|
||||
extraText: 'none',
|
||||
extraDetails: 'none',
|
||||
},
|
||||
};
|
||||
|
||||
const Template = story<Args>(({ sitesClickable, currentSiteClickable, extraText, extraDetails }) => ({
|
||||
component: CoreSitesListWrapperComponent,
|
||||
props: {
|
||||
sitesClickable,
|
||||
currentSiteClickableSelect: currentSiteClickable,
|
||||
extraText,
|
||||
extraDetails,
|
||||
},
|
||||
}));
|
||||
|
||||
export const Primary = story<Args>(Template);
|
|
@ -27,7 +27,7 @@
|
|||
<p>
|
||||
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
||||
</p>
|
||||
<p>{{site.siteUrl}}</p>
|
||||
<p *ngIf="!site.isDemoModeSite">{{site.siteUrl}}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -16,7 +16,7 @@ import { NgModule } from '@angular/core';
|
|||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreLoginSiteOnboardingComponent } from './site-onboarding/site-onboarding';
|
||||
import { CoreLoginSiteHelpComponent } from './site-help/site-help';
|
||||
import { CoreLoginSitesComponent } from './sites/sites';
|
||||
import { CoreLoginSitesModalComponent } from './sites-modal/sites-modal';
|
||||
import { CoreLoginMethodsComponent } from './login-methods/login-methods';
|
||||
import { CoreLoginExceededAttemptsComponent } from '@features/login/components/exceeded-attempts/exceeded-attempts';
|
||||
|
||||
|
@ -25,7 +25,7 @@ import { CoreLoginExceededAttemptsComponent } from '@features/login/components/e
|
|||
CoreLoginExceededAttemptsComponent,
|
||||
CoreLoginSiteOnboardingComponent,
|
||||
CoreLoginSiteHelpComponent,
|
||||
CoreLoginSitesComponent,
|
||||
CoreLoginSitesModalComponent,
|
||||
CoreLoginMethodsComponent,
|
||||
],
|
||||
imports: [
|
||||
|
@ -35,7 +35,7 @@ import { CoreLoginExceededAttemptsComponent } from '@features/login/components/e
|
|||
CoreLoginExceededAttemptsComponent,
|
||||
CoreLoginSiteOnboardingComponent,
|
||||
CoreLoginSiteHelpComponent,
|
||||
CoreLoginSitesComponent,
|
||||
CoreLoginSitesModalComponent,
|
||||
CoreLoginMethodsComponent,
|
||||
],
|
||||
})
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button fill="clear" (click)="close($event)" [attr.aria-label]="'core.back' | translate" class="ion-back-button">
|
||||
<ion-icon ios="chevron-back" md="arrow-back-sharp" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
|
||||
<ion-title>
|
||||
<h1>{{ 'core.mainmenu.switchaccount' | translate }}</h1>
|
||||
</ion-title>
|
||||
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" *ngIf="accountsList.count > 1" (click)="toggleDelete()"
|
||||
[attr.aria-label]="'core.login.toggleremove' | translate">
|
||||
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<core-sites-list [accountsList]="accountsList" [sitesClickable]="true" [currentSiteClickable]="false"
|
||||
(onSiteClicked)="login($event)">
|
||||
<ng-template #siteItem let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
<ion-icon *ngIf="isCurrentSite" color="success" name="fas-check"></ion-icon>
|
||||
|
||||
<ng-container *ngIf="!isCurrentSite">
|
||||
<ion-badge slot="end" *ngIf="!showDelete && site.badge" @coreShowHideAnimation>
|
||||
<span aria-hidden="true">{{site.badge}}</span>
|
||||
<span class="sr-only">{{ 'core.login.sitebadgedescription' | translate:{ count: site.badge }
|
||||
}}</span>
|
||||
</ion-badge>
|
||||
<ion-button *ngIf="showDelete" slot="end" fill="clear" color="danger" (click)="deleteSite($event, site)"
|
||||
[attr.aria-label]="'core.login.removeaccount' | translate" [@coreSlideInOut]="'fromRight'">
|
||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</core-sites-list>
|
||||
</core-loading>
|
||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end">
|
||||
<ion-fab-button (click)="add($event)" [attr.aria-label]="'core.login.add' | translate">
|
||||
<ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
|
||||
<span class="sr-only">{{ 'core.login.add' | translate }}</span>
|
||||
</ion-fab-button>
|
||||
</ion-fab>
|
||||
</ion-content>
|
|
@ -23,15 +23,14 @@ import { CoreAnimations } from '@components/animations';
|
|||
import { ModalController } from '@singletons';
|
||||
|
||||
/**
|
||||
* Component that displays a "splash screen" while the app is being initialized.
|
||||
* Modal that displays a list of sites to be able to enter or delete a site.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-login-sites',
|
||||
templateUrl: 'sites.html',
|
||||
styleUrls: ['../../sitelist.scss'],
|
||||
selector: 'core-login-sites-modal',
|
||||
templateUrl: 'sites-modal.html',
|
||||
animations: [CoreAnimations.SLIDE_IN_OUT, CoreAnimations.SHOW_HIDE],
|
||||
})
|
||||
export class CoreLoginSitesComponent implements OnInit {
|
||||
export class CoreLoginSitesModalComponent implements OnInit {
|
||||
|
||||
accountsList: CoreAccountsList = {
|
||||
sameSite: [],
|
||||
|
@ -51,7 +50,7 @@ export class CoreLoginSitesComponent implements OnInit {
|
|||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList(this.currentSiteId);
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList();
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
|
@ -99,15 +98,14 @@ export class CoreLoginSitesComponent implements OnInit {
|
|||
/**
|
||||
* Login in a site.
|
||||
*
|
||||
* @param event Click event.
|
||||
* @param siteId The site ID.
|
||||
* @param site The site.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async login(event: Event, siteId: string): Promise<void> {
|
||||
await this.close(event, true);
|
||||
async login(site: CoreSiteBasicInfo): Promise<void> {
|
||||
await this.close(undefined, true);
|
||||
|
||||
// This navigation will logout and navigate to the site home.
|
||||
await CoreNavigator.navigateToSiteHome({ preferCurrentTab: false , siteId });
|
||||
await CoreNavigator.navigateToSiteHome({ preferCurrentTab: false , siteId: site.id });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,9 +120,9 @@ export class CoreLoginSitesComponent implements OnInit {
|
|||
*
|
||||
* @param event Click event.
|
||||
*/
|
||||
async close(event: Event, closeAll = false): Promise<void> {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
async close(event?: Event, closeAll = false): Promise<void> {
|
||||
event?.preventDefault();
|
||||
event?.stopPropagation();
|
||||
|
||||
await ModalController.dismiss(closeAll);
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button fill="clear" (click)="close($event)" [attr.aria-label]="'core.back' | translate" class="ion-back-button">
|
||||
<ion-icon ios="chevron-back" md="arrow-back-sharp" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
|
||||
<ion-title>
|
||||
<h1>{{ 'core.mainmenu.switchaccount' | translate }}</h1>
|
||||
</ion-title>
|
||||
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" *ngIf="accountsList.count > 1" (click)="toggleDelete()"
|
||||
[attr.aria-label]="'core.login.toggleremove' | translate">
|
||||
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<ion-list class="core-sitelist">
|
||||
<ion-card *ngIf="accountsList.currentSite">
|
||||
<ion-item-divider sticky="true" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="accountsList.currentSite.siteName" clean="true"
|
||||
[siteId]="accountsList.currentSite.id"></core-format-text>
|
||||
</h2>
|
||||
<p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{
|
||||
accountsList.currentSite.siteUrlWithoutProtocol }}</a>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-item detail="false">
|
||||
<core-user-avatar [user]="accountsList.currentSite" slot="start" [linkProfile]="false"
|
||||
[siteId]="accountsList.currentSite.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{accountsList.currentSite.fullname}}</p>
|
||||
</ion-label>
|
||||
<ion-icon color="success" name="fas-check"></ion-icon>
|
||||
</ion-item>
|
||||
|
||||
<ng-container *ngTemplateOutlet="siteList; context: {sites: accountsList.sameSite}"></ng-container>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngFor="let sites of accountsList.otherSites">
|
||||
<ion-item-divider sticky="true" *ngIf="sites[0]" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
|
||||
</h2>
|
||||
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ng-container *ngTemplateOutlet="siteList; context: {sites: sites}"></ng-container>
|
||||
</ion-card>
|
||||
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end">
|
||||
<ion-fab-button (click)="add($event)" [attr.aria-label]="'core.login.add' | translate">
|
||||
<ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
|
||||
<span class="sr-only">{{ 'core.login.add' | translate }}</span>
|
||||
</ion-fab-button>
|
||||
</ion-fab>
|
||||
</ion-content>
|
||||
|
||||
<!-- Template to render a list of sites. -->
|
||||
<ng-template #siteList let-sites="sites">
|
||||
<ion-item button *ngFor="let site of sites" (click)="login($event, site.id)" detail="true">
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
</ion-label>
|
||||
<ion-badge slot="end" *ngIf="!showDelete && site.badge" @coreShowHideAnimation>
|
||||
<span aria-hidden="true">{{site.badge}}</span>
|
||||
<span class="sr-only">{{ 'core.login.sitebadgedescription' | translate:{ count: site.badge }
|
||||
}}</span>
|
||||
</ion-badge>
|
||||
<ion-button *ngIf="showDelete" slot="end" fill="clear" color="danger" (click)="deleteSite($event, site)"
|
||||
[attr.aria-label]="'core.login.removeaccount' | translate" [@coreSlideInOut]="'fromRight'">
|
||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</ng-template>
|
|
@ -32,7 +32,7 @@
|
|||
<h2 *ngIf="siteName" class="ion-margin-top ion-no-padding core-sitename">
|
||||
<core-format-text [text]="siteName" [filter]="false"></core-format-text>
|
||||
</h2>
|
||||
<p class="core-siteurl">{{siteUrl}}</p>
|
||||
<p class="core-siteurl" *ngIf="!isDemoModeSite">{{siteUrl}}</p>
|
||||
</div>
|
||||
|
||||
<core-login-exceeded-attempts *ngIf="exceededAttemptsHTML && supportConfig && loginAttempts >= 3"
|
||||
|
|
|
@ -61,6 +61,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
exceededAttemptsHTML?: SafeHtml | string | null;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
siteCheckError = '';
|
||||
isDemoModeSite = false;
|
||||
|
||||
protected siteCheck?: CoreSiteCheckResponse;
|
||||
protected eventThrown = false;
|
||||
|
@ -89,8 +90,11 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
this.siteConfig = this.siteCheck.config;
|
||||
}
|
||||
|
||||
this.siteName = CoreNavigator.getRouteParam('siteName');
|
||||
this.logoUrl = !CoreConstants.CONFIG.forceLoginLogo && CoreNavigator.getRouteParam('logoUrl') || undefined;
|
||||
this.isDemoModeSite = CoreLoginHelper.isDemoModeSite(this.siteUrl);
|
||||
this.siteName = this.isDemoModeSite ? CoreConstants.CONFIG.appname : CoreNavigator.getRouteParam('siteName');
|
||||
this.logoUrl = !CoreConstants.CONFIG.forceLoginLogo && !this.isDemoModeSite ?
|
||||
CoreNavigator.getRouteParam('logoUrl') :
|
||||
undefined;
|
||||
this.urlToOpen = CoreNavigator.getRouteParam('urlToOpen');
|
||||
this.supportConfig = this.siteConfig && new CoreUserGuestSupportConfig(this.siteConfig);
|
||||
} catch (error) {
|
||||
|
@ -191,9 +195,13 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
|
||||
this.siteName = this.siteConfig.sitename;
|
||||
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
|
||||
if (this.isDemoModeSite) {
|
||||
this.showScanQR = false;
|
||||
} else {
|
||||
this.siteName = this.siteConfig.sitename;
|
||||
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
|
||||
}
|
||||
|
||||
const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
|
||||
this.canSignup = this.siteConfig.registerauth == 'email' &&
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<ion-item class="ion-text-wrap ion-text-center">
|
||||
<ion-label>
|
||||
<!-- If no sitename show big siteurl. -->
|
||||
<p *ngIf="!siteName" class="ion-padding item-heading">{{siteUrl}}</p>
|
||||
<p *ngIf="!siteName && !isDemoModeSite" class="ion-padding item-heading">{{siteUrl}}</p>
|
||||
<!-- If sitename, show big sitename and small siteurl. -->
|
||||
<p *ngIf="siteName" class="ion-padding item-heading">
|
||||
<core-format-text [text]="siteName" [filter]="false"></core-format-text>
|
||||
|
|
|
@ -34,6 +34,7 @@ import { CoreForms } from '@singletons/form';
|
|||
import { CoreRecaptchaComponent } from '@components/recaptcha/recaptcha';
|
||||
import { CorePath } from '@singletons/path';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
||||
/**
|
||||
* Page to signup using email.
|
||||
|
@ -51,6 +52,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
|
||||
signupForm: FormGroup;
|
||||
siteUrl!: string;
|
||||
isDemoModeSite = false;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
siteName?: string;
|
||||
authInstructions = '';
|
||||
|
@ -127,6 +129,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
}
|
||||
|
||||
this.siteUrl = siteUrl;
|
||||
this.isDemoModeSite = CoreLoginHelper.isDemoModeSite(this.siteUrl);
|
||||
|
||||
// Fetch the data.
|
||||
this.fetchData().finally(() => {
|
||||
|
@ -235,7 +238,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
*/
|
||||
protected treatSiteConfig(): boolean {
|
||||
if (this.siteConfig?.registerauth == 'email' && !CoreLoginHelper.isEmailSignupDisabled(this.siteConfig)) {
|
||||
this.siteName = this.siteConfig.sitename;
|
||||
this.siteName = this.isDemoModeSite ? CoreConstants.CONFIG.appname : this.siteConfig.sitename;
|
||||
this.authInstructions = this.siteConfig.authinstructions;
|
||||
this.ageDigitalConsentVerification = this.siteConfig.agedigitalconsentverification;
|
||||
this.supportName = this.siteConfig.supportname;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<p *ngIf="siteInfo?.siteName" class="ion-no-margin ion-no-padding core-sitename">
|
||||
<core-format-text [text]="siteInfo?.siteName" [filter]="false"></core-format-text>
|
||||
</p>
|
||||
<p class="core-siteurl">{{siteUrl}}</p>
|
||||
<p class="core-siteurl" *ngIf="!isDemoModeSite">{{siteUrl}}</p>
|
||||
</div>
|
||||
|
||||
<div class="core-login-user">
|
||||
|
|
|
@ -46,6 +46,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
|
||||
credForm: FormGroup;
|
||||
siteUrl!: string;
|
||||
isDemoModeSite = false;
|
||||
logoUrl?: string;
|
||||
showForgottenPassword = true;
|
||||
showUserAvatar = false;
|
||||
|
@ -101,6 +102,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.siteUrl = site.getURL();
|
||||
this.isDemoModeSite = site.isDemoModeSite();
|
||||
|
||||
this.siteInfo = {
|
||||
id: this.siteId,
|
||||
|
@ -112,6 +114,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
siteName: await site.getSiteName(),
|
||||
userpictureurl: site.infos.userpictureurl,
|
||||
loggedOut: true, // Not used.
|
||||
isDemoModeSite: this.isDemoModeSite,
|
||||
};
|
||||
|
||||
this.username = site.infos.username;
|
||||
|
@ -185,7 +188,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
|
||||
await CoreSites.checkApplication(this.siteConfig);
|
||||
|
||||
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||
this.logoUrl = this.isDemoModeSite ? undefined : CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,35 +21,19 @@
|
|||
</ion-header>
|
||||
<ion-content class="limited-width">
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<ion-list class="core-sitelist">
|
||||
<ion-card *ngFor="let sites of accountsList.otherSites">
|
||||
<ion-item-divider sticky="true" *ngIf="sites[0]" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
|
||||
</h2>
|
||||
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-item button *ngFor="let site of sites" (click)="login($event, site.id)" detail="true">
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
</ion-label>
|
||||
<ion-badge slot="end" *ngIf="!showDelete && site.badge" @coreShowHideAnimation>
|
||||
<span aria-hidden="true">{{site.badge}}</span>
|
||||
<span class="sr-only">{{ 'core.login.sitebadgedescription' | translate:{ count: site.badge }
|
||||
}}</span>
|
||||
</ion-badge>
|
||||
<ion-button *ngIf="showDelete" slot="end" fill="clear" color="danger" (click)="deleteSite($event, site)"
|
||||
[attr.aria-label]="'core.login.removeaccount' | translate" [@coreSlideInOut]="'fromRight'">
|
||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
</ion-list>
|
||||
<core-sites-list [accountsList]="accountsList" [sitesClickable]="true" (onSiteClicked)="login($event)">
|
||||
<ng-template #siteItem let-site="site" let-isCurrentSite="isCurrentSite">
|
||||
<ion-badge slot="end" *ngIf="!showDelete && site.badge" @coreShowHideAnimation>
|
||||
<span aria-hidden="true">{{site.badge}}</span>
|
||||
<span class="sr-only">{{ 'core.login.sitebadgedescription' | translate:{ count: site.badge }
|
||||
}}</span>
|
||||
</ion-badge>
|
||||
<ion-button *ngIf="showDelete" slot="end" fill="clear" color="danger" (click)="deleteSite($event, site)"
|
||||
[attr.aria-label]="'core.login.removeaccount' | translate" [@coreSlideInOut]="'fromRight'">
|
||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
</core-sites-list>
|
||||
</core-loading>
|
||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end">
|
||||
<ion-fab-button (click)="add()" [attr.aria-label]="'core.login.add' | translate">
|
||||
|
|
|
@ -22,12 +22,11 @@ import { CoreFilter } from '@features/filter/services/filter';
|
|||
import { CoreAnimations } from '@components/animations';
|
||||
|
||||
/**
|
||||
* Page that displays a "splash screen" while the app is being initialized.
|
||||
* Page that displays the list of sites stored in the device.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-core-login-sites',
|
||||
templateUrl: 'sites.html',
|
||||
styleUrls: ['../../sitelist.scss'],
|
||||
animations: [CoreAnimations.SLIDE_IN_OUT, CoreAnimations.SHOW_HIDE],
|
||||
})
|
||||
export class CoreLoginSitesPage implements OnInit {
|
||||
|
@ -102,18 +101,14 @@ export class CoreLoginSitesPage implements OnInit {
|
|||
/**
|
||||
* Login in a site.
|
||||
*
|
||||
* @param event Click event.
|
||||
* @param siteId The site ID.
|
||||
* @param site The site.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async login(event: Event, siteId: string): Promise<void> {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
async login(site: CoreSiteBasicInfo): Promise<void> {
|
||||
const modal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
try {
|
||||
const loggedIn = await CoreSites.loadSite(siteId);
|
||||
const loggedIn = await CoreSites.loadSite(site.id);
|
||||
|
||||
if (loggedIn) {
|
||||
await CoreNavigator.navigateToSiteHome();
|
||||
|
|
|
@ -374,14 +374,23 @@ export class CoreLoginHelperProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get Available sites (includes staging sites if are enabled).
|
||||
* Get Available sites (includes staging sites if are enabled). It doesn't include demo mode site.
|
||||
*
|
||||
* @returns Available sites.
|
||||
*/
|
||||
async getAvailableSites(): Promise<CoreLoginSiteInfo[]> {
|
||||
const hasEnabledStagingSites = await CoreSettingsHelper.hasEnabledStagingSites();
|
||||
|
||||
return hasEnabledStagingSites ? CoreConstants.CONFIG.sites : CoreConstants.CONFIG.sites.filter(site => !site.staging);
|
||||
return CoreConstants.CONFIG.sites.filter(site => (!site.staging || hasEnabledStagingSites) && !site.demoMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get demo mode site info. This function doesn't check if demo mode is enabled.
|
||||
*
|
||||
* @returns Demo mode site info, undefined if no demo mode site.
|
||||
*/
|
||||
getDemoModeSiteInfo(): CoreLoginSiteInfo | undefined {
|
||||
return CoreConstants.CONFIG.sites.find(site => site.demoMode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -453,6 +462,14 @@ export class CoreLoginHelperProvider {
|
|||
* @returns Path and params.
|
||||
*/
|
||||
async getAddSiteRouteInfo(showKeyboard?: boolean): Promise<[string, Params]> {
|
||||
if (CoreConstants.CONFIG.demoMode) {
|
||||
const demoModeSite = this.getDemoModeSiteInfo();
|
||||
|
||||
if (demoModeSite) {
|
||||
return ['/login/credentials', { siteUrl: demoModeSite.url }];
|
||||
}
|
||||
}
|
||||
|
||||
const sites = await this.getAvailableSites();
|
||||
|
||||
if (sites.length === 1) {
|
||||
|
@ -583,7 +600,10 @@ export class CoreLoginHelperProvider {
|
|||
const sites = await this.getAvailableSites();
|
||||
|
||||
if (sites.length) {
|
||||
return sites.some((site) => CoreUrl.sameDomainAndPath(siteUrl, site.url));
|
||||
const demoModeSite = this.getDemoModeSiteInfo();
|
||||
|
||||
return sites.some((site) => CoreUrl.sameDomainAndPath(siteUrl, site.url)) ||
|
||||
(!!demoModeSite && CoreUrl.sameDomainAndPath(siteUrl, demoModeSite.url));
|
||||
} else if (CoreConstants.CONFIG.multisitesdisplay == 'sitefinder' && CoreConstants.CONFIG.onlyallowlistedsites &&
|
||||
checkSiteFinder) {
|
||||
// Call the sites finder to validate the site.
|
||||
|
@ -1281,10 +1301,9 @@ export class CoreLoginHelperProvider {
|
|||
/**
|
||||
* Get the accounts list classified per site.
|
||||
*
|
||||
* @param currentSiteId If loggedin, current Site Id.
|
||||
* @returns Promise resolved with account list.
|
||||
*/
|
||||
async getAccountsList(currentSiteId?: string): Promise<CoreAccountsList> {
|
||||
async getAccountsList(): Promise<CoreAccountsList> {
|
||||
const sites = await CoreUtils.ignoreErrors(CoreSites.getSortedSites(), [] as CoreSiteBasicInfo[]);
|
||||
|
||||
const accountsList: CoreAccountsList = {
|
||||
|
@ -1292,14 +1311,11 @@ export class CoreLoginHelperProvider {
|
|||
otherSites: [],
|
||||
count: sites.length,
|
||||
};
|
||||
|
||||
const currentSiteId = CoreSites.getCurrentSiteId();
|
||||
let siteUrl = '';
|
||||
|
||||
if (currentSiteId) {
|
||||
const index = sites.findIndex((site) => site.id == currentSiteId);
|
||||
|
||||
accountsList.currentSite = sites.splice(index, 1)[0];
|
||||
siteUrl = accountsList.currentSite.siteUrlWithoutProtocol;
|
||||
siteUrl = sites.find((site) => site.id == currentSiteId)?.siteUrlWithoutProtocol ?? '';
|
||||
}
|
||||
|
||||
const otherSites: Record<string, CoreSiteBasicInfo[]> = {};
|
||||
|
@ -1308,7 +1324,9 @@ export class CoreLoginHelperProvider {
|
|||
await Promise.all(sites.map(async (site) => {
|
||||
site.badge = await CoreUtils.ignoreErrors(CorePushNotifications.getSiteCounter(site.id)) || 0;
|
||||
|
||||
if (site.siteUrlWithoutProtocol == siteUrl) {
|
||||
if (site.id === currentSiteId) {
|
||||
accountsList.currentSite = site;
|
||||
} else if (site.siteUrlWithoutProtocol == siteUrl) {
|
||||
accountsList.sameSite.push(site);
|
||||
} else {
|
||||
if (!otherSites[site.siteUrlWithoutProtocol]) {
|
||||
|
@ -1497,6 +1515,23 @@ export class CoreLoginHelperProvider {
|
|||
return CoreTextUtils.parseJSON<Record<string, number>>(passwordResetsJson, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL belongs to the demo mode site.
|
||||
*
|
||||
* @returns Whether the URL belongs to the demo mode site.
|
||||
*/
|
||||
isDemoModeSite(url: string): boolean {
|
||||
const demoSiteData = CoreLoginHelper.getDemoModeSiteInfo();
|
||||
if (!demoSiteData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const demoSiteUrl = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(demoSiteData.url));
|
||||
url = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url));
|
||||
|
||||
return demoSiteUrl.indexOf(url) === 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const CoreLoginHelper = makeSingleton(CoreLoginHelperProvider);
|
||||
|
@ -1504,10 +1539,10 @@ export const CoreLoginHelper = makeSingleton(CoreLoginHelperProvider);
|
|||
/**
|
||||
* Accounts list for selecting sites interfaces.
|
||||
*/
|
||||
export type CoreAccountsList = {
|
||||
currentSite?: CoreSiteBasicInfo; // If logged in, current site info.
|
||||
sameSite: CoreSiteBasicInfo[]; // If logged in, accounts info on the same site.
|
||||
otherSites: CoreSiteBasicInfo[][]; // Other accounts in other sites.
|
||||
export type CoreAccountsList<T extends CoreSiteBasicInfo = CoreSiteBasicInfo> = {
|
||||
currentSite?: T; // If logged in, current site info.
|
||||
sameSite: T[]; // If logged in, accounts info on the same site.
|
||||
otherSites: T[][]; // Other accounts in other sites.
|
||||
count: number; // Number of sites.
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { CoreConstants } from '@/core/constants';
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { CoreSite, CoreSiteInfo } from '@classes/site';
|
||||
import { CoreFilter } from '@features/filter/services/filter';
|
||||
import { CoreLoginSitesComponent } from '@features/login/components/sites/sites';
|
||||
import { CoreLoginSitesModalComponent } from '@features/login/components/sites-modal/sites-modal';
|
||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
|
@ -113,7 +113,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
protected async loadSiteLogo(currentSite: CoreSite): Promise<void> {
|
||||
if (CoreConstants.CONFIG.forceLoginLogo) {
|
||||
if (CoreConstants.CONFIG.forceLoginLogo || currentSite.isDemoModeSite()) {
|
||||
this.siteLogo = 'assets/img/login_logo.png';
|
||||
this.siteLogoLoaded = true;
|
||||
|
||||
|
@ -239,7 +239,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
|
|||
event.stopPropagation();
|
||||
|
||||
const closeAll = await CoreDomUtils.openSideModal<boolean>({
|
||||
component: CoreLoginSitesComponent,
|
||||
component: CoreLoginSitesModalComponent,
|
||||
cssClass: 'core-modal-lateral core-modal-lateral-sm',
|
||||
});
|
||||
|
||||
|
|
|
@ -17,43 +17,21 @@
|
|||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<ion-list class="core-sitelist limited-width">
|
||||
<ion-card *ngIf="accountsList.currentSite">
|
||||
<ion-item-divider sticky="true" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="accountsList.currentSite.siteName" clean="true"
|
||||
[siteId]="accountsList.currentSite.id"></core-format-text>
|
||||
</p>
|
||||
<p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{
|
||||
accountsList.currentSite.siteUrlWithoutProtocol }}</a>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
<ion-list class="limited-width">
|
||||
<core-sites-list [accountsList]="accountsList">
|
||||
<ng-template #siteLabel let-site="site">
|
||||
<ion-badge color="light" *ngIf="site.spaceUsage !== undefined">{{ site.spaceUsage | coreBytesToSize }}</ion-badge>
|
||||
</ng-template>
|
||||
|
||||
<ion-item class="item-current">
|
||||
<ng-container *ngTemplateOutlet="siteUsage; context: {site: accountsList.currentSite}"></ng-container>
|
||||
</ion-item>
|
||||
|
||||
<ion-item *ngFor="let site of accountsList.sameSite">
|
||||
<ng-container *ngTemplateOutlet="siteUsage; context: {site: site}"></ng-container>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngFor="let sites of accountsList.otherSites">
|
||||
<ion-item-divider sticky="true" *ngIf="sites[0]" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
|
||||
</p>
|
||||
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-item *ngFor="let site of sites">
|
||||
<ng-container *ngTemplateOutlet="siteUsage; context: {site: site}"></ng-container>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
<ng-template #siteItem let-site="site">
|
||||
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)"
|
||||
[hidden]="site.spaceUsage <= 0 && !site.hasCacheEntries">
|
||||
<ion-icon name="fas-trash" slot="icon-only"
|
||||
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: site.siteName }">
|
||||
</ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
</core-sites-list>
|
||||
|
||||
<ion-item-divider>
|
||||
<ion-label>
|
||||
|
@ -66,19 +44,3 @@
|
|||
</ion-list>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
|
||||
<!-- Template to render a site space usage. -->
|
||||
<ng-template #siteUsage let-site="site">
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label class="ion-text-wrap">
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
<ion-badge color="light" *ngIf="site.spaceUsage !== undefined">{{ site.spaceUsage | coreBytesToSize }}</ion-badge>
|
||||
</ion-label>
|
||||
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)"
|
||||
[hidden]="site.spaceUsage <= 0 && !site.hasCacheEntries">
|
||||
<ion-icon name="fas-trash" slot="icon-only"
|
||||
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: site.siteName }">
|
||||
</ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
|
|
|
@ -20,6 +20,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
|
||||
import { CoreSettingsHelper } from '../../services/settings-helper';
|
||||
import { CoreAccountsList } from '@features/login/services/login-helper';
|
||||
|
||||
/**
|
||||
* Page that displays the space usage settings.
|
||||
|
@ -33,9 +34,10 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy {
|
|||
loaded = false;
|
||||
totalSpaceUsage = 0;
|
||||
|
||||
accountsList: CoreAccountsListWithUsage = {
|
||||
accountsList: CoreAccountsList<CoreSiteBasicInfoWithUsage> = {
|
||||
sameSite: [],
|
||||
otherSites: [],
|
||||
count: 0,
|
||||
};
|
||||
|
||||
protected sitesObserver: CoreEventObserver;
|
||||
|
@ -128,6 +130,7 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy {
|
|||
});
|
||||
|
||||
this.accountsList.otherSites = CoreUtils.objectToArray(otherSites);
|
||||
this.accountsList.count = sites.length;
|
||||
|
||||
this.totalSpaceUsage = totalSize;
|
||||
}
|
||||
|
@ -192,12 +195,3 @@ interface CoreSiteBasicInfoWithUsage extends CoreSiteBasicInfo {
|
|||
hasCacheEntries: boolean; // If has cached entries that can be cleared.
|
||||
spaceUsage: number; // Space used in this site.
|
||||
}
|
||||
|
||||
/**
|
||||
* Accounts list for selecting sites interfaces.
|
||||
*/
|
||||
type CoreAccountsListWithUsage = {
|
||||
currentSite?: CoreSiteBasicInfoWithUsage; // If logged in, current site info.
|
||||
sameSite: CoreSiteBasicInfoWithUsage[]; // If logged in, accounts info on the same site.
|
||||
otherSites: CoreSiteBasicInfoWithUsage[][]; // Other accounts in other sites.
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</ion-header>
|
||||
<ion-content class="limited-width">
|
||||
<core-loading [hideUntil]="sitesLoaded">
|
||||
<ion-list class="core-sitelist limited-width">
|
||||
<ion-list class="limited-width">
|
||||
<ion-item-divider>
|
||||
<ion-label>
|
||||
<h2>{{ 'core.settings.syncsettings' | translate }}</h2>
|
||||
|
@ -51,61 +51,25 @@
|
|||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-card *ngIf="accountsList.currentSite">
|
||||
<ion-item-divider sticky="true" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="accountsList.currentSite.siteName" clean="true"
|
||||
[siteId]="accountsList.currentSite.id"></core-format-text>
|
||||
</p>
|
||||
<p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{
|
||||
accountsList.currentSite.siteUrlWithoutProtocol }}</a>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
<core-sites-list [accountsList]="accountsList">
|
||||
<ng-template #siteLabel let-site="site">
|
||||
<p class="text-danger" *ngIf="site.loggedOut">{{ 'core.settings.logintosync' | translate }}</p>
|
||||
</ng-template>
|
||||
|
||||
<ion-item class="item-current">
|
||||
<ng-container *ngTemplateOutlet="siteSync; context: {site: accountsList.currentSite}"></ng-container>
|
||||
</ion-item>
|
||||
|
||||
<ion-item *ngFor="let site of accountsList.sameSite">
|
||||
<ng-container *ngTemplateOutlet="siteSync; context: {site: site}"></ng-container>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngFor="let sites of accountsList.otherSites">
|
||||
<ion-item-divider sticky="true" *ngIf="sites[0]" class="core-sitelist-sitename">
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
|
||||
</p>
|
||||
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-item *ngFor="let site of sites">
|
||||
<ng-container *ngTemplateOutlet="siteSync; context: {site: site}"></ng-container>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
<ng-template #siteItem let-site="site">
|
||||
<core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end" *ngIf="!site.loggedOut">
|
||||
<ion-button fill="clear" (click)="synchronize(site.id)"
|
||||
[attr.aria-label]="'core.settings.synchronizenow' | translate">
|
||||
<ion-icon name="fas-rotate" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</core-button-with-spinner>
|
||||
<ion-button fill="clear" (click)="login(site.id)" [attr.aria-label]="'core.login.login' | translate"
|
||||
*ngIf="site.loggedOut" slot="end">
|
||||
<ion-icon name="fas-right-to-bracket" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
</core-sites-list>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
|
||||
<!-- Template to render a site to sync. -->
|
||||
<ng-template #siteSync let-site="site">
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
<p class="text-danger" *ngIf="site.loggedOut">{{ 'core.settings.logintosync' | translate }}</p>
|
||||
</ion-label>
|
||||
<core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end" *ngIf="!site.loggedOut">
|
||||
<ion-button fill="clear" (click)="synchronize(site.id)" [attr.aria-label]="'core.settings.synchronizenow' | translate">
|
||||
<ion-icon name="fas-rotate" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</core-button-with-spinner>
|
||||
<ion-button fill="clear" (click)="login(site.id)" [attr.aria-label]="'core.login.login' | translate" *ngIf="site.loggedOut" slot="end">
|
||||
<ion-icon name="fas-right-to-bracket" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
|
|
|
@ -32,7 +32,6 @@ import { CoreNavigator } from '@services/navigator';
|
|||
@Component({
|
||||
selector: 'page-core-app-settings-synchronization',
|
||||
templateUrl: 'synchronization.html',
|
||||
styleUrls: ['../../../login/sitelist.scss'],
|
||||
})
|
||||
export class CoreSettingsSynchronizationPage implements OnInit, OnDestroy {
|
||||
|
||||
|
@ -105,10 +104,8 @@ export class CoreSettingsSynchronizationPage implements OnInit, OnDestroy {
|
|||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
const currentSiteId = CoreSites.getCurrentSiteId();
|
||||
|
||||
try {
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList(currentSiteId);
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList();
|
||||
} catch {
|
||||
// Ignore errors.
|
||||
}
|
||||
|
|
|
@ -17,17 +17,8 @@
|
|||
<p>{{fileName}}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item *ngFor="let site of sites" (click)="storeInSite(site.id)" detail="false" button>
|
||||
<core-user-avatar [user]="site" slot="start" [linkProfile]="false" [siteId]="site.id"></core-user-avatar>
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{site.fullname}}</p>
|
||||
<p>
|
||||
<core-format-text clean="true" [text]="site.siteName" [siteId]="site.id"></core-format-text>
|
||||
</p>
|
||||
<p>{{site.siteUrl}}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<core-sites-list [accountsList]="accountsList" [sitesClickable]="true" (onSiteClicked)="storeInSite($event)">
|
||||
</core-sites-list>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CoreAccountsList, CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreSharedFilesHelper } from '@features/sharedfiles/services/sharedfiles-helper';
|
||||
import { FileEntry } from '@ionic-native/file/ngx';
|
||||
import { CoreFile } from '@services/file';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSiteBasicInfo, CoreSites } from '@services/sites';
|
||||
import { CoreSiteBasicInfo } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
||||
/**
|
||||
|
@ -30,8 +31,12 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
export class CoreSharedFilesChooseSitePage implements OnInit {
|
||||
|
||||
fileName?: string;
|
||||
sites?: CoreSiteBasicInfo[];
|
||||
loaded = false;
|
||||
accountsList: CoreAccountsList = {
|
||||
sameSite: [],
|
||||
otherSites: [],
|
||||
count: 0,
|
||||
};
|
||||
|
||||
protected filePath?: string;
|
||||
protected fileEntry?: FileEntry;
|
||||
|
@ -89,15 +94,15 @@ export class CoreSharedFilesChooseSitePage implements OnInit {
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
protected async loadSites(): Promise<void> {
|
||||
this.sites = await CoreSites.getSites();
|
||||
this.accountsList = await CoreLoginHelper.getAccountsList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the file in a certain site.
|
||||
*
|
||||
* @param siteId Site ID.
|
||||
* @param site Site.
|
||||
*/
|
||||
async storeInSite(siteId: string): Promise<void> {
|
||||
async storeInSite(site: CoreSiteBasicInfo): Promise<void> {
|
||||
if (!this.fileEntry) {
|
||||
return;
|
||||
}
|
||||
|
@ -105,7 +110,7 @@ export class CoreSharedFilesChooseSitePage implements OnInit {
|
|||
this.loaded = false;
|
||||
|
||||
try {
|
||||
await CoreSharedFilesHelper.storeSharedFileInSite(this.fileEntry, siteId, this.isInbox);
|
||||
await CoreSharedFilesHelper.storeSharedFileInSite(this.fileEntry, site.id, this.isInbox);
|
||||
|
||||
CoreNavigator.back();
|
||||
} finally {
|
||||
|
|
|
@ -1300,11 +1300,24 @@ export class CoreSitesProvider {
|
|||
async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||
const sites = await this.sitesTable.getMany();
|
||||
|
||||
return this.siteDBRecordsToBasicInfo(sites, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert sites DB records to site basic info.
|
||||
*
|
||||
* @param sites DB records.
|
||||
* @param ids IDs of sites to return, undefined to return them all.
|
||||
* @returns Sites basic info.
|
||||
*/
|
||||
protected siteDBRecordsToBasicInfo(sites: SiteDBEntry[], ids?: string[]): CoreSiteBasicInfo[] {
|
||||
const formattedSites: CoreSiteBasicInfo[] = [];
|
||||
|
||||
sites.forEach((site) => {
|
||||
if (!ids || ids.indexOf(site.id) > -1) {
|
||||
// Parse info.
|
||||
const isDemoModeSite = CoreLoginHelper.isDemoModeSite(site.siteUrl);
|
||||
const siteInfo = site.info ? <CoreSiteInfo> CoreTextUtils.parseJSON(site.info) : undefined;
|
||||
|
||||
const basicInfo: CoreSiteBasicInfo = {
|
||||
id: site.id,
|
||||
siteUrl: site.siteUrl,
|
||||
|
@ -1312,10 +1325,11 @@ export class CoreSitesProvider {
|
|||
fullname: siteInfo?.fullname,
|
||||
firstname: siteInfo?.firstname,
|
||||
lastname: siteInfo?.lastname,
|
||||
siteName: siteInfo?.sitename,
|
||||
siteName: isDemoModeSite ? CoreConstants.CONFIG.appname : siteInfo?.sitename,
|
||||
userpictureurl: siteInfo?.userpictureurl,
|
||||
siteHomeId: siteInfo?.siteid || 1,
|
||||
loggedOut: !!site.loggedOut,
|
||||
isDemoModeSite,
|
||||
};
|
||||
formattedSites.push(basicInfo);
|
||||
}
|
||||
|
@ -2195,6 +2209,7 @@ export type CoreSiteBasicInfo = {
|
|||
badge?: number; // Badge to display in the site.
|
||||
siteHomeId?: number; // Site home ID.
|
||||
loggedOut: boolean; // If Site is logged out.
|
||||
isDemoModeSite: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2288,6 +2303,11 @@ export type CoreLoginSiteInfo = {
|
|||
* Class to apply to site item.
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Whether the site is for demo mode usage.
|
||||
*/
|
||||
demoMode?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,8 @@ import { CoreFilepoolProviderStub } from '@/storybook/stubs/services/filepool';
|
|||
import { CoreFilepoolProvider } from '@services/filepool';
|
||||
import { HttpClientStub } from '@/storybook/stubs/services/http';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CorePushNotificationsProviderStub } from './stubs/services/pushnotifications';
|
||||
|
||||
// For translate loader. AoT requires an exported function for factories.
|
||||
export class StaticTranslateLoader extends TranslateLoader {
|
||||
|
@ -56,6 +58,7 @@ export class StaticTranslateLoader extends TranslateLoader {
|
|||
{ provide: CoreSitesProvider, useClass: CoreSitesProviderStub },
|
||||
{ provide: CoreDbProvider, useClass: CoreDbProviderStub },
|
||||
{ provide: CoreFilepoolProvider, useClass: CoreFilepoolProviderStub },
|
||||
{ provide: CorePushNotificationsProvider, useClass: CorePushNotificationsProviderStub },
|
||||
{ provide: HttpClient, useClass: HttpClientStub },
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Sites provider stub.
|
||||
*/
|
||||
export class CorePushNotificationsProviderStub extends CorePushNotificationsProvider {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getSiteCounter(): Promise<number> {
|
||||
return Math.round(Math.random() * 100);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const CorePushNotificationsStub = makeSingleton<CorePushNotificationsProviderStub>(CorePushNotificationsProvider);
|
|
@ -12,9 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import school from '@/assets/storybook/sites/school.json';
|
||||
import { companyLisaSite } from '@/assets/storybook/sites/companylisa';
|
||||
import { schoolBarbaraSite } from '@/assets/storybook/sites/schoolbarbara';
|
||||
import { schoolJefferySite } from '@/assets/storybook/sites/schooljeffery';
|
||||
import { CoreSiteFixture, CoreSiteStub } from '@/storybook/stubs/classes/site';
|
||||
import { CoreSitesProvider } from '@services/sites';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { SiteDBEntry } from '@services/database/sites';
|
||||
import { CoreSiteBasicInfo, CoreSitesProvider } from '@services/sites';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
|
@ -22,17 +27,55 @@ import { makeSingleton } from '@singletons';
|
|||
*/
|
||||
export class CoreSitesProviderStub extends CoreSitesProvider {
|
||||
|
||||
protected static readonly SITES_FIXTURES = [schoolBarbaraSite, schoolJefferySite, companyLisaSite];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getRequiredCurrentSite!: () => CoreSiteStub;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||
const sites = CoreSitesProviderStub.SITES_FIXTURES.map(site => (<SiteDBEntry> {
|
||||
id: site.id,
|
||||
siteUrl: site.info.siteurl,
|
||||
info: JSON.stringify(site.info),
|
||||
token: '',
|
||||
privateToken: '',
|
||||
loggedOut: 0,
|
||||
}));
|
||||
|
||||
return this.siteDBRecordsToBasicInfo(sites, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getSite(siteId?: string): Promise<CoreSite> {
|
||||
if (!siteId) {
|
||||
if (this.currentSite) {
|
||||
return this.currentSite;
|
||||
}
|
||||
|
||||
throw new CoreError('No current site found.');
|
||||
}
|
||||
|
||||
const siteFixture = CoreSitesProviderStub.SITES_FIXTURES.find(site => site.id === siteId);
|
||||
if (!siteFixture) {
|
||||
throw new CoreError('SiteId not found.');
|
||||
}
|
||||
|
||||
return new CoreSiteStub(siteFixture);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
stubCurrentSite(fixture?: CoreSiteFixture): CoreSiteStub {
|
||||
if (!this.currentSite) {
|
||||
this.currentSite = new CoreSiteStub(fixture ?? school);
|
||||
this.currentSite = new CoreSiteStub(fixture ?? schoolBarbaraSite);
|
||||
}
|
||||
|
||||
return this.getRequiredCurrentSite();
|
||||
|
|
|
@ -73,4 +73,5 @@ export interface EnvironmentConfig {
|
|||
disableCallWSInBackground?: boolean; // If true, disable calling WS in background.
|
||||
callWSInBackgroundExpirationTime?: number; // Ms to consider an entry expired when calling WS in background. Default: 1 week.
|
||||
disableTokenFile: boolean; // Disable the use of tokenpluginfile.php for downloading files (so it fallbacks to pluginfile.php)
|
||||
demoMode?: boolean; // Whether to run the app in "demo mode".
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ For more information about upgrading, read the official documentation: https://m
|
|||
- Starting with this release, this file will only document breaking changes for APIs exposed to site plugins. Internal changes will no longer be documented.
|
||||
- CoreCache has been deprecated, use plain object as in-memory stores instead.
|
||||
|
||||
=== 4.4.0 ===
|
||||
|
||||
- Renamed CoreLoginSitesComponent to CoreLoginSitesModalComponent to make it clear that it's a modal and to avoid confusing it with the new CoreSitesListComponent.
|
||||
|
||||
=== 4.3.0 ===
|
||||
|
||||
- CoreSiteBasicInfo fullName attribute has changed to fullname and avatar to userpictureurl to match user fields.
|
||||
|
|
Loading…
Reference in New Issue