mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
41 changed files with 514 additions and 404 deletions
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
@ -1,67 +1,65 @@ |
|||
<sqx-title message="i18n:apps.listPageTitle" /> |
|||
@if (authState.userChanges | async; as user) { |
|||
<div class="panel-container page"> |
|||
<div class="apps-section"> |
|||
<h1 class="apps-title">{{ "apps.welcomeTitle" | sqxTranslate: { user: user.displayName } }}</h1> |
|||
|
|||
<div class="subtext">{{ "apps.welcomeSubtitle" | sqxTranslate }}</div> |
|||
</div> |
|||
|
|||
@if (groupedApps | async; as groups) { |
|||
<div class="apps-section" sqxTourStep="allApps"> |
|||
@for (group of groups; track trackByGroup($index, group)) { |
|||
<div class="team"> |
|||
@if (group.team) { |
|||
<div class="team-header"><sqx-team (leave)="leaveTeam($event)" [team]="group.team" /></div> |
|||
} |
|||
|
|||
<div class="team-body" [class.padded]="group.team"> |
|||
@for (app of group.apps; track app.id) { |
|||
<sqx-app [app]="app" (leave)="leaveApp($event)" /> |
|||
} @empty { |
|||
<small class="team-empty"> {{ "teams.empty" | sqxTranslate }} </small> |
|||
} |
|||
</div> |
|||
</div> |
|||
} @empty { |
|||
<div class="empty"> |
|||
<h3 class="empty-headline">{{ "apps.empty" | sqxTranslate }}</h3> |
|||
</div> |
|||
} |
|||
</div> |
|||
} |
|||
|
|||
@if ((uiState.settings | async)?.canCreateApps) { |
|||
@if (authState.userChanges | async; as user) { |
|||
<div class="panel-container page flex-grow d-flex flex-grow flex-column justify-content-between" style="flex-grow: 1"> |
|||
<div class="apps"> |
|||
<div class="apps-section"> |
|||
<div class="card card-template card-href" (click)="createNewApp()" data-testid="new-app" sqxTourStep="addApp"> |
|||
<div class="card-body"> |
|||
<div class="card-image"><img src="./images/add-app.svg" /></div> |
|||
<div class="row align-items-center"> |
|||
<div class="col"> |
|||
<h1 class="apps-title">{{ "apps.welcomeTitle" | sqxTranslate: { user: user.displayName } }}</h1> |
|||
|
|||
<h3 class="card-title">{{ "apps.createBlankApp" | sqxTranslate }}</h3> |
|||
<sqx-form-hint> {{ "apps.createBlankAppDescription" | sqxTranslate }} </sqx-form-hint> |
|||
<div class="subtext">{{ "apps.welcomeSubtitle" | sqxTranslate }}</div> |
|||
</div> |
|||
|
|||
@if ((uiState.settings | async)?.canCreateApps) { |
|||
<div class="col-auto"> |
|||
<button class="btn btn-block btn-success" (click)="addAppDialog.show()" data-testid="new-app" sqxTourStep="addApp" type="button"> |
|||
<i class="icon-plus"></i> {{ "apps.appsButtonCreate" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
|
|||
@for (template of templates | async; track template) { |
|||
<div class="card card-template card-href" (click)="createNewApp(template)"> |
|||
<div class="card-body"> |
|||
<div class="card-image"><img src="./images/add-template.svg" /></div> |
|||
@if (groupedApps | async; as groups) { |
|||
<div class="apps-section" sqxTourStep="allApps"> |
|||
@for (group of groups; track trackByGroup($index, group)) { |
|||
<div class="team"> |
|||
@if (group.team) { |
|||
<div class="team-header"><sqx-team (leave)="leaveTeam($event)" [team]="group.team" /></div> |
|||
} |
|||
|
|||
<h3 class="card-title">{{ template.title }}</h3> |
|||
<sqx-form-hint> {{ template.description }} </sqx-form-hint> |
|||
<div class="team-body row g-2" [class.padded]="group.team"> |
|||
@for (app of group.apps; track app.id) { |
|||
<div class="col-12 col-md-6 col-lg-4"> |
|||
<sqx-app [app]="app" (leave)="leaveApp($event)" /> |
|||
</div> |
|||
} @empty { |
|||
<small class="team-empty"> {{ "teams.empty" | sqxTranslate }} </small> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
} |
|||
} @empty { |
|||
<div class="empty"> |
|||
<h3 class="empty-headline">{{ "apps.empty" | sqxTranslate }}</h3> |
|||
</div> |
|||
} |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
@if (info) { |
|||
@if (generalInfo) { |
|||
<div class="apps-section"> |
|||
<small class="info">{{ info }}</small> |
|||
<small class="info">{{ generalInfo }}</small> |
|||
</div> |
|||
} |
|||
</div> |
|||
} |
|||
<sqx-app-form (dialogClose)="addAppDialog.hide()" *sqxModal="addAppDialog" [template]="addAppTemplate" /> |
|||
|
|||
<sqx-onboarding-dialog (dialogClose)="onboardingDialog.hide()" *sqxModal="onboardingDialog" /> |
|||
|
|||
@if (starters | async; as templates) { |
|||
<sqx-app-form (dialogClose)="addAppDialog.hide()" *sqxModal="addAppDialog" [template]="addAppTemplate" [templates]="templates" /> |
|||
} |
|||
|
|||
<sqx-news-dialog (dialogClose)="newsDialog.hide()" [features]="newsFeatures!" *sqxModal="newsDialog" /> |
|||
|
|||
@ -1,31 +0,0 @@ |
|||
<div class="table-items-row table-items-row-expandable"> |
|||
<div class="table-items-row-summary row gx-2 align-items-center"> |
|||
<div class="col"> |
|||
{{ template.title }} <sqx-form-hint class="truncate">{{ template.description }}</sqx-form-hint> |
|||
</div> |
|||
|
|||
<div class="col-auto"> |
|||
<div class="float-end"> |
|||
<button class="btn btn-outline-secondary btn-expand me-1" [class.expanded]="isExpanded" (click)="toggleExpanded()" type="button"> |
|||
<i class="icon-download"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
@if (isExpanded) { |
|||
<div class="table-items-row-details"> |
|||
<div class="table-items-row-details-tabs clearfix"> |
|||
<h4>{{ "common.details" | sqxTranslate }}</h4> |
|||
</div> |
|||
|
|||
<div class="table-items-row-details-tab"> |
|||
@if (details | async; as loadedDetails) { |
|||
<div class="help" [sqxMarkdown]="loadedDetails"></div> |
|||
} @else { |
|||
<sqx-loader /> |
|||
} |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
@ -1,17 +0,0 @@ |
|||
@import 'mixins'; |
|||
@import 'vars'; |
|||
|
|||
h4 { |
|||
font-size: 1rem; |
|||
font-weight: 500; |
|||
margin: 0; |
|||
margin-top: .5rem; |
|||
} |
|||
|
|||
.help { |
|||
::ng-deep { |
|||
h1 { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { AsyncPipe } from '@angular/common'; |
|||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; |
|||
import { map, Observable, shareReplay } from 'rxjs'; |
|||
import { AppsState, ClientsState, FormHintComponent, LoaderComponent, MarkdownDirective, TemplateDetailsDto, TemplateDto, TemplatesService, TranslatePipe } from '@app/shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-template', |
|||
styleUrls: ['./template.component.scss'], |
|||
templateUrl: './template.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
imports: [ |
|||
AsyncPipe, |
|||
FormHintComponent, |
|||
LoaderComponent, |
|||
MarkdownDirective, |
|||
TranslatePipe, |
|||
], |
|||
}) |
|||
export class TemplateComponent { |
|||
@Input({ required: true }) |
|||
public template!: TemplateDto; |
|||
|
|||
public isExpanded = false; |
|||
|
|||
public details?: Observable<string>; |
|||
|
|||
constructor( |
|||
private readonly clientsState: ClientsState, |
|||
private readonly appsState: AppsState, |
|||
private readonly templatesService: TemplatesService, |
|||
) { |
|||
} |
|||
|
|||
public ngOnChanges() { |
|||
this.details = this.templatesService.getTemplate(this.template).pipe(map(x => this.buildDetails(x)), shareReplay(1)); |
|||
} |
|||
|
|||
public toggleExpanded() { |
|||
this.isExpanded = !this.isExpanded; |
|||
} |
|||
|
|||
private buildDetails(dto: TemplateDetailsDto) { |
|||
const app = this.appsState.appName; |
|||
|
|||
let details = dto.details.replace(/<APP>/g, app); |
|||
|
|||
const client = this.clientsState.snapshot.clients[0]; |
|||
|
|||
if (client) { |
|||
const clientId = `${app}:${client.id}`; |
|||
|
|||
details = details.replace(/\<CLIENT_ID>/g, clientId); |
|||
details = details.replace(/\<CLIENT_SECRET>/g, client.secret); |
|||
} |
|||
|
|||
return details; |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
<sqx-title message="i18n:common.templates" /> |
|||
<sqx-layout innerWidth="50" layout="main" titleIcon="download" titleText="i18n:common.templates"> |
|||
<ng-container menu> |
|||
<button class="btn btn-text-secondary me-2" (click)="reload()" shortcut="CTRL + B" title="i18n:templates.refreshTooltip" type="button"> |
|||
<i class="icon-reset"></i> {{ "common.refresh" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
<ng-container> |
|||
<sqx-list-view innerWidth="50rem" [isLoading]="templatesState.isLoading | async"> |
|||
<sqx-form-alert light="true"> |
|||
<div inline="true" [sqxMarkdown]="'templates.cliHint' | sqxTranslate"></div> |
|||
</sqx-form-alert> |
|||
@if ((templatesState.isLoaded | async) && (templatesState.templates | async); as templates) { |
|||
@for (template of templates; track template.name) { |
|||
<sqx-template [template]="template" /> |
|||
} |
|||
} |
|||
</sqx-list-view> |
|||
</ng-container> |
|||
<ng-template sidebarMenu> |
|||
<div class="panel-nav"> |
|||
<a |
|||
class="panel-link" |
|||
attr.aria-label="{{ 'common.help' | sqxTranslate }}" |
|||
queryParamsHandling="preserve" |
|||
replaceUrl="true" |
|||
routerLink="help" |
|||
routerLinkActive="active" |
|||
sqxTourStep="help" |
|||
title="i18n:common.help" |
|||
titlePosition="left"> |
|||
<i class="icon-help2"></i> |
|||
</a> |
|||
</div> |
|||
</ng-template> |
|||
</sqx-layout> |
|||
<router-outlet /> |
|||
@ -1,52 +0,0 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { AsyncPipe } from '@angular/common'; |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'; |
|||
import { ClientsState, FormAlertComponent, LayoutComponent, ListViewComponent, MarkdownDirective, ShortcutDirective, SidebarMenuDirective, TemplatesState, TitleComponent, TooltipDirective, TourStepDirective, TranslatePipe } from '@app/shared'; |
|||
import { TemplateComponent } from './template.component'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-templates-page', |
|||
styleUrls: ['./templates-page.component.scss'], |
|||
templateUrl: './templates-page.component.html', |
|||
imports: [ |
|||
AsyncPipe, |
|||
FormAlertComponent, |
|||
LayoutComponent, |
|||
ListViewComponent, |
|||
MarkdownDirective, |
|||
RouterLink, |
|||
RouterLinkActive, |
|||
RouterOutlet, |
|||
ShortcutDirective, |
|||
SidebarMenuDirective, |
|||
TemplateComponent, |
|||
TitleComponent, |
|||
TooltipDirective, |
|||
TourStepDirective, |
|||
TranslatePipe, |
|||
], |
|||
}) |
|||
export class TemplatesPageComponent implements OnInit { |
|||
constructor( |
|||
public readonly clientsState: ClientsState, |
|||
public readonly templatesState: TemplatesState, |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.clientsState.load(); |
|||
|
|||
this.templatesState.load(); |
|||
} |
|||
|
|||
public reload() { |
|||
this.templatesState.load(true); |
|||
} |
|||
} |
|||
@ -1,2 +1,31 @@ |
|||
@use 'sass:color'; |
|||
@import 'mixins'; |
|||
@import 'vars'; |
|||
@import 'vars'; |
|||
|
|||
.card-image { |
|||
width: 30%; |
|||
} |
|||
|
|||
.card-title { |
|||
margin: .25rem 0; |
|||
} |
|||
|
|||
.col-info { |
|||
background-color: color.adjust($color-background, $lightness: 2%); |
|||
border-radius: 0; |
|||
border-left: 1px solid $color-border; |
|||
padding: 1.5rem 2rem; |
|||
width: 18rem; |
|||
} |
|||
|
|||
.col-left { |
|||
padding: 1.5rem 2rem; |
|||
} |
|||
|
|||
.help { |
|||
::ng-deep { |
|||
h1 { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue