diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 748e5be..5f5b76d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -19,7 +19,7 @@ jobs: build: strategy: matrix: - node-version: [10.13.0, 12.x, 14.x, 15.x] + node-version: [14.x] # The type of runner that the job will run on runs-on: windows-latest diff --git a/package.json b/package.json index af90e69..fa1511a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "msfs-community-downloader", - "version": "0.4.0", + "version": "0.5.0", "description": "MSFS addin downloader client", "homepage": "https://github.com/nicolasconstant/msfs-community-downloader", "author": { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 80f4e47..5e967d4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -16,6 +16,12 @@ import { SettingsModule } from './settings/settings.module'; import { AppComponent } from './app.component'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { ImportModule } from './import/import.module'; + +// import { AddPackageComponent } from './import/add-package.component'; +// import { CreatePackageComponent } from './import/create-package/create-package.component'; +// import { ImportPackageComponent } from './import/import-package/import-package.component'; +// import { ExportPackageComponent } from './import/export-package/export-package.component'; // AoT requires an exported function for factories export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { @@ -31,6 +37,7 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { CoreModule, SharedModule, HomeModule, + ImportModule, SettingsModule, AppRoutingModule, FontAwesomeModule, diff --git a/src/app/core/services/domain.service.ts b/src/app/core/services/domain.service.ts index 880b502..cf93015 100644 --- a/src/app/core/services/domain.service.ts +++ b/src/app/core/services/domain.service.ts @@ -10,8 +10,7 @@ import { SettingsService } from './settings.service'; @Injectable({ providedIn: 'root' }) -export class DomainService { - +export class DomainService { private packages: Package[]; private downloadSub: Subscription; private downloadUpdateSub: Subscription; @@ -25,7 +24,7 @@ export class DomainService { private githubService: GithubService, private downloaderService: DownloaderService, private extractorService: ExtractorService, - private settingsService: SettingsService + private settingsService: SettingsService ) { this.downloadSub = downloaderService.fileDownloaded.subscribe(r => { if (r) { @@ -53,7 +52,11 @@ export class DomainService { let pipeline: Promise = Promise.resolve(true); packages.forEach(x => { pipeline = pipeline.then(() => { - return this.analysePackage(x); + return this.analysePackage(x) + .catch(err => { + console.error(err); + x.state = InstallStatusEnum.error; + }); }); }); return pipeline; @@ -65,26 +68,37 @@ export class DomainService { return Promise.all([localPromise, githubPromise]) .then(result => { - p.localVersion = result[0].version; - p.availableVersion = result[1].availableVersion; - p.assetDownloadUrl = result[1].downloadUrl; - p.state = this.getState(p, result[0], result[1]); - p.publishedAt = result[1].publishedAt; + const local = result[0]; + const remote = result [1]; + + if(local){ + p.localVersion = local.version; + } + + if(remote) { + p.availableVersion = remote.availableVersion; + p.assetDownloadUrl = remote.downloadUrl; + p.publishedAt = remote.publishedAt; + } + + p.state = this.getState(p, local, remote); }); } private getState(p: Package, local: LocalState, info: PackageInfo): InstallStatusEnum { if (p.state === InstallStatusEnum.downloading) return InstallStatusEnum.downloading; if (p.state === InstallStatusEnum.extracting) return InstallStatusEnum.extracting; - if (p.state === InstallStatusEnum.installing) return InstallStatusEnum.installing; + if (p.state === InstallStatusEnum.installing) return InstallStatusEnum.installing; - if (local.untrackedFolderFound) return InstallStatusEnum.untrackedPackageFound; - if (!local.folderFound) return InstallStatusEnum.notFound; - if (local.version && info.availableVersion) { + if (local && local.untrackedFolderFound) return InstallStatusEnum.untrackedPackageFound; + if (local && !local.folderFound) return InstallStatusEnum.notFound; + if (local && local.version && info && info.availableVersion) { if (local.version === info.availableVersion) return InstallStatusEnum.installed; if (local.version !== info.availableVersion) return InstallStatusEnum.updateAvailable; } - return InstallStatusEnum.notFound; + + if (p.state === InstallStatusEnum.error) return InstallStatusEnum.error; + return InstallStatusEnum.unknown; } private processDownloadedFile(r: FileDownloadInfo): void { @@ -143,16 +157,78 @@ export class DomainService { this.app.tick(); } - getPackages(): Promise { + getPackages(): Package[] { if (this.packages) { - return Promise.resolve(this.packages); + return this.packages; } - return this.packageService.getPackages() - .then(p => { - this.packages = p; - return p; - }); + this.packages = this.packageService.getPackages(); + return this.packages; + } + + addCustomPackage(p: Package): void { + if(!this.packages) { + this.getPackages(); + } + + this.packages.forEach(x => x.isSelected = false); + + const settings = this.settingsService.getSettings(); + settings.customPackages.push(p); + this.settingsService.saveSettings(settings); + + this.packages.unshift(p); + p.state = InstallStatusEnum.unknown; + p.isCustomPackage = true; + p.isSelected = true; + this.analysePackage(p); + } + + updateCustomPackage(p: Package): void { + if(!p) return; + + const settings = this.settingsService.getSettings(); + const toUpdate = settings.customPackages.find(x => x.id === p.id); + + toUpdate.id = p.id; + toUpdate.name = p.name; + toUpdate.description = p.description; + toUpdate.summary = p.summary; + toUpdate.githubOwner = p.githubOwner; + toUpdate.githubRepo = p.githubRepo; + toUpdate.assetName = p.assetName; + toUpdate.isPrerelease = p.isPrerelease; + toUpdate.folderName = p.folderName; + toUpdate.illustration = p.illustration; + toUpdate.webpageUrl = p.webpageUrl; + toUpdate.versionPatternToRemove = p.versionPatternToRemove; + + this.settingsService.saveSettings(settings); + + const localToUpdate = this.packages.find(x => x.id === p.id); + + localToUpdate.id = p.id; + localToUpdate.name = p.name; + localToUpdate.description = p.description; + localToUpdate.summary = p.summary; + localToUpdate.githubOwner = p.githubOwner; + localToUpdate.githubRepo = p.githubRepo; + localToUpdate.assetName = p.assetName; + localToUpdate.isPrerelease = p.isPrerelease; + localToUpdate.folderName = p.folderName; + localToUpdate.illustration = p.illustration; + localToUpdate.webpageUrl = p.webpageUrl; + localToUpdate.versionPatternToRemove = p.versionPatternToRemove; + } + + removeCustomPackage(p: Package): void { + if(!p) return; + + const settings = this.settingsService.getSettings(); + settings.customPackages = settings.customPackages.filter(x => x.id !== p.id); + this.settingsService.saveSettings(settings); + + this.packages = this.packages.filter(x => x.id !== p.id); } install(p: Package): void { diff --git a/src/app/core/services/github.service.ts b/src/app/core/services/github.service.ts index 02d738f..2099a10 100644 --- a/src/app/core/services/github.service.ts +++ b/src/app/core/services/github.service.ts @@ -11,7 +11,7 @@ export class GithubService { constructor(private http: HttpClient) { } retrievePackageInfo(p: Package): Promise { - const route = `https://api.github.com/repos/${p.githubOwner}/${p.githubRepo}/releases`; + const route = `https://api.github.com/repos/${p.githubOwner}/${p.githubRepo}/releases?per_page=100`; return this.http.get(route).toPromise() .then((rel: GithubRelease[]) => { const lastRelease = rel @@ -19,6 +19,9 @@ export class GithubService { return new Date(b.published_at).getTime() - new Date(a.published_at).getTime(); }) .find(x => this.isCandidate(x, p)); + + if(!lastRelease) return null; + const asset = lastRelease.assets.find(y => y.name.includes(p.assetName)); let downloadUrl = lastRelease.zipball_url; @@ -32,8 +35,13 @@ export class GithubService { } private isCandidate(rel: GithubRelease, p: Package): boolean { + let keepPrerelease = false; + if(p.isPrerelease) { + keepPrerelease = true; + } + return rel.draft === false - && rel.prerelease === false + && rel.prerelease === keepPrerelease && (!p.assetName || rel.assets.findIndex(y => y.name.includes(p.assetName)) !== -1); } } diff --git a/src/app/core/services/packages.service.ts b/src/app/core/services/packages.service.ts index 9844764..346a0a2 100644 --- a/src/app/core/services/packages.service.ts +++ b/src/app/core/services/packages.service.ts @@ -1,12 +1,15 @@ import { Injectable } from '@angular/core'; +import { SettingsService } from './settings.service'; @Injectable({ providedIn: 'root' }) export class PackagesService { - constructor() { } + constructor( + private settingsService: SettingsService + ) { } - getPackages(): Promise { + getPackages(): Package[] { const wtcj4 = new Package(); wtcj4.id = "wt-cj4"; wtcj4.name = "WT CJ4"; @@ -19,7 +22,7 @@ export class PackagesService { wtcj4.versionPatternToRemove = "cj4-"; wtcj4.state = InstallStatusEnum.unknown; wtcj4.summary = "OPEN BETA
Performance and avionics improvements for the Citation CJ4"; - wtcj4.webpageUrl = "https://www.workingtitle.aero/packages/cj4/"; + wtcj4.webpageUrl = "https://www.workingtitle.aero/packages/cj4/"; const wtg1000 = new Package(); wtg1000.id = "wt-g1000"; @@ -49,6 +52,21 @@ export class PackagesService { wtg3000.summary = "Fixes and enhancements for the stock G3000 avionics package"; wtg3000.webpageUrl = "https://www.workingtitle.aero/packages/g3000/"; + const wtg3x = new Package(); + wtg3x.id = "wt-g3x"; + wtg3x.name = "WT G3X"; + wtg3x.description = "Working Title G3X Touch"; + wtg3x.githubOwner = "Working-Title-MSFS-Mods"; + wtg3x.githubRepo = "fspackages"; + wtg3x.illustration = "assets/illustrations/g3x.jpg"; + wtg3x.folderName = "workingtitle-gx"; + wtg3x.assetName = "workingtitle-gx-v"; + wtg3x.versionPatternToRemove = "gx-"; + wtg3x.state = InstallStatusEnum.unknown; + wtg3x.summary = "This is an early release of what is intended to eventually be the reworking of several of the smaller Garmin units in the game.

