Merge branch 'next/minor' of github.com:Start9Labs/start-os into next/major

This commit is contained in:
Matt Hill
2024-08-08 10:52:49 -06:00
765 changed files with 43858 additions and 19423 deletions

View File

@@ -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 = ''

View File

@@ -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> -->

View File

@@ -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>

View File

@@ -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;
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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 {}

View File

@@ -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()
}
}

View File

@@ -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> -->

View File

@@ -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,
),

View File

@@ -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>

View File

@@ -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[]
}

View File

@@ -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 {}