mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +00:00
Merge branch 'next/minor' of github.com:Start9Labs/start-os into next/major
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-categories',
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
})
|
||||
export class CategoriesComponent {
|
||||
@Input()
|
||||
categories?: string[]
|
||||
categories!: Map<string, T.Category>
|
||||
|
||||
@Input()
|
||||
category = ''
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="background">
|
||||
<img
|
||||
[src]="determineIcon(marketplace)"
|
||||
alt="{{ pkg.manifest.title }} Icon"
|
||||
alt="{{ pkg.title }} Icon"
|
||||
/>
|
||||
</div>
|
||||
<!-- darkening overlay -->
|
||||
@@ -15,14 +15,32 @@
|
||||
<img
|
||||
[src]="determineIcon(marketplace)"
|
||||
class="icon"
|
||||
alt="{{ pkg.manifest.title }} Icon"
|
||||
alt="{{ pkg.title }} Icon"
|
||||
/>
|
||||
<div class="detail">
|
||||
<span class="detail-title" ticker>
|
||||
{{ pkg.manifest.title }}
|
||||
{{ pkg.title }}
|
||||
</span>
|
||||
<span class="detail-description">
|
||||
{{ pkg.manifest.description.short }}
|
||||
{{ pkg.description.short }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- @TODO Alex -->
|
||||
<!-- <ion-item
|
||||
class="service-card"
|
||||
[routerLink]="['/marketplace', pkg.id]"
|
||||
[queryParams]="{ flavor: pkg.flavor, version: pkg.version }"
|
||||
>
|
||||
<ion-thumbnail slot="start">
|
||||
<img alt="" [src]="pkg.icon | trustUrl" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h2 class="montserrat">
|
||||
<strong>{{ pkg.title }}</strong>
|
||||
</h2>
|
||||
<h3>{{ pkg.description.short }}</h3>
|
||||
<ng-content></ng-content>
|
||||
</ion-label>
|
||||
</ion-item> -->
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<div class="background-border box-shadow-lg shadow-color-light">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">What's new</h2>
|
||||
<div class="box-container-details">
|
||||
<div class="box-container-details-version">
|
||||
<h3>Version {{ pkg.manifest.version }}</h3>
|
||||
<p
|
||||
safeLinks
|
||||
class="box-container-details-notes"
|
||||
[innerHTML]="pkg.manifest.releaseNotes | markdown | dompurify"
|
||||
></p>
|
||||
</div>
|
||||
<button
|
||||
*ngIf="pkg.versions.length > 2"
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="secondary"
|
||||
size="m"
|
||||
(click)="showReleaseNotes(template)"
|
||||
>
|
||||
Previous releases
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #template let-observer>
|
||||
<ng-container *ngIf="notes$ | async as notes; else loading">
|
||||
<tui-accordion
|
||||
class="max-width-lg"
|
||||
style="max-width: 32rem"
|
||||
[closeOthers]="false"
|
||||
*ngFor="
|
||||
let note of notes
|
||||
| filterVersions: pkg.manifest.version
|
||||
| keyvalue: asIsOrder
|
||||
"
|
||||
>
|
||||
<tui-accordion-item style="margin: 0.25rem 0">
|
||||
{{ note.key | displayEmver }}
|
||||
<ng-template tuiAccordionItemContent>
|
||||
<p safeLinks [innerHTML]="note.value | markdown | dompurify"></p>
|
||||
</ng-template>
|
||||
</tui-accordion-item>
|
||||
</tui-accordion>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #loading>
|
||||
<tui-loader textContent="Loading Release Notes" />
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -1,44 +0,0 @@
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.75rem;
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
align-items: center;
|
||||
|
||||
&-details {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
&-version {
|
||||
line-height: 1.5rem;
|
||||
font-size: 1rem;
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 1.25rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-notes {
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.25rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 0.75rem;
|
||||
place-self: end;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
place-self: start;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
place-self: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
Inject,
|
||||
Input,
|
||||
Pipe,
|
||||
PipeTransform,
|
||||
} from '@angular/core'
|
||||
import { AbstractMarketplaceService } from '../../services/marketplace.service'
|
||||
import { PolymorpheusContent } from '@taiga-ui/polymorpheus'
|
||||
import { TuiDialogContext, TuiDialogService } from '@taiga-ui/core'
|
||||
import { MarketplacePkg } from '../../types'
|
||||
import { Observable } from 'rxjs'
|
||||
import { Emver } from '@start9labs/shared'
|
||||
import { KeyValue } from '@angular/common'
|
||||
|
||||
@Component({
|
||||
selector: 'release-notes',
|
||||
templateUrl: './release-notes.component.html',
|
||||
styleUrls: ['./release-notes.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ReleaseNotesComponent {
|
||||
constructor(
|
||||
private readonly emver: Emver,
|
||||
private readonly marketplaceService: AbstractMarketplaceService,
|
||||
@Inject(TuiDialogService) private readonly dialogs: TuiDialogService,
|
||||
) {}
|
||||
|
||||
@Input({ required: true })
|
||||
pkg!: MarketplacePkg
|
||||
|
||||
notes$!: Observable<Record<string, string>>
|
||||
|
||||
ngOnChanges() {
|
||||
this.notes$ = this.marketplaceService.fetchReleaseNotes$(
|
||||
this.pkg.manifest.id,
|
||||
)
|
||||
}
|
||||
|
||||
asIsOrder(a: KeyValue<string, string>, b: KeyValue<string, string>) {
|
||||
const a1 = a.key.split('.')
|
||||
const b1 = b.key.split('.')
|
||||
// contingency in case there's a 4th or 5th version
|
||||
const len = Math.min(a1.length, b1.length)
|
||||
// look through each version number and compare.
|
||||
for (let i = 0; i < len; i++) {
|
||||
const a2 = +a1[i] || 0
|
||||
const b2 = +b1[i] || 0
|
||||
|
||||
if (a2 !== b2) {
|
||||
// sort descending
|
||||
return a2 > b2 ? -1 : 1
|
||||
}
|
||||
}
|
||||
return a1.length - b1.length
|
||||
}
|
||||
|
||||
async showReleaseNotes(content: PolymorpheusContent<TuiDialogContext>) {
|
||||
this.dialogs
|
||||
.open(content, {
|
||||
label: 'Previous Release Notes',
|
||||
})
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'filterVersions',
|
||||
standalone: true,
|
||||
})
|
||||
export class FilterVersionsPipe implements PipeTransform {
|
||||
transform(
|
||||
notes: Record<string, string>,
|
||||
pkgVersion: string,
|
||||
): Record<string, string> {
|
||||
delete notes[pkgVersion]
|
||||
return notes
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { TuiAccordion } from '@taiga-ui/kit'
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import {
|
||||
EmverPipesModule,
|
||||
MarkdownPipeModule,
|
||||
SafeLinksDirective,
|
||||
} from '@start9labs/shared'
|
||||
import { TuiLoader, TuiButton } from '@taiga-ui/core'
|
||||
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
|
||||
import {
|
||||
FilterVersionsPipe,
|
||||
ReleaseNotesComponent,
|
||||
} from './release-notes.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
EmverPipesModule,
|
||||
MarkdownPipeModule,
|
||||
NgDompurifyModule,
|
||||
SafeLinksDirective,
|
||||
TuiButton,
|
||||
...TuiAccordion,
|
||||
TuiLoader,
|
||||
FilterVersionsPipe,
|
||||
],
|
||||
declarations: [ReleaseNotesComponent],
|
||||
exports: [ReleaseNotesComponent],
|
||||
})
|
||||
export class ReleaseNotesModule {}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { ReleaseNotesComponent } from '../../../modals/release-notes/release-notes.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-about',
|
||||
@@ -10,4 +12,15 @@ import { MarketplacePkg } from '../../../types'
|
||||
export class AboutComponent {
|
||||
@Input({ required: true })
|
||||
pkg!: MarketplacePkg
|
||||
|
||||
constructor(private readonly modalCtrl: ModalController) {}
|
||||
|
||||
async presentModalNotes() {
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: { pkg: this.pkg },
|
||||
component: ReleaseNotesComponent,
|
||||
})
|
||||
|
||||
await modal.present()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
></marketplace-additional-item>
|
||||
<!-- git hash -->
|
||||
<marketplace-additional-item
|
||||
*ngIf="pkg.manifest.gitHash as gitHash; else noHash"
|
||||
*ngIf="pkg.gitHash as gitHash; else noHash"
|
||||
(click)="copyService.copy(gitHash)"
|
||||
[data]="gitHash"
|
||||
label="Git Hash"
|
||||
@@ -29,7 +29,7 @@
|
||||
<!-- license -->
|
||||
<marketplace-additional-item
|
||||
(click)="presentModalMd('License')"
|
||||
[data]="pkg.manifest.license"
|
||||
[data]="pkg.license"
|
||||
label="License"
|
||||
icon="@tui.chevron-right"
|
||||
class="item-pointer"
|
||||
@@ -46,29 +46,29 @@
|
||||
<ng-content />
|
||||
<!-- links -->
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.manifest.marketingSite"
|
||||
[url]="pkg.manifest.marketingSite"
|
||||
*ngIf="pkg.marketingSite"
|
||||
[url]="pkg.marketingSite"
|
||||
label="Marketing Site"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
></marketplace-additional-link>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.manifest.upstreamRepo"
|
||||
[url]="pkg.manifest.upstreamRepo"
|
||||
*ngIf="pkg.upstreamRepo"
|
||||
[url]="pkg.upstreamRepo"
|
||||
label="Source Repository"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
></marketplace-additional-link>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.manifest.wrapperRepo"
|
||||
[url]="pkg.manifest.wrapperRepo"
|
||||
*ngIf="pkg.wrapperRepo"
|
||||
[url]="pkg.wrapperRepo"
|
||||
label="Wrapper Repository"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
></marketplace-additional-link>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.manifest.supportSite"
|
||||
[url]="pkg.manifest.supportSite"
|
||||
*ngIf="pkg.supportSite"
|
||||
[url]="pkg.supportSite"
|
||||
label="Support Site"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
@@ -76,3 +76,98 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <ion-item-divider>Additional Info</ion-item-divider>
|
||||
<ion-grid *ngIf="pkg">
|
||||
<ion-row>
|
||||
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item
|
||||
*ngIf="pkg.gitHash as gitHash; else noHash"
|
||||
button
|
||||
detail="false"
|
||||
(click)="copy(gitHash)"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>{{ gitHash }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="copy-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ng-template #noHash>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>Unknown</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
<ion-item button detail="false" (click)="presentAlertVersions()">
|
||||
<ion-label>
|
||||
<h2>Other Versions</h2>
|
||||
<p>Click to view other versions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ pkg.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
button
|
||||
detail="false"
|
||||
(click)="presentModalMd('instructions')"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Instructions</h2>
|
||||
<p>Click to view instructions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
<ion-col responsiveCol sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item
|
||||
[href]="pkg.upstreamRepo"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Source Repository</h2>
|
||||
<p>{{ pkg.upstreamRepo }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="pkg.wrapperRepo"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Wrapper Repository</h2>
|
||||
<p>{{ pkg.wrapperRepo }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="pkg.supportSite"
|
||||
[disabled]="!pkg.supportSite"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Support Site</h2>
|
||||
<p>{{ pkg.supportSite || 'Not provided' }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid> -->
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { TuiDialogService } from '@taiga-ui/core'
|
||||
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { CopyService, MarkdownComponent } from '@start9labs/shared'
|
||||
import { CopyService, Exver, MarkdownComponent } from '@start9labs/shared'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||
|
||||
@@ -38,7 +38,7 @@ export class AdditionalComponent {
|
||||
size: 'l',
|
||||
data: {
|
||||
content: this.marketplaceService.fetchStatic$(
|
||||
this.pkg.manifest.id,
|
||||
this.pkg.id,
|
||||
label.toLowerCase(),
|
||||
this.url,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<ion-item-divider>Alternative Implementations</ion-item-divider>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs" responsiveCol sizeSm="12" sizeMd="6">
|
||||
<ion-item
|
||||
[routerLink]="['/marketplace', pkg.id]"
|
||||
[queryParams]="{ flavor: pkg.flavor }"
|
||||
>
|
||||
<ion-thumbnail slot="start">
|
||||
<img alt="" style="border-radius: 100%" [src]="pkg.icon | trustUrl" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h2>
|
||||
{{ pkg.title }}
|
||||
</h2>
|
||||
<p>{{ pkg.version }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-flavors',
|
||||
templateUrl: 'flavors.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FlavorsComponent {
|
||||
@Input()
|
||||
pkgs!: MarketplacePkg[]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { NgModule } from '@angular/core'
|
||||
import { RouterModule } from '@angular/router'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { ResponsiveColModule, SharedPipesModule } from '@start9labs/shared'
|
||||
import { FlavorsComponent } from './flavors.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
IonicModule,
|
||||
SharedPipesModule,
|
||||
ResponsiveColModule,
|
||||
],
|
||||
declarations: [FlavorsComponent],
|
||||
exports: [FlavorsComponent],
|
||||
})
|
||||
export class FlavorsModule {}
|
||||
Reference in New Issue
Block a user