At the moment the only thing that has been updated is the G3X Touch, but future modifications to the non-touch G3X, and to the touch-based Aera which uses much of the same code, are possible."; + wtg3x.webpageUrl = "https://www.workingtitle.aero/packages/g3x/"; + wtg3x.isPrerelease = true; + const a32nx = new Package(); a32nx.id = "a32nx"; a32nx.name = "FBW A32NX"; @@ -62,17 +80,6 @@ export class PackagesService { a32nx.summary = "The A32NX Project is a community-driven open source project to create a free Airbus A320neo in Microsoft Flight Simulator that is as close to reality as possible.

The following aircraft configuration is currently simulated:

Model  A320-251N
Engine  CFM LEAP 1A-26
FMGS  Honeywell Pegasus II
FWC Std.  H2F9C

Please note that this configuration may change in the future as the A32NX project evolves and changes."; a32nx.webpageUrl = "https://flybywiresim.com/"; - // const wtg3x = new Package(); - // wtg3x.id = "wt-g3x"; - // wtg3x.name = "WT G3X"; - // wtg3x.description = "Working Title G3X Touch"; - // wtg3x.githubOwner = "Working-Title-MSFS-Mods"; - // wtg3x.githubRepo = "fspackages"; - // wtg3x.illustration = "assets/illustrations/aa.jpg"; - // wtg3x.folderName = "workingtitle-g3000"; - // wtg3x.assetName = "workingtitle-g3000-v"; - // wtg3x.state = InstallStatusEnum.unknown; - const b787xe = new Package(); b787xe.id = "b787xe"; b787xe.name = "HD B78XH"; @@ -133,47 +140,29 @@ export class PackagesService { jplc152.assetName = "jplogistics-c152-"; jplc152.state = InstallStatusEnum.unknown; jplc152.summary = "A MSFS Addon to improve the Cessna C152 "; + + const pms50gns530 = new Package(); + pms50gns530.id = "pms50gns530"; + pms50gns530.name = "PMS50 GNS530"; + pms50gns530.description = "Pimarc PMS50 GNS530"; + pms50gns530.githubOwner = "pimarc"; + pms50gns530.githubRepo = "pms50-gns530"; + pms50gns530.illustration = "assets/illustrations/pms50gns530.jpg"; + pms50gns530.folderName = "pms50-gns530"; + pms50gns530.assetName = "pms50-gns530.zip"; + pms50gns530.state = InstallStatusEnum.unknown; + pms50gns530.summary = "This package is an enhancement of the built-in GNS530 GPS. The goal is to offer an instrument that comes as close as possible to the original."; - return Promise.resolve([wtcj4, wtg1000, wtg3000, a32nx, b787xe, salty747, aa, tfg36p, jplc152]); - - // new Package(); - // "aa-liv", - // "AA Liveries", - // "Azghar Airline Liveries", - // InstallStatusEnum.installed, - // null, - // "1.0.0", - // "dites33", - // "aa", - // null, - // "url", - // "assets/illustrations/aa.jpg", - // true - // ), - // new Package( - // "wt-cj4", - // "WT CJ4", - // "Working Title CJ4", - // InstallStatusEnum.notFound, - // null, - // "1.0.0", - // "url", - // "assets/illustrations/aa.jpg", - // false - // ), - // new Package( - // "aa-liv-3", - // "AA Liveries", - // "Azghar Airline Liveries", - // InstallStatusEnum.updateAvailable, - // null, - // "1.0.0", - // "url", - // "assets/illustrations/aa.jpg", - // false - // ) - - // ]); + const packages = [wtcj4, wtg1000, wtg3000, wtg3x, a32nx, b787xe, salty747, aa, tfg36p, jplc152, pms50gns530]; + const customPackages = this.settingsService.getSettings().customPackages; + + for (const p of customPackages) { + p.isCustomPackage = true; + p.state = InstallStatusEnum.unknown; + packages.unshift(p); + } + + return packages; } } @@ -189,6 +178,7 @@ export class Package { public githubOwner: string; public githubRepo: string; public assetName: string; + public isPrerelease: boolean; public versionPatternToRemove: string; public folderName: string; public assetDownloadUrl: string; @@ -201,7 +191,9 @@ export class Package { public summary: string; public webpageUrl: string; - public oldFolderNames: string[]; //TODO + public oldFolderNames: string[]; + + public isCustomPackage: boolean; } export enum InstallStatusEnum { diff --git a/src/app/core/services/settings.service.ts b/src/app/core/services/settings.service.ts index 747b0c5..7239450 100644 --- a/src/app/core/services/settings.service.ts +++ b/src/app/core/services/settings.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { ElectronService } from './electron/electron.service'; +import { Package } from './packages.service'; @Injectable({ providedIn: 'root' @@ -18,6 +19,10 @@ export class SettingsService { this.saveSettings(settings); } } + if(!settings.customPackages){ + settings.customPackages = []; + this.saveSettings(settings); + } return settings; } @@ -95,7 +100,7 @@ export class SettingsService { } } - private saveSettings(settings: SettingsData) { + saveSettings(settings: SettingsData): void { const json = JSON.stringify(settings); localStorage.setItem('settings', json); } @@ -103,4 +108,5 @@ export class SettingsService { class SettingsData { communityPath: string; + customPackages: Package[]; } \ No newline at end of file diff --git a/src/app/home/home-routing.module.ts b/src/app/home/home-routing.module.ts index 93d9df2..931ce08 100644 --- a/src/app/home/home-routing.module.ts +++ b/src/app/home/home-routing.module.ts @@ -1,6 +1,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Routes, RouterModule } from '@angular/router'; + import { HomeComponent } from './home.component'; import { CommunityfolderGuard } from '../core/guards/communityfolder.guard'; diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 859df70..cf701b1 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,5 +1,11 @@ +
Remove @@ -8,7 +23,7 @@ Install {{getWorkingInfo()}} -
+

