mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
update/alpha.9 (#2988)
* import marketplac preview for sideload * fix: improve state service (#2977) * fix: fix sideload DI * fix: update Angular * fix: cleanup * fix: fix version selection * Bump node version to fix build for Angular * misc fixes - update node to v22 - fix chroot-and-upgrade access to prune-images - don't self-migrate legacy packages - #2985 - move dataVersion to volume folder - remove "instructions.md" from s9pk - add "docsUrl" to manifest * version bump * include flavor when clicking view listing from updates tab * closes #2980 * fix: fix select button * bring back ssh keys * fix: drop 'portal' from all routes * fix: implement longtap action to select table rows * fix description for ssh page * replace instructions with docsLink and refactor marketplace preview * delete unused translations * fix patchdb diffing algorithm * continue refactor of marketplace lib show components * Booting StartOS instead of Setting up your server on init * misc fixes - closes #2990 - closes #2987 * fix build * docsUrl and clickable service headers * don't cleanup after update until new service install succeeds * update types * misc fixes * beta.35 * sdkversion, githash for sideload, correct logs for init, startos pubkey display * bring back reboot button on install * misc fixes * beta.36 * better handling of setup and init for websocket errors * reopen init and setup logs even on graceful closure * better logging, misc fixes * fix build * dont let package stats hang * dont show docsurl in marketplace if no docsurl * re-add needs-config * show error if init fails, shorten hover state on header icons * fix operator precedemce --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> Co-authored-by: Alex Inkin <alexander@inkin.ru> Co-authored-by: Mariusz Kogen <k0gen@pm.me>
This commit is contained in:
@@ -4,20 +4,20 @@ import { knownRegistries, sameUrl } from '@start9labs/shared'
|
||||
@Component({
|
||||
selector: 'store-icon',
|
||||
template: `
|
||||
<img
|
||||
*ngIf="icon; else noIcon"
|
||||
[style.border-radius.%]="100"
|
||||
[style.max-width]="size || '100%'"
|
||||
[src]="icon"
|
||||
alt="Registry Icon"
|
||||
/>
|
||||
<ng-template #noIcon>
|
||||
@if (icon) {
|
||||
<img
|
||||
[style.border-radius.%]="100"
|
||||
[style.max-width]="size || '100%'"
|
||||
[src]="icon"
|
||||
alt="Registry Icon"
|
||||
/>
|
||||
} @else {
|
||||
<img
|
||||
[style.max-width]="size || '100%'"
|
||||
src="assets/img/storefront-outline.png"
|
||||
alt="Registry Icon"
|
||||
/>
|
||||
</ng-template>
|
||||
}
|
||||
`,
|
||||
styles: ':host { overflow: hidden; }',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { Exver, MarkdownPipe } from '@start9labs/shared'
|
||||
import { TuiDialogContext } from '@taiga-ui/core'
|
||||
import { NgDompurifyPipe } from '@taiga-ui/dompurify'
|
||||
import { TuiAccordion } from '@taiga-ui/kit'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { MarketplacePkg } from '../../src/types'
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<tui-accordion>
|
||||
@for (note of notes | keyvalue: asIsOrder; track $index) {
|
||||
<tui-accordion-item>
|
||||
{{ note.key }}
|
||||
<ng-template tuiAccordionItemContent>
|
||||
<div [innerHTML]="note.value | markdown | dompurify"></div>
|
||||
</ng-template>
|
||||
</tui-accordion-item>
|
||||
}
|
||||
</tui-accordion>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, TuiAccordion, MarkdownPipe, NgDompurifyPipe],
|
||||
})
|
||||
export class ReleaseNotesComponent {
|
||||
private readonly exver = inject(Exver)
|
||||
private readonly pkg =
|
||||
injectContext<TuiDialogContext<void, MarketplacePkg>>().data
|
||||
|
||||
readonly notes = Object.entries(this.pkg.otherVersions)
|
||||
.filter(
|
||||
([v, _]) =>
|
||||
this.exver.getFlavor(v) === this.pkg.flavor &&
|
||||
this.exver.compareExver(this.pkg.version, v) === 1,
|
||||
)
|
||||
.reduce(
|
||||
(obj, [version, info]) => ({
|
||||
...obj,
|
||||
[version]: info.releaseNotes,
|
||||
}),
|
||||
{
|
||||
[`${this.pkg.version} (current)`]: this.pkg.releaseNotes,
|
||||
},
|
||||
)
|
||||
|
||||
asIsOrder(a: any, b: any) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
export const RELEASE_NOTES = new PolymorpheusComponent(ReleaseNotesComponent)
|
||||
@@ -16,8 +16,8 @@
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -50;
|
||||
border-radius: 1.5rem;
|
||||
background-color: rgb(39 39 42);
|
||||
|
||||
139
web/projects/marketplace/src/pages/show/about.component.ts
Normal file
139
web/projects/marketplace/src/pages/show/about.component.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
} from '@angular/core'
|
||||
import { MarketplacePkgBase } from '../../types'
|
||||
import { CopyService } from '@start9labs/shared'
|
||||
import { DatePipe } from '@angular/common'
|
||||
import { MarketplaceItemComponent } from './item.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-about',
|
||||
template: `
|
||||
<div class="background-border box-shadow-lg shadow-color-light">
|
||||
<div class="box-container">
|
||||
<div class="detail-container">
|
||||
<!-- version -->
|
||||
<marketplace-item
|
||||
[style.pointer-events]="'none'"
|
||||
[data]="pkg().version"
|
||||
label="Version"
|
||||
icon=""
|
||||
/>
|
||||
<!-- release date -->
|
||||
@if (pkg().s9pk?.publishedAt; as published) {
|
||||
<marketplace-item
|
||||
[style.pointer-events]="'none'"
|
||||
[data]="(published | date: 'medium')!"
|
||||
label="Released"
|
||||
icon=""
|
||||
/>
|
||||
}
|
||||
<!-- SDK version -->
|
||||
<marketplace-item
|
||||
[style.pointer-events]="'none'"
|
||||
[data]="pkg().sdkVersion || 'Unknown'"
|
||||
label="SDK Version"
|
||||
icon=""
|
||||
/>
|
||||
<!-- git hash -->
|
||||
@if (pkg().gitHash; as gitHash) {
|
||||
<marketplace-item
|
||||
(click)="copyService.copy(gitHash)"
|
||||
[data]="gitHash"
|
||||
label="Git Hash"
|
||||
icon="@tui.copy"
|
||||
class="item-copy"
|
||||
/>
|
||||
} @else {
|
||||
<div class="item-padding">
|
||||
<label tuiTitle>
|
||||
<span tuiSubtitle>Git Hash</span>
|
||||
Unknown
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
<!-- license -->
|
||||
<marketplace-item
|
||||
(click)="static.emit('license')"
|
||||
[data]="pkg().license"
|
||||
label="License"
|
||||
icon="@tui.chevron-right"
|
||||
class="item-pointer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="background-border box-shadow-lg shadow-color-light">
|
||||
<div class="box-container">
|
||||
<p [innerHTML]="pkg().description.long"></p>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: `
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-container {
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
|
||||
& > * + * {
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 0;
|
||||
border-color: rgb(113 113 122);
|
||||
}
|
||||
}
|
||||
|
||||
.item-pointer:hover {
|
||||
cursor: pointer;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.item-copy:hover {
|
||||
cursor: copy;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: copy;
|
||||
}
|
||||
}
|
||||
|
||||
.item-padding {
|
||||
padding: 0.75rem 0.25rem;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: rgb(var(--tw-color-gray-200) / 1);
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [MarketplaceItemComponent, DatePipe],
|
||||
})
|
||||
export class MarketplaceAboutComponent {
|
||||
readonly copyService = inject(CopyService)
|
||||
|
||||
readonly pkg = input.required<MarketplacePkgBase>()
|
||||
|
||||
readonly static = output<'license'>()
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<div class="background-border box-shadow-lg shadow-color-light">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">New in {{ pkg.version }}</h2>
|
||||
<p [innerHTML]="pkg.releaseNotes | markdown | dompurify"></p>
|
||||
<button
|
||||
tuiButton
|
||||
size="s"
|
||||
appearance="whiteblock"
|
||||
iconEnd="@tui.chevron-right"
|
||||
(click)="onPast()"
|
||||
>
|
||||
Past Release Notes
|
||||
</button>
|
||||
<h2 class="additional-detail-title" [style.margin-top.rem]="2">About</h2>
|
||||
<p [innerHTML]="pkg.description.long"></p>
|
||||
<a
|
||||
*ngIf="pkg.marketingSite as url"
|
||||
tuiButton
|
||||
iconEnd="@tui.external-link"
|
||||
size="s"
|
||||
appearance="secondary-grayscale"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
[href]="url"
|
||||
>
|
||||
View website
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.75rem;
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
Input,
|
||||
} from '@angular/core'
|
||||
import { TuiDialogService } from '@taiga-ui/core'
|
||||
import { RELEASE_NOTES } from '../../../modals/release-notes.component'
|
||||
import { MarketplacePkgBase } from '../../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-about',
|
||||
templateUrl: 'about.component.html',
|
||||
styleUrls: ['about.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class AboutComponent {
|
||||
private readonly dialogs = inject(TuiDialogService)
|
||||
|
||||
@Input({ required: true })
|
||||
pkg!: MarketplacePkgBase
|
||||
|
||||
async onPast() {
|
||||
this.dialogs
|
||||
.open(RELEASE_NOTES, { label: 'Past Release Notes', data: this.pkg })
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { NgModule } from '@angular/core'
|
||||
import { RouterModule } from '@angular/router'
|
||||
import { MarkdownPipe, SafeLinksDirective } from '@start9labs/shared'
|
||||
import { TuiButton } from '@taiga-ui/core'
|
||||
import { NgDompurifyPipe } from '@taiga-ui/dompurify'
|
||||
import { TuiTagModule } from '@taiga-ui/legacy'
|
||||
import { AboutComponent } from './about.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
TuiTagModule,
|
||||
NgDompurifyPipe,
|
||||
SafeLinksDirective,
|
||||
MarkdownPipe,
|
||||
TuiButton,
|
||||
],
|
||||
declarations: [AboutComponent],
|
||||
exports: [AboutComponent],
|
||||
})
|
||||
export class AboutModule {}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { MarketplaceAdditionalItemComponent } from './additional-item.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-additional-link',
|
||||
template: `
|
||||
<a [href]="url" target="_blank" rel="noreferrer">
|
||||
<marketplace-additional-item
|
||||
[label]="label"
|
||||
[icon]="icon"
|
||||
[data]="url"
|
||||
></marketplace-additional-item>
|
||||
</a>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, MarketplaceAdditionalItemComponent],
|
||||
})
|
||||
export class MarketplaceAdditionalLinkComponent {
|
||||
@Input({ required: true })
|
||||
label!: string
|
||||
|
||||
@Input({ required: true })
|
||||
icon!: string
|
||||
|
||||
@Input({ required: true })
|
||||
url!: string
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<div class="background-border shadow-color-light box-shadow-lg">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">Information</h2>
|
||||
<div class="detail-container">
|
||||
<!-- release date -->
|
||||
<marketplace-additional-item
|
||||
*ngIf="pkg.s9pk?.publishedAt as published"
|
||||
[data]="(published | date: 'medium')!"
|
||||
label="Released"
|
||||
icon=""
|
||||
/>
|
||||
<!-- git hash -->
|
||||
<marketplace-additional-item
|
||||
*ngIf="pkg.gitHash as gitHash; else noHash"
|
||||
(click)="copyService.copy(gitHash)"
|
||||
[data]="gitHash"
|
||||
label="Git Hash"
|
||||
icon="@tui.copy"
|
||||
class="item-copy"
|
||||
/>
|
||||
<ng-template #noHash>
|
||||
<div class="item-padding">
|
||||
<label tuiTitle>
|
||||
<span tuiSubtitle>Git Hash</span>
|
||||
Unknown
|
||||
</label>
|
||||
</div>
|
||||
</ng-template>
|
||||
<!-- license -->
|
||||
<marketplace-additional-item
|
||||
(click)="static.emit('license')"
|
||||
[data]="pkg.license"
|
||||
label="License"
|
||||
icon="@tui.chevron-right"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<!-- instructions -->
|
||||
<marketplace-additional-item
|
||||
(click)="static.emit('instructions')"
|
||||
data="Click to view instructions"
|
||||
label="Instructions"
|
||||
icon="@tui.chevron-right"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<!-- versions -->
|
||||
<ng-content />
|
||||
<!-- links -->
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.marketingSite"
|
||||
[url]="pkg.marketingSite"
|
||||
label="Marketing Site"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.upstreamRepo"
|
||||
[url]="pkg.upstreamRepo"
|
||||
label="Source Repository"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.wrapperRepo"
|
||||
[url]="pkg.wrapperRepo"
|
||||
label="Wrapper Repository"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<marketplace-additional-link
|
||||
*ngIf="pkg.supportSite"
|
||||
[url]="pkg.supportSite"
|
||||
label="Support Site"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +0,0 @@
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.75rem;
|
||||
}
|
||||
|
||||
.detail-container {
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
|
||||
& > * + * {
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 0;
|
||||
border-color: rgb(113 113 122);
|
||||
}
|
||||
}
|
||||
|
||||
.item-pointer:hover {
|
||||
cursor: pointer;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.item-copy:hover {
|
||||
cursor: copy;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: copy;
|
||||
}
|
||||
}
|
||||
|
||||
.item-padding {
|
||||
padding: 0.75rem 0.25rem;
|
||||
}
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: rgb(var(--tw-color-gray-200) / 1);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { CopyService } from '@start9labs/shared'
|
||||
import { MarketplacePkgBase } from '../../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-additional',
|
||||
templateUrl: 'additional.component.html',
|
||||
styleUrls: ['additional.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class AdditionalComponent {
|
||||
@Input({ required: true })
|
||||
pkg!: MarketplacePkgBase
|
||||
|
||||
@Output()
|
||||
readonly static = new EventEmitter<'license' | 'instructions'>()
|
||||
|
||||
constructor(
|
||||
readonly copyService: CopyService,
|
||||
private readonly route: ActivatedRoute,
|
||||
) {}
|
||||
|
||||
readonly url = this.route.snapshot.queryParamMap.get('url') || undefined
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { NgModule } from '@angular/core'
|
||||
import { AdditionalComponent } from './additional.component'
|
||||
import { TuiButton, TuiLabel, TuiTitle } from '@taiga-ui/core'
|
||||
import { MarketplaceAdditionalItemComponent } from './additional-item.component'
|
||||
import { MarketplaceAdditionalLinkComponent } from './additional-link.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
TuiButton,
|
||||
TuiLabel,
|
||||
MarketplaceAdditionalItemComponent,
|
||||
MarketplaceAdditionalLinkComponent,
|
||||
TuiTitle,
|
||||
],
|
||||
declarations: [AdditionalComponent],
|
||||
exports: [AdditionalComponent],
|
||||
})
|
||||
export class AdditionalModule {}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CommonModule, KeyValue } from '@angular/common'
|
||||
import { KeyValue } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { RouterModule } from '@angular/router'
|
||||
import { ExverPipesModule } from '@start9labs/shared'
|
||||
@@ -19,10 +19,11 @@ import { MarketplacePkgBase } from '../../../types'
|
||||
{{ getTitle(dep.key) }}
|
||||
</span>
|
||||
<p>
|
||||
<ng-container [ngSwitch]="dep.value.optional">
|
||||
<span *ngSwitchCase="true">(optional)</span>
|
||||
<span *ngSwitchCase="false">(required)</span>
|
||||
</ng-container>
|
||||
@if (dep.value.optional) {
|
||||
<span>(optional)</span>
|
||||
} @else {
|
||||
<span>(required)</span>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -87,13 +88,7 @@ import { MarketplacePkgBase } from '../../../types'
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
TuiAvatar,
|
||||
ExverPipesModule,
|
||||
TuiLineClamp,
|
||||
],
|
||||
imports: [RouterModule, TuiAvatar, ExverPipesModule, TuiLineClamp],
|
||||
})
|
||||
export class MarketplaceDepItemComponent {
|
||||
@Input({ required: true })
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SharedPipesModule } from '@start9labs/shared'
|
||||
import { TuiTitle } from '@taiga-ui/core'
|
||||
import { TuiAvatar } from '@taiga-ui/kit'
|
||||
import { TuiCell } from '@taiga-ui/layout'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { MarketplacePkg } from '../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-flavors',
|
||||
@@ -33,7 +33,7 @@ import { MarketplacePkg } from '../../../types'
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.75rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
}
|
||||
|
||||
[tuiCell] {
|
||||
@@ -44,7 +44,7 @@ import { MarketplacePkg } from '../../../types'
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [RouterLink, TuiCell, TuiTitle, SharedPipesModule, TuiAvatar],
|
||||
})
|
||||
export class FlavorsComponent {
|
||||
export class MarketplaceFlavorsComponent {
|
||||
@Input()
|
||||
pkgs!: MarketplacePkg[]
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
|
||||
@@ -17,8 +16,6 @@ import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
<div class="dark-overlay"></div>
|
||||
<div class="inner-container-title">
|
||||
<h2 ticker>{{ pkg.title }}</h2>
|
||||
<h3>{{ pkg.version }}</h3>
|
||||
<p>{{ pkg.description.short }}</p>
|
||||
</div>
|
||||
<!-- control buttons -->
|
||||
<ng-content />
|
||||
@@ -43,7 +40,7 @@ import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
min-height: 32vh;
|
||||
position: relative;
|
||||
border-radius: 1.5rem;
|
||||
padding: 4rem 2rem 0 2rem;
|
||||
padding: 3rem 2rem 0 2rem;
|
||||
|
||||
@media (min-width: 376px) {
|
||||
min-height: 20vh;
|
||||
@@ -66,7 +63,7 @@ import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
}
|
||||
|
||||
.inner-container-title {
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0 1rem 0;
|
||||
color: rgb(250 250 250);
|
||||
mix-blend-mode: plus-lighter;
|
||||
z-index: 1;
|
||||
@@ -77,29 +74,11 @@ import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
font-size: 2.5rem;
|
||||
line-height: 3rem;
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
font-weight: 300;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
margin: 1rem 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +117,7 @@ import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, SharedPipesModule, TickerComponent],
|
||||
imports: [SharedPipesModule, TickerComponent],
|
||||
})
|
||||
export class MarketplacePackageHeroComponent {
|
||||
@Input({ required: true })
|
||||
@@ -1,10 +1,9 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { TuiIcon, TuiTitle } from '@taiga-ui/core'
|
||||
import { TuiFade } from '@taiga-ui/kit'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-additional-item',
|
||||
selector: 'marketplace-item',
|
||||
template: `
|
||||
<label tuiTitle>
|
||||
<span tuiSubtitle>{{ label }}</span>
|
||||
@@ -35,9 +34,9 @@ import { TuiFade } from '@taiga-ui/kit'
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, TuiIcon, TuiTitle, TuiFade],
|
||||
imports: [TuiIcon, TuiTitle, TuiFade],
|
||||
})
|
||||
export class MarketplaceAdditionalItemComponent {
|
||||
export class MarketplaceItemComponent {
|
||||
@Input({ required: true })
|
||||
label!: string
|
||||
|
||||
23
web/projects/marketplace/src/pages/show/link.component.ts
Normal file
23
web/projects/marketplace/src/pages/show/link.component.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { MarketplaceItemComponent } from './item.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-link',
|
||||
template: `
|
||||
<a [href]="url" target="_blank" rel="noreferrer">
|
||||
<marketplace-item [label]="label" [icon]="icon" [data]="url" />
|
||||
</a>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [MarketplaceItemComponent],
|
||||
})
|
||||
export class MarketplaceLinkComponent {
|
||||
@Input({ required: true })
|
||||
label!: string
|
||||
|
||||
@Input({ required: true })
|
||||
icon!: string
|
||||
|
||||
@Input({ required: true })
|
||||
url!: string
|
||||
}
|
||||
128
web/projects/marketplace/src/pages/show/links.component.ts
Normal file
128
web/projects/marketplace/src/pages/show/links.component.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
input,
|
||||
} from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { CopyService } from '@start9labs/shared'
|
||||
import { MarketplacePkgBase } from '../../types'
|
||||
import { MarketplaceLinkComponent } from './link.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-links',
|
||||
template: `
|
||||
<div class="background-border shadow-color-light box-shadow-lg">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">Source Code</h2>
|
||||
<div class="detail-container">
|
||||
<marketplace-link
|
||||
[url]="pkg().upstreamRepo"
|
||||
label="Upstream Service"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
<marketplace-link
|
||||
[url]="pkg().wrapperRepo"
|
||||
label="StartOS Package"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="background-border shadow-color-light box-shadow-lg">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">Links</h2>
|
||||
<div class="detail-container">
|
||||
<marketplace-link
|
||||
[url]="pkg().marketingSite"
|
||||
label="Marketing"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
@if (pkg().docsUrl; as docsUrl) {
|
||||
<marketplace-link
|
||||
[url]="docsUrl"
|
||||
label="Documentation"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
}
|
||||
<marketplace-link
|
||||
[url]="pkg().supportSite"
|
||||
label="Support"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
@if (pkg().donationUrl; as donationUrl) {
|
||||
<marketplace-link
|
||||
[url]="donationUrl"
|
||||
label="Donations"
|
||||
icon="@tui.external-link"
|
||||
class="item-pointer"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: `
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
}
|
||||
|
||||
.detail-container {
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
|
||||
& > * + * {
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 0;
|
||||
border-color: rgb(113 113 122);
|
||||
}
|
||||
}
|
||||
|
||||
.item-pointer:hover {
|
||||
cursor: pointer;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.item-copy:hover {
|
||||
cursor: copy;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: copy;
|
||||
}
|
||||
}
|
||||
|
||||
.item-padding {
|
||||
padding: 0.75rem 0.25rem;
|
||||
}
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: rgb(var(--tw-color-gray-200) / 1);
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [MarketplaceLinkComponent],
|
||||
})
|
||||
export class MarketplaceLinksComponent {
|
||||
readonly copyService = inject(CopyService)
|
||||
readonly url =
|
||||
inject(ActivatedRoute).snapshot.queryParamMap.get('url') || undefined
|
||||
|
||||
readonly pkg = input.required<MarketplacePkgBase>()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ChangeDetectionStrategy, Component, input } from '@angular/core'
|
||||
import { MarkdownPipe } from '@start9labs/shared'
|
||||
import { NgDompurifyPipe } from '@taiga-ui/dompurify'
|
||||
import { MarketplacePkgBase } from '../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-release-notes',
|
||||
template: `
|
||||
<div class="background-border box-shadow-lg shadow-color-light">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">New in {{ pkg().version }}</h2>
|
||||
<p [innerHTML]="pkg().releaseNotes | markdown | dompurify"></p>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: `
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgDompurifyPipe, MarkdownPipe],
|
||||
})
|
||||
export class MarketplaceReleaseNotesComponent {
|
||||
readonly pkg = input.required<MarketplacePkgBase>()
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import { TuiCarousel } from '@taiga-ui/kit'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
@@ -7,73 +5,72 @@ import {
|
||||
Input,
|
||||
} from '@angular/core'
|
||||
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
|
||||
import { TuiDialogContext, TuiDialogService, TuiButton } from '@taiga-ui/core'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { TuiButton, TuiDialogContext, TuiDialogService } from '@taiga-ui/core'
|
||||
import { TuiCarousel } from '@taiga-ui/kit'
|
||||
import { PolymorpheusContent } from '@taiga-ui/polymorpheus'
|
||||
import { MarketplacePkg } from '../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-package-screenshots',
|
||||
template: `
|
||||
<!--@TODO future release-->
|
||||
<div
|
||||
*ngIf="$any(pkg).screenshots as screenshots"
|
||||
tuiCarouselButtons
|
||||
class="outer-container"
|
||||
>
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="flat-grayscale"
|
||||
iconStart="@tui.chevron-left"
|
||||
title="Previous"
|
||||
type="button"
|
||||
(click)="carousel.prev()"
|
||||
></button>
|
||||
<tui-carousel
|
||||
#carousel
|
||||
[itemsCount]="isMobile ? 1 : 2"
|
||||
[(index)]="index"
|
||||
class="carousel"
|
||||
>
|
||||
<ng-container *ngFor="let item of screenshots; let i = index">
|
||||
<div
|
||||
*tuiItem
|
||||
draggable="false"
|
||||
[class.item_active]="i === index + 1"
|
||||
class="screenshot-item"
|
||||
>
|
||||
<img
|
||||
#template
|
||||
alt="Service screenshot"
|
||||
src="assets/img/temp/{{ item }}"
|
||||
class="screenshot-item-img"
|
||||
(click)="presentModalImg(dialogTemplate)"
|
||||
/>
|
||||
<ng-template #dialogTemplate let-observer>
|
||||
@if ($any(pkg).screenshots; as screenshots) {
|
||||
<div tuiCarouselButtons class="outer-container">
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="flat-grayscale"
|
||||
iconStart="@tui.chevron-left"
|
||||
title="Previous"
|
||||
type="button"
|
||||
(click)="carousel.prev()"
|
||||
></button>
|
||||
<tui-carousel
|
||||
#carousel
|
||||
[itemsCount]="isMobile ? 1 : 2"
|
||||
[(index)]="index"
|
||||
class="carousel"
|
||||
>
|
||||
@for (item of screenshots; track item; let i = $index) {
|
||||
<div
|
||||
*tuiItem
|
||||
draggable="false"
|
||||
[class.item_active]="i === index + 1"
|
||||
class="screenshot-item"
|
||||
>
|
||||
<img
|
||||
#template
|
||||
alt="Service screenshot"
|
||||
src="assets/img/temp/{{ item }}"
|
||||
class="screenshot-item-img-enlarged"
|
||||
class="screenshot-item-img"
|
||||
(click)="presentModalImg(dialogTemplate)"
|
||||
/>
|
||||
</ng-template>
|
||||
</div>
|
||||
</ng-container>
|
||||
</tui-carousel>
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="flat-grayscale"
|
||||
type="button"
|
||||
iconStart="@tui.chevron-right"
|
||||
title="Next"
|
||||
(click)="carousel.next()"
|
||||
></button>
|
||||
</div>
|
||||
<ng-template #dialogTemplate let-observer>
|
||||
<img
|
||||
alt="Service screenshot"
|
||||
src="assets/img/temp/{{ item }}"
|
||||
class="screenshot-item-img-enlarged"
|
||||
/>
|
||||
</ng-template>
|
||||
</div>
|
||||
}
|
||||
</tui-carousel>
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="flat-grayscale"
|
||||
type="button"
|
||||
iconStart="@tui.chevron-right"
|
||||
title="Next"
|
||||
(click)="carousel.next()"
|
||||
></button>
|
||||
</div>
|
||||
}
|
||||
`,
|
||||
styles: `
|
||||
.outer-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
margin-left: -3.5rem;
|
||||
@@ -123,7 +120,7 @@ import { PolymorpheusContent } from '@taiga-ui/polymorpheus'
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, TuiCarousel, TuiButton],
|
||||
imports: [TuiCarousel, TuiButton],
|
||||
})
|
||||
export class MarketplacePackageScreenshotComponent {
|
||||
private readonly dialogs = inject(TuiDialogService)
|
||||
102
web/projects/marketplace/src/pages/show/versions.component.ts
Normal file
102
web/projects/marketplace/src/pages/show/versions.component.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
TemplateRef,
|
||||
} from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { DialogService, i18nPipe, SharedPipesModule } from '@start9labs/shared'
|
||||
import { TuiButton, TuiDialogContext } from '@taiga-ui/core'
|
||||
import { TuiRadioList } from '@taiga-ui/kit'
|
||||
import { filter } from 'rxjs'
|
||||
import { MarketplaceItemComponent } from './item.component'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-versions',
|
||||
template: `
|
||||
<div class="background-border shadow-color-light box-shadow-lg">
|
||||
<div class="box-container">
|
||||
<h2 class="additional-detail-title">Versions</h2>
|
||||
<marketplace-item
|
||||
(click)="promptSelectVersion(versionSelect)"
|
||||
data="Select another version"
|
||||
icon="@tui.chevron-right"
|
||||
label=""
|
||||
class="select"
|
||||
/>
|
||||
<ng-template
|
||||
#versionSelect
|
||||
let-data="data"
|
||||
let-completeWith="completeWith"
|
||||
>
|
||||
<tui-radio-list [items]="versions()" [(ngModel)]="data.version" />
|
||||
<footer class="buttons">
|
||||
<button
|
||||
tuiButton
|
||||
appearance="secondary"
|
||||
(click)="completeWith(null)"
|
||||
>
|
||||
{{ 'Cancel' | i18n }}
|
||||
</button>
|
||||
<button
|
||||
tuiButton
|
||||
appearance="secondary"
|
||||
(click)="completeWith(data.version)"
|
||||
>
|
||||
{{ 'Ok' | i18n }}
|
||||
</button>
|
||||
</footer>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: `
|
||||
.box-container {
|
||||
background-color: rgb(39 39 42);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
}
|
||||
|
||||
.select {
|
||||
border: 0;
|
||||
// border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-color: rgb(113 113 122);
|
||||
border-style: solid;
|
||||
cursor: pointer;
|
||||
|
||||
::ng-deep label {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
MarketplaceItemComponent,
|
||||
TuiButton,
|
||||
SharedPipesModule,
|
||||
FormsModule,
|
||||
TuiRadioList,
|
||||
i18nPipe,
|
||||
],
|
||||
})
|
||||
export class MarketplaceVersionsComponent {
|
||||
private readonly dialog = inject(DialogService)
|
||||
readonly version = input.required<string | null>()
|
||||
readonly versions = input.required<string[]>()
|
||||
|
||||
onVersion = output<string>()
|
||||
|
||||
promptSelectVersion(template: TemplateRef<TuiDialogContext>) {
|
||||
this.dialog
|
||||
.openComponent<string>(template, {
|
||||
label: 'All versions',
|
||||
size: 's',
|
||||
data: { version: this.version() },
|
||||
})
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(selected => this.onVersion.emit(selected))
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,17 @@ export * from './pages/list/item/item.component'
|
||||
export * from './pages/list/item/item.module'
|
||||
export * from './pages/list/search/search.component'
|
||||
export * from './pages/list/search/search.module'
|
||||
export * from './pages/show/about/about.component'
|
||||
export * from './pages/show/about/about.module'
|
||||
export * from './pages/show/additional/additional-link.component'
|
||||
export * from './pages/show/additional/additional-item.component'
|
||||
export * from './pages/show/additional/additional.component'
|
||||
export * from './pages/show/additional/additional.module'
|
||||
export * from './pages/show/link.component'
|
||||
export * from './pages/show/item.component'
|
||||
export * from './pages/show/links.component'
|
||||
export * from './pages/show/dependencies/dependencies.component'
|
||||
export * from './pages/show/dependencies/dependency-item.component'
|
||||
export * from './pages/show/screenshots/screenshots.component'
|
||||
export * from './pages/show/hero/hero.component'
|
||||
export * from './pages/show/flavors/flavors.component'
|
||||
export * from './pages/show/about.component'
|
||||
export * from './pages/show/screenshots.component'
|
||||
export * from './pages/show/hero.component'
|
||||
export * from './pages/show/flavors.component'
|
||||
export * from './pages/show/versions.component'
|
||||
export * from './pages/show/release-notes.component'
|
||||
|
||||
export * from './pipes/filter-packages.pipe'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user