mirror of
https://github.com/WowUp/WowUp.git
synced 2026-04-23 23:37:11 -04:00
App can now show unmatched addons
This commit is contained in:
@@ -3,7 +3,7 @@ import * as fs from "fs-extra";
|
||||
import * as async from "async";
|
||||
import * as path from "path";
|
||||
import * as admZip from "adm-zip";
|
||||
import { readdir } from "fs";
|
||||
import { readdir, stat } from "fs";
|
||||
import axios from "axios";
|
||||
|
||||
import {
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
GET_ASSET_FILE_PATH,
|
||||
DOWNLOAD_FILE_CHANNEL,
|
||||
CREATE_DIRECTORY_CHANNEL,
|
||||
STAT_FILES_CHANNEL,
|
||||
} from "./src/common/constants";
|
||||
import { CurseScanResult } from "./src/common/curse/curse-scan-result";
|
||||
import { CurseFolderScanner } from "./src/common/curse/curse-folder-scanner";
|
||||
@@ -70,6 +71,21 @@ export function initializeIpcHanders(window: BrowserWindow) {
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle(STAT_FILES_CHANNEL, async (evt, filePaths: string[]) => {
|
||||
const results: { [path: string]: fs.Stats } = {};
|
||||
await async.eachLimit<string>(filePaths, 3, (path, cb) => {
|
||||
fs.stat(path, (err, stats) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
results[path] = stats;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
return results;
|
||||
});
|
||||
|
||||
ipcMain.handle(PATH_EXISTS_CHANNEL, async (evt, filePath: string) => {
|
||||
console.log(PATH_EXISTS_CHANNEL, filePath);
|
||||
|
||||
|
||||
@@ -622,6 +622,7 @@ export class CurseAddonProvider implements AddonProvider {
|
||||
downloadCount: scanResult.searchResult.downloadCount,
|
||||
summary: scanResult.searchResult.summary,
|
||||
releasedAt: new Date(latestVersion.fileDate),
|
||||
isLoadOnDemand: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ export class TukUiAddonProvider implements AddonProvider {
|
||||
downloadCount: Number.parseFloat(tukUiAddon.downloads),
|
||||
screenshotUrls: [tukUiAddon.screenshot_url],
|
||||
releasedAt: new Date(`${tukUiAddon.lastupdate} UTC`),
|
||||
isLoadOnDemand: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +210,7 @@ export class WowInterfaceAddonProvider implements AddonProvider {
|
||||
screenshotUrls: response.images?.map((img) => img.imageUrl),
|
||||
downloadCount: response.downloads,
|
||||
releasedAt: new Date(response.lastUpdate),
|
||||
isLoadOnDemand: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -254,6 +254,7 @@ export class WowUpAddonProvider implements AddonProvider {
|
||||
patreonFundingLink: scanResult.exactMatch.patreon_funding_link,
|
||||
customFundingLink: scanResult.exactMatch.custom_funding_link,
|
||||
githubFundingLink: scanResult.exactMatch.github_funding_link,
|
||||
isLoadOnDemand: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ export class AddonViewModel {
|
||||
public stateTextTranslationKey: string = "";
|
||||
public selected: boolean = false;
|
||||
|
||||
get isLoadOnDemand() {
|
||||
return this.addon?.isLoadOnDemand;
|
||||
}
|
||||
|
||||
get installedAt() {
|
||||
return new Date(this.addon?.installedAt);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
>
|
||||
{{ getStatusText() | translate }}
|
||||
</div>
|
||||
<mat-icon
|
||||
<!-- <mat-icon
|
||||
*ngIf="this.listItem.isAutoUpdate === true"
|
||||
class="auto-update-icon"
|
||||
[matTooltip]="'PAGES.MY_ADDONS.TABLE.AUTO_UPDATE_ICON_TOOLTIP' | translate"
|
||||
>
|
||||
update
|
||||
</mat-icon>
|
||||
</mat-icon> -->
|
||||
</div>
|
||||
|
||||
@@ -1,64 +1,46 @@
|
||||
<div class="addon-column row align-items-center">
|
||||
<div class="addon-column row align-items-center" >
|
||||
<div class="thumbnail-container">
|
||||
<div
|
||||
*ngIf="listItem.hasThumbnail === true"
|
||||
class="addon-logo-container"
|
||||
[style.backgroundImage]="'url(' + listItem.addon.thumbnailUrl + ')'"
|
||||
></div>
|
||||
<div *ngIf="listItem.hasThumbnail === true" class="addon-logo-container"
|
||||
[style.backgroundImage]="'url(' + listItem.addon.thumbnailUrl + ')'"></div>
|
||||
<div *ngIf="listItem.hasThumbnail === false" class="addon-logo-container">
|
||||
<div class="addon-logo-letter">
|
||||
{{ listItem.thumbnailLetter }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="listItem.isBetaChannel || listItem.isAlphaChannel"
|
||||
class="channel"
|
||||
[ngClass]="{
|
||||
<div *ngIf="listItem.isBetaChannel || listItem.isAlphaChannel" class="channel" [ngClass]="{
|
||||
beta: listItem.isBetaChannel,
|
||||
alpha: listItem.isAlphaChannel
|
||||
}"
|
||||
>
|
||||
}">
|
||||
{{ listItem.isAlphaChannel ? "Alpha" : "Beta" }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
class="addon-title mat-subheading-2"
|
||||
(click)="viewDetails()"
|
||||
[ngClass]="{ ignored: listItem.isIgnored }"
|
||||
>{{ listItem.addon.name }}</a
|
||||
>
|
||||
<a class="addon-title mat-subheading-2" (click)="viewDetails()"
|
||||
[ngClass]="{ ignored: listItem.isIgnored }">{{ listItem.addon.name }}</a>
|
||||
<div class="addon-funding">
|
||||
<a
|
||||
*ngIf="listItem.addon.patreonFundingLink"
|
||||
appExternalLink
|
||||
[href]="listItem.addon.patreonFundingLink"
|
||||
matTooltip="Support the author on Patreon"
|
||||
>
|
||||
<a *ngIf="listItem.addon.patreonFundingLink" appExternalLink [href]="listItem.addon.patreonFundingLink"
|
||||
matTooltip="Support the author on Patreon">
|
||||
<img class="funding-icon" src="assets/images/patreon_logo_small.png" />
|
||||
</a>
|
||||
<a
|
||||
*ngIf="listItem.addon.githubFundingLink"
|
||||
appExternalLink
|
||||
[href]="listItem.addon.githubFundingLink"
|
||||
matTooltip="Support the author on GitHub"
|
||||
>
|
||||
<a *ngIf="listItem.addon.githubFundingLink" appExternalLink [href]="listItem.addon.githubFundingLink"
|
||||
matTooltip="Support the author on GitHub">
|
||||
<img class="funding-icon" src="assets/images/github_logo_small.png" />
|
||||
</a>
|
||||
<a
|
||||
*ngIf="listItem.addon.customFundingLink"
|
||||
appExternalLink
|
||||
[href]="listItem.addon.customFundingLink"
|
||||
matTooltip="Support this author"
|
||||
>
|
||||
<img
|
||||
class="funding-icon"
|
||||
src="assets/images/custom_funding_logo_small.png"
|
||||
/>
|
||||
<a *ngIf="listItem.addon.customFundingLink" appExternalLink [href]="listItem.addon.customFundingLink"
|
||||
matTooltip="Support this author">
|
||||
<img class="funding-icon" src="assets/images/custom_funding_logo_small.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="addon-version" [ngClass]="{ ignored: listItem.isIgnored }">
|
||||
{{ listItem.addon.installedVersion }}
|
||||
<div class="addon-version row align-items-center" [ngClass]="{ ignored: listItem.isIgnored }">
|
||||
<span class="mr-1">{{ listItem.addon.installedVersion }}</span>
|
||||
<mat-icon *ngIf="listItem.isLoadOnDemand" [inline]="true" [matTooltip]="'Required dependency missing'"
|
||||
[style.color]="'#ff9800'">
|
||||
error_outline
|
||||
</mat-icon>
|
||||
<mat-icon *ngIf="listItem.isAutoUpdate" [inline]="true"
|
||||
[matTooltip]="'PAGES.MY_ADDONS.TABLE.AUTO_UPDATE_ICON_TOOLTIP' | translate">
|
||||
update
|
||||
</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,6 +18,7 @@ export interface Addon {
|
||||
author?: string;
|
||||
installedFolders?: string;
|
||||
isIgnored: boolean;
|
||||
isLoadOnDemand: boolean;
|
||||
autoUpdateEnabled: boolean;
|
||||
clientType: WowClientType;
|
||||
channelType: AddonChannelType;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Addon } from "../../entities/addon";
|
||||
import { Toc } from "./toc";
|
||||
import { Stats } from "fs";
|
||||
|
||||
export interface AddonFolder {
|
||||
name: string;
|
||||
@@ -10,4 +11,5 @@ export interface AddonFolder {
|
||||
toc: Toc;
|
||||
tocMetaData: string[];
|
||||
matchingAddon?: Addon;
|
||||
fileStats?: Stats;
|
||||
}
|
||||
|
||||
@@ -12,4 +12,6 @@ export interface Toc {
|
||||
wowInterfaceId?: string;
|
||||
tukUiProjectId?: string;
|
||||
tukUiProjectFolders?: string;
|
||||
loadOnDemand?: string;
|
||||
dependencyList: string[];
|
||||
}
|
||||
|
||||
@@ -1,97 +1,53 @@
|
||||
<div
|
||||
class="tab-container d-flex flex-col"
|
||||
[ngClass]="{
|
||||
<div class="tab-container d-flex flex-col" [ngClass]="{
|
||||
mac: electronService.isMac,
|
||||
windows: electronService.isWin,
|
||||
linux: electronService.isLinux
|
||||
}"
|
||||
>
|
||||
}">
|
||||
<div class="control-container">
|
||||
<div class="select-container">
|
||||
<mat-form-field>
|
||||
<mat-label>{{
|
||||
"PAGES.MY_ADDONS.CLIENT_TYPE_SELECT_LABEL" | translate
|
||||
}}</mat-label>
|
||||
<mat-select
|
||||
class="select pointer"
|
||||
[(value)]="selectedClient"
|
||||
(selectionChange)="onClientChange()"
|
||||
[disabled]="enableControls === false"
|
||||
>
|
||||
<mat-option
|
||||
[value]="clientType"
|
||||
*ngFor="
|
||||
<mat-select class="select pointer" [(value)]="selectedClient" (selectionChange)="onClientChange()"
|
||||
[disabled]="enableControls === false">
|
||||
<mat-option [value]="clientType" *ngFor="
|
||||
let clientType of warcraftService.installedClientTypes$ | async
|
||||
"
|
||||
>
|
||||
">
|
||||
{{ warcraftService.getClientDisplayName(clientType) }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="right-container">
|
||||
<div
|
||||
class="filter-container"
|
||||
*ngIf="selectedClient !== wowClientType.None"
|
||||
>
|
||||
<div class="filter-container" *ngIf="selectedClient !== wowClientType.None">
|
||||
<mat-form-field>
|
||||
<mat-label>{{
|
||||
"PAGES.MY_ADDONS.FILTER_LABEL" | translate
|
||||
}}</mat-label>
|
||||
<input matInput (keyup)="filterAddons()" [(ngModel)]="filter" />
|
||||
<button
|
||||
mat-button
|
||||
color="accent"
|
||||
*ngIf="filter"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="onClearFilter()"
|
||||
>
|
||||
<button mat-button color="accent" *ngIf="filter" matSuffix mat-icon-button aria-label="Clear"
|
||||
(click)="onClearFilter()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
[matTooltip]="'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false"
|
||||
(click)="onUpdateAll()"
|
||||
(contextmenu)="onUpdateAllContext($event)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="UpdateAll"
|
||||
>
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onUpdateAll()" (contextmenu)="onUpdateAllContext($event)"
|
||||
appUserActionTracker category="MyAddons" action="UpdateAll">
|
||||
{{ "PAGES.MY_ADDONS.UPDATE_ALL_BUTTON" | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
[matTooltip]="
|
||||
<button mat-flat-button color="primary" [matTooltip]="
|
||||
'PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON_TOOLTIP' | translate
|
||||
"
|
||||
[disabled]="enableControls === false"
|
||||
(click)="onRefresh()"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="CheckUpdates"
|
||||
>
|
||||
" [disabled]="enableControls === false" (click)="onRefresh()" appUserActionTracker category="MyAddons"
|
||||
action="CheckUpdates">
|
||||
{{ "PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON" | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
[matTooltip]="
|
||||
<button mat-flat-button color="primary" [matTooltip]="
|
||||
'PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON_TOOLTIP' | translate
|
||||
"
|
||||
[disabled]="enableControls === false"
|
||||
(click)="onReScan()"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="ReScanFolders"
|
||||
>
|
||||
" [disabled]="enableControls === false" (click)="onReScan()" appUserActionTracker category="MyAddons"
|
||||
action="ReScanFolders">
|
||||
{{ "PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON" | translate }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -102,27 +58,18 @@
|
||||
<app-progress-spinner [message]="spinnerMessage"> </app-progress-spinner>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="isBusy === false && sortedListItems.length === 0"
|
||||
class="no-addons-container flex-grow-1"
|
||||
>
|
||||
<div *ngIf="isBusy === false && sortedListItems.length === 0" class="no-addons-container flex-grow-1">
|
||||
<h1>No Addons found</h1>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="table-container flex-grow-1"
|
||||
[hidden]="isBusy === true || sortedListItems.length === 0"
|
||||
>
|
||||
<div class="table-container flex-grow-1" [hidden]="isBusy === true || sortedListItems.length === 0">
|
||||
<table mat-table matSort [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="addon.name">
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{ "PAGES.MY_ADDONS.TABLE.ADDON_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element" class="cell-padding">
|
||||
<app-my-addons-addon-cell
|
||||
[addon]="element"
|
||||
(onViewDetails)="openDetailDialog($event)"
|
||||
>
|
||||
<app-my-addons-addon-cell [addon]="element" (onViewDetails)="openDetailDialog($event)">
|
||||
</app-my-addons-addon-cell>
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -131,37 +78,19 @@
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{ "PAGES.MY_ADDONS.TABLE.STATUS_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td
|
||||
mat-cell
|
||||
*matCellDef="let element"
|
||||
class="status-column cell-padding"
|
||||
>
|
||||
<app-my-addon-status-column
|
||||
[listItem]="element"
|
||||
></app-my-addon-status-column>
|
||||
<td mat-cell *matCellDef="let element" class="status-column cell-padding">
|
||||
<app-my-addon-status-column [listItem]="element"></app-my-addon-status-column>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="installedAt">
|
||||
<th
|
||||
class="installed-at-cell"
|
||||
mat-header-cell
|
||||
mat-sort-header
|
||||
*matHeaderCellDef
|
||||
>
|
||||
<th class="installed-at-cell" mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{ "PAGES.MY_ADDONS.TABLE.UPDATED_AT_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td
|
||||
mat-cell
|
||||
*matCellDef="let element"
|
||||
class="cell-padding"
|
||||
[matTooltip]="
|
||||
<td mat-cell *matCellDef="let element" class="cell-padding" [matTooltip]="
|
||||
'COMMON.DATES.DATETIME_SHORT'
|
||||
| translate: { d: element.installedAt }
|
||||
"
|
||||
matTooltipPosition="above"
|
||||
matTooltipShowDelay="500"
|
||||
>
|
||||
" matTooltipPosition="above" matTooltipShowDelay="500">
|
||||
{{ element.installedAt | relativeDuration }}
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -176,36 +105,19 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="addon.releasedAt">
|
||||
<th
|
||||
class="released-at-cell"
|
||||
mat-header-cell
|
||||
mat-sort-header
|
||||
*matHeaderCellDef
|
||||
>
|
||||
<th class="released-at-cell" mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{ "PAGES.MY_ADDONS.TABLE.RELEASED_AT_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td
|
||||
mat-cell
|
||||
*matCellDef="let element"
|
||||
class="cell-padding"
|
||||
[matTooltip]="
|
||||
<td mat-cell *matCellDef="let element" class="cell-padding" [matTooltip]="
|
||||
'COMMON.DATES.DATETIME_SHORT'
|
||||
| translate: { d: element.addon.releasedAt }
|
||||
"
|
||||
matTooltipPosition="above"
|
||||
matTooltipShowDelay="500"
|
||||
>
|
||||
" matTooltipPosition="above" matTooltipShowDelay="500">
|
||||
{{ element.addon.releasedAt | relativeDuration }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="addon.gameVersion">
|
||||
<th
|
||||
class="game-version-cell"
|
||||
mat-header-cell
|
||||
mat-sort-header
|
||||
*matHeaderCellDef
|
||||
>
|
||||
<th class="game-version-cell" mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{ "PAGES.MY_ADDONS.TABLE.GAME_VERSION_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td class="game-version-cell" mat-cell *matCellDef="let element">
|
||||
@@ -214,30 +126,19 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="addon.providerName">
|
||||
<th
|
||||
mat-header-cell
|
||||
mat-sort-header
|
||||
*matHeaderCellDef
|
||||
class="provider-column"
|
||||
>
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef class="provider-column">
|
||||
{{ "PAGES.MY_ADDONS.TABLE.PROVIDER_COLUMN_HEADER" | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element" class="cell-padding">
|
||||
<div *ngIf="element.addon.providerName !== 'WowUp'">
|
||||
{{ element.addon.providerName }}
|
||||
</div>
|
||||
<div
|
||||
*ngIf="element.addon.providerName === 'WowUp'"
|
||||
class="addon-provider"
|
||||
>
|
||||
<div *ngIf="element.addon.providerName === 'WowUp'" class="addon-provider">
|
||||
<div class="addon-provider-name">
|
||||
{{ element.addon.providerSource }}
|
||||
</div>
|
||||
<img
|
||||
class="provider-logo"
|
||||
[matTooltip]="'Sourced from ' + element.addon.providerName"
|
||||
src="assets/icons/favicon.256x256.png"
|
||||
/>
|
||||
<img class="provider-logo" [matTooltip]="'Sourced from ' + element.addon.providerName"
|
||||
src="assets/icons/favicon.256x256.png" />
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -255,42 +156,24 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr
|
||||
mat-header-row
|
||||
*matHeaderRowDef="displayedColumns; sticky: true"
|
||||
(contextmenu)="onHeaderContext($event); $event.preventDefault()"
|
||||
></tr>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"
|
||||
(contextmenu)="onHeaderContext($event); $event.preventDefault()"></tr>
|
||||
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let i = index; columns: displayedColumns"
|
||||
tabindex="0"
|
||||
[ngClass]="{ 'selected-row': row.selected }"
|
||||
(click)="onRowClicked($event, row, i)"
|
||||
(dblclick)="openDetailDialog(row)"
|
||||
(contextmenu)="onCellContext($event, row)"
|
||||
(keydown.control.a)="selectAllRows($event)"
|
||||
(keydown.meta.a)="selectAllRows($event)"
|
||||
></tr>
|
||||
<tr mat-row *matRowDef="let row; let i = index; columns: displayedColumns" tabindex="0"
|
||||
[ngClass]="{ 'selected-row': row.selected }" (click)="onRowClicked($event, row, i)"
|
||||
(dblclick)="openDetailDialog(row)" (contextmenu)="onCellContext($event, row)"
|
||||
(keydown.control.a)="selectAllRows($event)" (keydown.meta.a)="selectAllRows($event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="visibility: hidden; position: fixed"
|
||||
#addonContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x"
|
||||
[style.top]="contextMenuPosition.y"
|
||||
[matMenuTriggerFor]="contextMenu"
|
||||
></div>
|
||||
<div style="visibility: hidden; position: fixed" #addonContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="contextMenu"></div>
|
||||
<mat-menu #contextMenu="matMenu" class="addon-context-menu">
|
||||
<ng-template matMenuContent let-listItem="listItem">
|
||||
<div class="addon-context-menu-header">
|
||||
<div
|
||||
*ngIf="listItem.hasThumbnail === true"
|
||||
class="thumbnail"
|
||||
[style.backgroundImage]="'url(' + listItem.addon.thumbnailUrl + ')'"
|
||||
></div>
|
||||
<div *ngIf="listItem.hasThumbnail === true" class="thumbnail"
|
||||
[style.backgroundImage]="'url(' + listItem.addon.thumbnailUrl + ')'"></div>
|
||||
<div *ngIf="listItem.hasThumbnail === false" class="thumbnail">
|
||||
<div class="thumbnail-letter">
|
||||
{{ listItem.thumbnailLetter }}
|
||||
@@ -302,109 +185,59 @@
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-checkbox
|
||||
class="mat-menu-item"
|
||||
[checked]="listItem.addon.isIgnored"
|
||||
(change)="onClickIgnoreAddon($event, listItem)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="IgnoreAddon"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<mat-checkbox *ngIf="addonService.isValidProviderName(listItem.addon.providerName)" class="mat-menu-item"
|
||||
[checked]="listItem.addon.isIgnored" (change)="onClickIgnoreAddon($event, listItem)" appUserActionTracker
|
||||
category="MyAddons" action="IgnoreAddon" [label]="listItem.addon.name">
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.IGNORE_ADDON_BUTTON" | translate }}
|
||||
</mat-checkbox>
|
||||
<mat-checkbox
|
||||
*ngIf="listItem.addon.isIgnored === false"
|
||||
class="mat-menu-item"
|
||||
[checked]="listItem.addon.autoUpdateEnabled"
|
||||
(change)="onClickAutoUpdateAddon($event, listItem)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="AutoUpdateAddon"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<mat-checkbox *ngIf="listItem.addon.isIgnored === false" class="mat-menu-item"
|
||||
[checked]="listItem.addon.autoUpdateEnabled" (change)="onClickAutoUpdateAddon($event, listItem)"
|
||||
appUserActionTracker category="MyAddons" action="AutoUpdateAddon" [label]="listItem.addon.name">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.AUTO_UPDATE_ADDON_BUTTON"
|
||||
| translate
|
||||
}}
|
||||
</mat-checkbox>
|
||||
<button mat-menu-item [matMenuTriggerFor]="addonChannels">
|
||||
<button *ngIf="addonService.isValidProviderName(listItem.addon.providerName)" mat-menu-item
|
||||
[matMenuTriggerFor]="addonChannels">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.CHANNEL_SUBMENT_TITLE" | translate
|
||||
}}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onShowfolder(listItem.addon)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="ShowAddonFolder"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<button mat-menu-item (click)="onShowfolder(listItem.addon)" appUserActionTracker category="MyAddons"
|
||||
action="ShowAddonFolder" [label]="listItem.addon.name">
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.SHOW_FOLDER" | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onReInstallAddon(listItem)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="ReInstallAddon"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<button *ngIf="addonService.isValidProviderName(listItem.addon.providerName)" mat-menu-item
|
||||
(click)="onReInstallAddon(listItem)" appUserActionTracker category="MyAddons" action="ReInstallAddon"
|
||||
[label]="listItem.addon.name">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.REINSTALL_ADDON_BUTTON" | translate
|
||||
}}
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onRemoveAddon(listItem.addon)"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="RemoveAddon"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<button mat-menu-item (click)="onRemoveAddon(listItem.addon)" appUserActionTracker category="MyAddons"
|
||||
action="RemoveAddon" [label]="listItem.addon.name">
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.REMOVE_ADDON_BUTTON" | translate }}
|
||||
</button>
|
||||
<mat-menu #addonChannels="matMenu" class="addon-context-menu">
|
||||
<mat-radio-group
|
||||
class="vertical-radio-group"
|
||||
[ngModel]="listItem.addon.channelType"
|
||||
(change)="onSelectedAddonChannelChange($event, listItem)"
|
||||
>
|
||||
<mat-radio-button
|
||||
class="mat-menu-item"
|
||||
[value]="0"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="SetStableAddonChannel"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<mat-radio-group class="vertical-radio-group" [ngModel]="listItem.addon.channelType"
|
||||
(change)="onSelectedAddonChannelChange($event, listItem)">
|
||||
<mat-radio-button class="mat-menu-item" [value]="0" appUserActionTracker category="MyAddons"
|
||||
action="SetStableAddonChannel" [label]="listItem.addon.name">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.STABLE_ADDON_CHANNEL"
|
||||
| translate
|
||||
}}
|
||||
</mat-radio-button>
|
||||
<mat-radio-button
|
||||
class="mat-menu-item"
|
||||
[value]="1"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="SetBetaAddonChannel"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<mat-radio-button class="mat-menu-item" [value]="1" appUserActionTracker category="MyAddons"
|
||||
action="SetBetaAddonChannel" [label]="listItem.addon.name">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.BETA_ADDON_CHANNEL" | translate
|
||||
}}
|
||||
</mat-radio-button>
|
||||
<mat-radio-button
|
||||
class="mat-menu-item"
|
||||
[value]="2"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="SetAlphaAddonChannel"
|
||||
[label]="listItem.addon.name"
|
||||
>
|
||||
<mat-radio-button class="mat-menu-item" [value]="2" appUserActionTracker category="MyAddons"
|
||||
action="SetAlphaAddonChannel" [label]="listItem.addon.name">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.ALPHA_ADDON_CHANNEL" | translate
|
||||
}}
|
||||
@@ -414,31 +247,20 @@
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<div
|
||||
style="visibility: hidden; position: fixed"
|
||||
#addonMultiContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x"
|
||||
[style.top]="contextMenuPosition.y"
|
||||
[matMenuTriggerFor]="multiContextMenu"
|
||||
></div>
|
||||
<div style="visibility: hidden; position: fixed" #addonMultiContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="multiContextMenu"></div>
|
||||
<mat-menu #multiContextMenu="matMenu" class="addon-context-menu">
|
||||
<ng-template matMenuContent let-listItems="listItems">
|
||||
<div class="addon-context-menu-header">
|
||||
{{ listItems.length + " addons selected" }}
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-checkbox
|
||||
class="mat-menu-item"
|
||||
[checked]="isSelectedItemsProp(listItems, 'addon.isIgnored')"
|
||||
(change)="onClickIgnoreAddons($event, listItems)"
|
||||
>
|
||||
<mat-checkbox class="mat-menu-item" [checked]="isSelectedItemsProp(listItems, 'addon.isIgnored')"
|
||||
(change)="onClickIgnoreAddons($event, listItems)">
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.IGNORE_ADDON_BUTTON" | translate }}
|
||||
</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="mat-menu-item"
|
||||
[checked]="isSelectedItemsProp(listItems, 'addon.autoUpdateEnabled')"
|
||||
(change)="onClickAutoUpdateAddons($event, listItems)"
|
||||
>
|
||||
<mat-checkbox class="mat-menu-item" [checked]="isSelectedItemsProp(listItems, 'addon.autoUpdateEnabled')"
|
||||
(change)="onClickAutoUpdateAddons($event, listItems)">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.AUTO_UPDATE_ADDON_BUTTON"
|
||||
| translate
|
||||
@@ -459,10 +281,7 @@
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.REMOVE_ADDON_BUTTON" | translate }}
|
||||
</button>
|
||||
<mat-menu #addonChannels="matMenu" class="addon-context-menu">
|
||||
<mat-radio-group
|
||||
class="vertical-radio-group"
|
||||
(change)="onSelectedAddonsChannelChange($event, listItems)"
|
||||
>
|
||||
<mat-radio-group class="vertical-radio-group" (change)="onSelectedAddonsChannelChange($event, listItems)">
|
||||
<mat-radio-button class="mat-menu-item" [value]="0">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.STABLE_ADDON_CHANNEL"
|
||||
@@ -484,13 +303,9 @@
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<div
|
||||
style="visibility: hidden; position: fixed"
|
||||
#columnContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x"
|
||||
[style.top]="contextMenuPosition.y"
|
||||
[matMenuTriggerFor]="columnContextMenu"
|
||||
></div>
|
||||
<div style="visibility: hidden; position: fixed" #columnContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="columnContextMenu">
|
||||
</div>
|
||||
<mat-menu #columnContextMenu="matMenu" class="addon-context-menu">
|
||||
<ng-template matMenuContent let-columns="columns">
|
||||
<div class="addon-context-menu-header">
|
||||
@@ -499,49 +314,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-checkbox
|
||||
*ngFor="let column of columns"
|
||||
class="mat-menu-item"
|
||||
[checked]="column.visible"
|
||||
(change)="onColumnVisibleChange($event, column)"
|
||||
>
|
||||
<mat-checkbox *ngFor="let column of columns" class="mat-menu-item" [checked]="column.visible"
|
||||
(change)="onColumnVisibleChange($event, column)">
|
||||
{{ column.display }}
|
||||
</mat-checkbox>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<div
|
||||
style="visibility: hidden; position: fixed"
|
||||
#updateAllContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x"
|
||||
[style.top]="contextMenuPosition.y"
|
||||
[matMenuTriggerFor]="updateAllContextMenu"
|
||||
></div>
|
||||
<div style="visibility: hidden; position: fixed" #updateAllContextMenuTrigger="matMenuTrigger"
|
||||
[style.left]="contextMenuPosition.x" [style.top]="contextMenuPosition.y" [matMenuTriggerFor]="updateAllContextMenu">
|
||||
</div>
|
||||
<mat-menu #updateAllContextMenu="matMenu" class="addon-context-menu">
|
||||
<ng-template matMenuContent let-columns="columns">
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onUpdateAllRetailClassic()"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="UpdateAllClassicRetail"
|
||||
>
|
||||
<button mat-menu-item (click)="onUpdateAllRetailClassic()" appUserActionTracker category="MyAddons"
|
||||
action="UpdateAllClassicRetail">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.UPDATE_ALL_CONTEXT_MENU.UPDATE_RETAIL_CLASSIC_BUTTON"
|
||||
| translate
|
||||
}}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onUpdateAllClients()"
|
||||
appUserActionTracker
|
||||
category="MyAddons"
|
||||
action="UpdateAllClients"
|
||||
>
|
||||
<button mat-menu-item (click)="onUpdateAllClients()" appUserActionTracker category="MyAddons"
|
||||
action="UpdateAllClients">
|
||||
{{
|
||||
"PAGES.MY_ADDONS.UPDATE_ALL_CONTEXT_MENU.UPDATE_ALL_CLIENTS_BUTTON"
|
||||
| translate
|
||||
}}
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
</mat-menu>
|
||||
@@ -516,6 +516,11 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
listItems: AddonViewModel[]
|
||||
) {
|
||||
listItems.forEach((listItem) => {
|
||||
// if provider is not valid (Unknown) then ignore this
|
||||
if (!this.addonService.isValidProviderName(listItem.addon.providerName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
listItem.addon.isIgnored = evt.checked;
|
||||
if (evt.checked) {
|
||||
listItem.addon.autoUpdateEnabled = false;
|
||||
|
||||
@@ -84,7 +84,7 @@ export class AddonService {
|
||||
);
|
||||
var searchResults = await Promise.all(searchTasks);
|
||||
|
||||
await this._analyticsService.trackUserAction(
|
||||
this._analyticsService.trackUserAction(
|
||||
"addons",
|
||||
"search",
|
||||
`${clientType}|${query}`
|
||||
@@ -308,6 +308,11 @@ export class AddonService {
|
||||
return addon.name;
|
||||
};
|
||||
|
||||
public isValidProviderName(providerName: string) {
|
||||
const providerNames = this._addonProviders.map((provider) => provider.name);
|
||||
return _.includes(providerNames, providerName);
|
||||
}
|
||||
|
||||
public async logDebugData() {
|
||||
const curseProvider = this._addonProviders.find(
|
||||
(p) => p.name === "Curse"
|
||||
@@ -616,6 +621,8 @@ export class AddonService {
|
||||
const matchedAddonFolders = addonFolders.filter(
|
||||
(addonFolder) => !!addonFolder.matchingAddon
|
||||
);
|
||||
const matchedAddonFolderNames = matchedAddonFolders.map((mf) => mf.name);
|
||||
|
||||
const matchedGroups = _.groupBy(
|
||||
matchedAddonFolders,
|
||||
(addonFolder) =>
|
||||
@@ -624,7 +631,55 @@ export class AddonService {
|
||||
|
||||
console.log(Object.keys(matchedGroups));
|
||||
|
||||
return Object.values(matchedGroups).map((value) => value[0].matchingAddon);
|
||||
const addonList = Object.values(matchedGroups).map(
|
||||
(value) => value[0].matchingAddon
|
||||
);
|
||||
|
||||
const unmatchedFolders = addonFolders.filter((af) =>
|
||||
this.isAddonFolderUnmatched(matchedAddonFolderNames, af)
|
||||
);
|
||||
console.debug("unmatchedFolders", unmatchedFolders);
|
||||
|
||||
const unmatchedAddons = unmatchedFolders.map((uf) =>
|
||||
this.createUnmatchedAddon(uf, clientType)
|
||||
);
|
||||
|
||||
console.debug("unmatchedAddons", unmatchedAddons);
|
||||
|
||||
addonList.push(...unmatchedAddons);
|
||||
|
||||
return addonList;
|
||||
}
|
||||
|
||||
private reconcileUnmatchedAddons(addon: Addon) {}
|
||||
|
||||
/**
|
||||
* This should verify that a folder that did not have a match, is actually unmatched
|
||||
* This will happen for any sub folders of TukUI or WowInterface addons
|
||||
*/
|
||||
private isAddonFolderUnmatched(
|
||||
matchedFolderNames: string[],
|
||||
addonFolder: AddonFolder
|
||||
) {
|
||||
if (addonFolder.matchingAddon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the folder is load on demand, it 'should' be a sub folder
|
||||
const isLoadOnDemand = addonFolder.toc?.loadOnDemand === "1";
|
||||
if (
|
||||
isLoadOnDemand &&
|
||||
this.allItemsMatch(addonFolder.toc.dependencyList, matchedFolderNames)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Check if all primitives in subset are in the superset (strings, ints) */
|
||||
private allItemsMatch(subset: any[], superset: any[]) {
|
||||
return _.difference(subset, superset).length === 0;
|
||||
}
|
||||
|
||||
public getFeaturedAddons(
|
||||
@@ -757,6 +812,37 @@ export class AddonService {
|
||||
releasedAt: latestFile.releaseDate,
|
||||
summary: searchResult.summary,
|
||||
screenshotUrls: searchResult.screenshotUrls,
|
||||
isLoadOnDemand: false,
|
||||
};
|
||||
}
|
||||
|
||||
private createUnmatchedAddon(
|
||||
addonFolder: AddonFolder,
|
||||
clientType: WowClientType
|
||||
): Addon {
|
||||
return {
|
||||
id: uuidv4(),
|
||||
name: addonFolder.toc?.title || addonFolder.name,
|
||||
thumbnailUrl: "",
|
||||
latestVersion: addonFolder.toc?.version || "",
|
||||
installedVersion: addonFolder.toc?.version || "",
|
||||
clientType: clientType,
|
||||
externalId: "",
|
||||
folderName: addonFolder.name,
|
||||
gameVersion: addonFolder.toc?.interface || "",
|
||||
author: addonFolder.toc?.author || "",
|
||||
downloadUrl: "",
|
||||
externalUrl: "",
|
||||
providerName: "Unknown",
|
||||
channelType: this._wowUpService.getDefaultAddonChannel(clientType),
|
||||
isIgnored: true,
|
||||
autoUpdateEnabled: false,
|
||||
releasedAt: new Date(),
|
||||
installedAt: addonFolder.fileStats?.mtime || new Date(),
|
||||
installedFolders: addonFolder.name,
|
||||
summary: "",
|
||||
screenshotUrls: [],
|
||||
isLoadOnDemand: addonFolder.toc?.loadOnDemand === "1",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
PATH_EXISTS_CHANNEL,
|
||||
READ_FILE_CHANNEL,
|
||||
SHOW_DIRECTORY,
|
||||
STAT_FILES_CHANNEL,
|
||||
UNZIP_FILE_CHANNEL,
|
||||
} from "../../../common/constants";
|
||||
import { CopyFileRequest } from "../../../common/models/copy-file-request";
|
||||
@@ -108,6 +109,15 @@ export class FileService {
|
||||
);
|
||||
}
|
||||
|
||||
public async statFiles(
|
||||
filePaths: string[]
|
||||
): Promise<{ [path: string]: fs.Stats }> {
|
||||
return await this._electronService.ipcRenderer.invoke(
|
||||
STAT_FILES_CHANNEL,
|
||||
filePaths
|
||||
);
|
||||
}
|
||||
|
||||
public listEntries(sourcePath: string, filter: string) {
|
||||
const globFilter = globrex(filter);
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ import { Injectable } from "@angular/core";
|
||||
import { Toc } from "../../models/wowup/toc";
|
||||
import { FileService } from "../files/file.service";
|
||||
|
||||
const TOC_DEPENDENCIES = "Dependencies";
|
||||
const TOC_REQUIRED_DEPS = "RequiredDeps";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
@@ -9,7 +12,14 @@ export class TocService {
|
||||
constructor(private _fileService: FileService) {}
|
||||
|
||||
public async parse(tocPath: string): Promise<Toc> {
|
||||
const tocText = await this._fileService.readFile(tocPath);
|
||||
let tocText = await this._fileService.readFile(tocPath);
|
||||
tocText = tocText.trim();
|
||||
|
||||
const dependencies =
|
||||
this.getValue(TOC_DEPENDENCIES, tocText) ||
|
||||
this.getValue(TOC_REQUIRED_DEPS, tocText);
|
||||
|
||||
const dependencyList: string[] = this.getDependencyList(tocText);
|
||||
|
||||
return {
|
||||
author: this.getValue("Author", tocText),
|
||||
@@ -22,12 +32,27 @@ export class TocService {
|
||||
category: this.getValue("X-Category", tocText),
|
||||
localizations: this.getValue("X-Localizations", tocText),
|
||||
wowInterfaceId: this.getValue("X-WoWI-ID", tocText),
|
||||
dependencies: this.getValue("Dependencies", tocText),
|
||||
dependencies,
|
||||
dependencyList,
|
||||
tukUiProjectId: this.getValue("X-Tukui-ProjectID", tocText),
|
||||
tukUiProjectFolders: this.getValue("X-Tukui-ProjectFolders", tocText),
|
||||
loadOnDemand: this.getValue("LoadOnDemand", tocText),
|
||||
};
|
||||
}
|
||||
|
||||
private getDependencyList(tocText: string) {
|
||||
const dependencies = this.getValue(TOC_DEPENDENCIES, tocText);
|
||||
const requiredDeps = this.getValue(TOC_REQUIRED_DEPS, tocText);
|
||||
|
||||
const deps = []
|
||||
.concat(...dependencies.split(","), ...requiredDeps.split(","))
|
||||
.filter((dep) => !!dep);
|
||||
|
||||
console.debug("deps", deps);
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
public async parseMetaData(tocPath: string): Promise<string[]> {
|
||||
const tocText = await this._fileService.readFile(tocPath);
|
||||
|
||||
|
||||
@@ -181,10 +181,18 @@ export class WarcraftService {
|
||||
const directories = await this._fileService.listDirectories(
|
||||
addonFolderPath
|
||||
);
|
||||
|
||||
const dirPaths = directories.map((dir) => path.join(addonFolderPath, dir));
|
||||
const dirStats = await this._fileService.statFiles(dirPaths);
|
||||
|
||||
console.debug("directories", directories);
|
||||
console.debug("dirStats", dirStats);
|
||||
|
||||
// const directories = files.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
|
||||
for (let i = 0; i < directories.length; i += 1) {
|
||||
const dir = directories[i];
|
||||
const addonFolder = await this.getAddonFolder(addonFolderPath, dir);
|
||||
addonFolder.fileStats = dirStats[path.join(addonFolderPath, dir)];
|
||||
if (addonFolder) {
|
||||
addonFolders.push(addonFolder);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export const CREATE_DIRECTORY_CHANNEL = "create-directory";
|
||||
export const DELETE_DIRECTORY_CHANNEL = "delete-directory";
|
||||
export const STAT_DIRECTORY_CHANNEL = "stat-directory";
|
||||
export const LIST_DIRECTORIES_CHANNEL = "list-directories";
|
||||
export const STAT_FILES_CHANNEL = "stat_files";
|
||||
export const PATH_EXISTS_CHANNEL = "path-exists";
|
||||
export const LIST_FILES_CHANNEL = "list-files";
|
||||
export const READ_FILE_CHANNEL = "read-file";
|
||||
@@ -27,6 +28,8 @@ export const USE_HARDWARE_ACCELERATION_PREFERENCE_KEY =
|
||||
"use_hardware_acceleration";
|
||||
export const START_WITH_SYSTEM_PREFERENCE_KEY = "start_with_system";
|
||||
export const START_MINIMIZED_PREFERENCE_KEY = "start_minimized";
|
||||
|
||||
// ERRORS
|
||||
export const NO_SEARCH_RESULTS_ERROR = "NO_SEARCH_RESULTS";
|
||||
export const NO_LATEST_SEARCH_RESULT_FILES_ERROR =
|
||||
"NO_LATEST_SEARCH_RESULT_FILES";
|
||||
|
||||
Reference in New Issue
Block a user