{{package.name}}

{{package.description}}

diff --git a/src/app/home/package-detailed/package-detailed.component.scss b/src/app/home/package-detailed/package-detailed.component.scss index d9f455a..2128ac8 100644 --- a/src/app/home/package-detailed/package-detailed.component.scss +++ b/src/app/home/package-detailed/package-detailed.component.scss @@ -80,6 +80,53 @@ } } +.edit-buttons { + // outline: 1px dotted greenyellow; + + float: right; + margin: 20px 20px 0 0; + + &__button { + display: inline-block; + width: 40px; + height: 40px; + border: 1px solid #dbdbdb; + color: #dbdbdb; + border-radius: 3px; + text-decoration: none; + margin-left: 15px; + opacity: .5; + padding: 7px 0 0 0; + font-size: 18px; + text-align: center; + transition: all .2s; + background-color: rgba(#000000, 0.15); + + &:hover { + opacity: 1; + border: 1px solid white; + color: white; + background-color: rgba(#000000, 0.3); + } + + &__export { + padding-right: 1px; + } + + &__delete { + padding-right: 1px; + + &:hover { + border: 1px solid #ff3232; + color: #ff3232; + // background-color: rgba(#ffffff, 0.3); + } + } + + } + +} + .package-detailed::-webkit-scrollbar { width: 12px; /* width of the entire scrollbar */ diff --git a/src/app/home/package-detailed/package-detailed.component.ts b/src/app/home/package-detailed/package-detailed.component.ts index a8f1d4f..5dac7e9 100644 --- a/src/app/home/package-detailed/package-detailed.component.ts +++ b/src/app/home/package-detailed/package-detailed.component.ts @@ -1,9 +1,12 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, Output } from '@angular/core'; import { faGithub } from '@fortawesome/free-brands-svg-icons'; +import { Subject } from 'rxjs'; +import { faArrowDown, faTrash, faTrashAlt, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { Package, InstallStatusEnum } from '../../core/services/packages.service'; import { DomainService } from '../../core/services/domain.service'; + @Component({ selector: 'app-package-detailed', templateUrl: './package-detailed.component.html', @@ -11,10 +14,17 @@ import { DomainService } from '../../core/services/domain.service'; }) export class PackageDetailedComponent implements OnInit { faGithub = faGithub; + faArrowDown = faArrowDown; + faTrash = faTrash; + faTrashAlt = faTrashAlt; + faPencilAlt = faPencilAlt; @Input() package: Package; updatingStatus: string; + @Output() + deletedEvent = new Subject(); + constructor( private domainService: DomainService, ) { } @@ -61,4 +71,12 @@ export class PackageDetailedComponent implements OnInit { if(!pattern || !version) return version; return version.replace(pattern, ''); } + + removePackage(): boolean { + if(!this.package.isCustomPackage) return false; + + this.domainService.removeCustomPackage(this.package); + this.deletedEvent.next(this.package); + return false; + } } diff --git a/src/app/import/add-package.component.html b/src/app/import/add-package.component.html new file mode 100644 index 0000000..f39eb88 --- /dev/null +++ b/src/app/import/add-package.component.html @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/src/app/import/add-package.component.scss b/src/app/import/add-package.component.scss new file mode 100644 index 0000000..33a8dde --- /dev/null +++ b/src/app/import/add-package.component.scss @@ -0,0 +1,33 @@ +.add-package { + color: whitesmoke; + height: 100%; + // position: relative; + + &__content { + width: 700px; + padding-top: 50px; + margin: auto; + overflow: hidden; + } +} + +.button { + color: whitesmoke; + display: block; + margin: auto; + width: 250px; + text-align: center; + // height: 50px; + border-radius: 5px; + border: 1px solid white; + margin-bottom: 30px; + padding: 10px; + text-decoration: none; + + &--cancel { + margin-bottom: 50px; + color: #ca0000; + border-color: #ca0000; + margin-top: 70px; + } +} \ No newline at end of file diff --git a/src/app/import/add-package.component.spec.ts b/src/app/import/add-package.component.spec.ts new file mode 100644 index 0000000..1ff1d4b --- /dev/null +++ b/src/app/import/add-package.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddPackageComponent } from './add-package.component'; + +describe('AddPackageComponent', () => { + let component: AddPackageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AddPackageComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AddPackageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/import/add-package.component.ts b/src/app/import/add-package.component.ts new file mode 100644 index 0000000..1b868ee --- /dev/null +++ b/src/app/import/add-package.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-add-package', + templateUrl: './add-package.component.html', + styleUrls: ['./add-package.component.scss'] +}) +export class AddPackageComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/import/create-package/create-package.component.html b/src/app/import/create-package/create-package.component.html new file mode 100644 index 0000000..38cbdb8 --- /dev/null +++ b/src/app/import/create-package/create-package.component.html @@ -0,0 +1,84 @@ +
+
+
+

Create a new package

+

Edit package

+
+
+
+ + +

The id must be unique among all packages.

+
+
+ + +

The name of the package's folder. Must be unique amongs all other packages. Usually the name of the folder inside the zip package.

+
+
+ + +

The name displayed in the left panel.

+
+
+ + +

The full name displayed under the name in the right panel.

+
+
+ + +

Short (or long) description of the package.

+
+
+ + +

The name of the github owner.
If the URL is https://github.com/my-name/my-package the owner is "my-name".

+
+
+ + +

The name of the github repository.
If the URL is https://github.com/my-name/my-package the repository is "my-package".

+
+
+ + +

The name of the zip file of the package.
If it changes every version, just enter the first part that is common. For example if a package is released via a zip called "my-package-v0.5.0.zip" enter "my-package-v" in this field.
If the package isn't released via a zip, leave empty.

+
+
+ + +

If this package is released with the Github tag "Prerelease".

+
+
+ + +

The URL of the illustration. The recommended size is 1500x530px.

+
+
+ + +

Optionnal.
If the package has a landing page, official website, etc, enter the URL here.

+
+
+ + +

Optionnal.
If the version is messed up, you can clean-up for display purposes. If the version is released like "data-v0.5.0", enter "data-" to remove this part in the interface.

+
+
+ +
+
\ No newline at end of file diff --git a/src/app/import/create-package/create-package.component.scss b/src/app/import/create-package/create-package.component.scss new file mode 100644 index 0000000..6544f01 --- /dev/null +++ b/src/app/import/create-package/create-package.component.scss @@ -0,0 +1,147 @@ +.add-package { + color: whitesmoke; + height: 100%; + // position: relative; + + &__content { + width: 700px; + margin: auto; + // padding: 20px; + // position: relative; + } + + + &__header { + // outline: 1px dotted purple; + + height: 60px; + width: calc(100%); + + &__title { + padding: 15px 0 0 210px; + font-size: 1.2em; + } + } + + &__new-package { + // outline: 1px dotted greenyellow; + + // height: calc(100% - 60px); + width: 700px; + + position: absolute; + top: 60px; + bottom: 80px; + + overflow: auto; + + &::-webkit-scrollbar { + width: 12px; + /* width of the entire scrollbar */ + } + + &::-webkit-scrollbar-track { + background: rgba(36, 39, 46, 0); + /* color of the tracking area */ + } + + &::-webkit-scrollbar-thumb { + background-color: rgb(74, 74, 95); + background-color: rgb(104, 104, 104); + /* color of the scroll thumb */ + border-radius: 20px; + /* roundness of the scroll thumb */ + border: 3px solid #1a1a1a; + /* creates padding around scroll thumb */ + } + } + + + + &__footer { + // outline: 1px dotted yellow; + + position: absolute; + bottom: 0; + height: 80px; + width: 700px; + } +} + +.entry { + padding: 10px; + font-size: 1.1em; + + &__label { + display: inline-block; + width: 200px; + text-align: right; + padding-right: 20px; + // position: relative; + // top: 2px; + } + + &__input { + padding: 5px; + height: 30px; + width: 240px; + font-size: 1em; + + &--long { + width: 460px; + } + } + + &__description { + display: inline-block; + margin-left: 200px; + padding-top: 5px; + font-size: .8em; + } +} + +.button { + color: whitesmoke; + display: block; + margin: auto; + width: 150px; + text-align: center; + border-radius: 5px; + border: 1px solid white; + padding: 10px; + text-decoration: none; + + &--cancel { + color: #ca0000; + border-color: #ca0000; + + float: left; + + position: relative; + top: 20px; + left: 20px; + } + + &--save { + float: right; + + position: relative; + top: 20px; + right: 20px; + + cursor: pointer; + -webkit-user-select: none; + + } +} + +.error { + float: left; + color: red; + + // position: relative; + // top: 10px; + + margin-top: 30px; + margin-left: 50px; +} \ No newline at end of file diff --git a/src/app/import/create-package/create-package.component.spec.ts b/src/app/import/create-package/create-package.component.spec.ts new file mode 100644 index 0000000..aa6c90c --- /dev/null +++ b/src/app/import/create-package/create-package.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreatePackageComponent } from './create-package.component'; + +describe('CreatePackageComponent', () => { + let component: CreatePackageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ CreatePackageComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CreatePackageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/import/create-package/create-package.component.ts b/src/app/import/create-package/create-package.component.ts new file mode 100644 index 0000000..6f91488 --- /dev/null +++ b/src/app/import/create-package/create-package.component.ts @@ -0,0 +1,88 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; +import { Subscription } from 'rxjs'; + +import { Package } from '../../core/services/packages.service'; +import { DomainService } from '../../core/services/domain.service'; + +@Component({ + selector: 'app-create-package', + templateUrl: './create-package.component.html', + styleUrls: ['./create-package.component.scss'] +}) +export class CreatePackageComponent implements OnInit, OnDestroy { + + error: boolean; + errorMessage: string; + package: Package; + + isEditing: boolean; + + sub: Subscription; + + constructor( + private activatedRoute: ActivatedRoute, + private router: Router, + private domainService: DomainService + ) { } + + ngOnInit(): void { + this.sub = this.activatedRoute.params.subscribe(params => { + const id = params['id']; + + this.package = new Package(); + + if(id){ + this.isEditing = true; + + const p = this.domainService.getPackages().find(x => x.id === id); + this.package.id = p.id; + this.package.name = p.name; + this.package.description = p.description; + this.package.summary = p.summary; + this.package.githubOwner = p.githubOwner; + this.package.githubRepo = p.githubRepo; + this.package.assetName = p.assetName; + this.package.isPrerelease = p.isPrerelease; + this.package.folderName = p.folderName; + this.package.illustration = p.illustration; + this.package.webpageUrl = p.webpageUrl; + this.package.versionPatternToRemove = p.versionPatternToRemove; + } else { + this.isEditing = false; + } + }); + } + + ngOnDestroy(): void { + if(this.sub) this.sub.unsubscribe(); + } + + save(): boolean { + this.error = false; + + const currentPackages = this.domainService.getPackages(); + + if (!this.isEditing && currentPackages.find(x => x.id === this.package.id)) { + this.error = true; + this.errorMessage = "A package has already this ID"; + return false; + } + + if (!this.isEditing && currentPackages.find(x => x.folderName === this.package.folderName)) { + this.error = true; + this.errorMessage = "A package has already this Folder Name"; + return false; + } + + if(this.isEditing){ + this.domainService.updateCustomPackage(this.package); + } else { + this.domainService.addCustomPackage(this.package); + } + + this.router.navigate(['/']); + return false; + } +} diff --git a/src/app/import/export-package/export-package.component.html b/src/app/import/export-package/export-package.component.html new file mode 100644 index 0000000..1cf3d8d --- /dev/null +++ b/src/app/import/export-package/export-package.component.html @@ -0,0 +1 @@ +

export-package works!

diff --git a/src/app/import/export-package/export-package.component.scss b/src/app/import/export-package/export-package.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/import/export-package/export-package.component.spec.ts b/src/app/import/export-package/export-package.component.spec.ts new file mode 100644 index 0000000..567a1f2 --- /dev/null +++ b/src/app/import/export-package/export-package.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExportPackageComponent } from './export-package.component'; + +describe('ExportPackageComponent', () => { + let component: ExportPackageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ExportPackageComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ExportPackageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/import/export-package/export-package.component.ts b/src/app/import/export-package/export-package.component.ts new file mode 100644 index 0000000..bffa909 --- /dev/null +++ b/src/app/import/export-package/export-package.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-export-package', + templateUrl: './export-package.component.html', + styleUrls: ['./export-package.component.scss'] +}) +export class ExportPackageComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/import/import-package/import-package.component.html b/src/app/import/import-package/import-package.component.html new file mode 100644 index 0000000..9a34a6f --- /dev/null +++ b/src/app/import/import-package/import-package.component.html @@ -0,0 +1 @@ +

import-package works!

diff --git a/src/app/import/import-package/import-package.component.scss b/src/app/import/import-package/import-package.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/import/import-package/import-package.component.spec.ts b/src/app/import/import-package/import-package.component.spec.ts new file mode 100644 index 0000000..2e578af --- /dev/null +++ b/src/app/import/import-package/import-package.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ImportPackageComponent } from './import-package.component'; + +describe('ImportPackageComponent', () => { + let component: ImportPackageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ImportPackageComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImportPackageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/import/import-package/import-package.component.ts b/src/app/import/import-package/import-package.component.ts new file mode 100644 index 0000000..c797743 --- /dev/null +++ b/src/app/import/import-package/import-package.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-import-package', + templateUrl: './import-package.component.html', + styleUrls: ['./import-package.component.scss'] +}) +export class ImportPackageComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/import/import-routing.module.ts b/src/app/import/import-routing.module.ts new file mode 100644 index 0000000..02a2432 --- /dev/null +++ b/src/app/import/import-routing.module.ts @@ -0,0 +1,44 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Routes, RouterModule } from '@angular/router'; + +import { AddPackageComponent } from './add-package.component'; +import { CreatePackageComponent } from './create-package/create-package.component'; +import { ImportPackageComponent } from './import-package/import-package.component'; +import { ExportPackageComponent } from './export-package/export-package.component'; +import { CommunityfolderGuard } from '../core/guards/communityfolder.guard'; + +const routes: Routes = [ + { + path: 'add-package', + component: AddPackageComponent, + canActivate: [CommunityfolderGuard] + }, + { + path: 'create-package', + component: CreatePackageComponent, + canActivate: [CommunityfolderGuard] + }, + { + path: 'create-package/:id', + component: CreatePackageComponent, + canActivate: [CommunityfolderGuard] + }, + { + path: 'import-package', + component: ImportPackageComponent, + canActivate: [CommunityfolderGuard] + }, + { + path: 'export-package/:id', + component: ExportPackageComponent, + canActivate: [CommunityfolderGuard] + } +]; + +@NgModule({ + declarations: [], + imports: [CommonModule, RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ImportRoutingModule { } diff --git a/src/app/import/import.module.ts b/src/app/import/import.module.ts new file mode 100644 index 0000000..dc10a61 --- /dev/null +++ b/src/app/import/import.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; + +import { SharedModule } from '../shared/shared.module'; +import { ImportRoutingModule } from './import-routing.module'; + +import { AddPackageComponent } from './add-package.component'; +import { CreatePackageComponent } from './create-package/create-package.component'; +import { ImportPackageComponent } from './import-package/import-package.component'; +import { ExportPackageComponent } from './export-package/export-package.component'; + +@NgModule({ + declarations: [AddPackageComponent, CreatePackageComponent, ImportPackageComponent, ExportPackageComponent], + imports: [CommonModule, SharedModule, ImportRoutingModule, FontAwesomeModule] + }) + export class ImportModule {} + \ No newline at end of file diff --git a/src/assets/illustrations/g3x.jpg b/src/assets/illustrations/g3x.jpg new file mode 100644 index 0000000..df169d6 Binary files /dev/null and b/src/assets/illustrations/g3x.jpg differ diff --git a/src/assets/illustrations/pms50gns530.jpg b/src/assets/illustrations/pms50gns530.jpg new file mode 100644 index 0000000..9614507 Binary files /dev/null and b/src/assets/illustrations/pms50gns530.jpg differ