diff --git a/locales/en/messages.json b/locales/en/messages.json
index 3ae750aa..6699fdc9 100644
--- a/locales/en/messages.json
+++ b/locales/en/messages.json
@@ -6857,6 +6857,10 @@
"message": "Keywords:",
"description": "Hint text in the presets detailed dialog"
},
+ "presetsSourceRepository": {
+ "message": "Source:",
+ "description": "Text prefixing user defined name of the preset repository containing a preset"
+ },
"presetsVersions": {
"message": "Firmware:",
"description": "Hint text in the presets detailed dialog"
@@ -7005,6 +7009,10 @@
"message": "Make Active",
"description": "Presets tab, sources dialog, button to make selected source active"
},
+ "presetsSourcesDialogMakeSourceDisable": {
+ "message": "Make disabled",
+ "description": "Presets tab, sources dialog, button to make selected source disabled"
+ },
"presetsSourcesDialogDeleteSource": {
"message": "Delete",
"description": "Presets tab, sources dialog, button to delete selected source"
@@ -7013,6 +7021,10 @@
"message": "WARNING! A third party preset source is selected.",
"description": "Warning message that shows up when a third party preset source is selected"
},
+ "presetsFailedToLoadRepositories": {
+ "message": "WARNING! Failed to load following repositories: {{repos}}",
+ "description": "Warning message that shows up when we fail to load some repositories"
+ },
"presetsWarningBackup": {
"message": "Please make sure you backup your current configuration ('$t(presetsBackupSave.message)' button or via CLI if the button is disabled) before picking and applying presets. Otherwise there is no way to return to previous configuration after applying presets.",
"description": "Warning message that shows up at the top of the presets tab"
diff --git a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js
index 0795b4a9..c6570960 100644
--- a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js
+++ b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js
@@ -26,9 +26,10 @@ export default class PresetsDetailedDialog {
});
}
- open(preset, presetsRepo) {
+ open(preset, presetsRepo, showPresetRepoName) {
this._presetsRepo = presetsRepo;
this._preset = preset;
+ this._showPresetRepoName = showPresetRepoName;
this._setLoadingState(true);
this._domDialog[0].showModal();
this._optionsShowedAtLeastOnce = false;
@@ -78,8 +79,8 @@ export default class PresetsDetailedDialog {
}
this._titlePanel.empty();
- const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, false,
- () => this._setLoadingState(false), this._favoritePresets);
+ const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, this._presetsRepo, false,
+ this._showPresetRepoName, () => this._setLoadingState(false), this._favoritePresets);
titlePanel.load();
this._loadOptionsSelect();
this._updateFinalCliText();
@@ -263,7 +264,7 @@ export default class PresetsDetailedDialog {
_pickPreset() {
const cliStrings = this._getFinalCliText();
- const pickedPreset = new PickedPreset(this._preset, cliStrings);
+ const pickedPreset = new PickedPreset(this._preset, cliStrings, this._presetsRepo);
this._pickedPresetList.push(pickedPreset);
this._onPresetPickedCallback?.();
this._isPresetPickedOnClose = true;
diff --git a/src/tabs/presets/FavoritePresets.js b/src/tabs/presets/FavoritePresets.js
index b4ce87a0..4a3f62a7 100644
--- a/src/tabs/presets/FavoritePresets.js
+++ b/src/tabs/presets/FavoritePresets.js
@@ -75,19 +75,19 @@ class FavoritePresetsClass {
this._favoritePresetsData = new FavoritePresetsData();
}
- add(preset) {
- const favoritePreset = this._favoritePresetsData.add(preset.fullPath);
+ add(preset, repo) {
+ const favoritePreset = this._favoritePresetsData.add(repo.getPresetOnlineLink(preset));
preset.lastPickDate = favoritePreset.lastPickDate;
}
- delete(preset) {
- this._favoritePresetsData.delete(preset.fullPath);
+ delete(preset, repo) {
+ this._favoritePresetsData.delete(repo.getPresetOnlineLink(preset));
preset.lastPickDate = undefined;
}
- addLastPickDate(presets) {
+ addLastPickDate(presets, repo) {
for (let preset of presets) {
- let favoritePreset = this._favoritePresetsData.findPreset(preset.fullPath);
+ let favoritePreset = this._favoritePresetsData.findPreset(repo.getPresetOnlineLink(preset));
if (favoritePreset) {
preset.lastPickDate = favoritePreset.lastPickDate;
diff --git a/src/tabs/presets/PickedPreset.js b/src/tabs/presets/PickedPreset.js
index 96b197e0..19adde35 100644
--- a/src/tabs/presets/PickedPreset.js
+++ b/src/tabs/presets/PickedPreset.js
@@ -1,8 +1,9 @@
export default class PickedPreset
{
- constructor(preset, presetCli)
+ constructor(preset, presetCli, presetRepo)
{
this.preset = preset;
this.presetCli = presetCli;
+ this.presetRepo = presetRepo;
}
}
diff --git a/src/tabs/presets/PresetsRepoIndexed/PresetsGithubRepo.js b/src/tabs/presets/PresetsRepoIndexed/PresetsGithubRepo.js
index e3405784..4ad36bc3 100644
--- a/src/tabs/presets/PresetsRepoIndexed/PresetsGithubRepo.js
+++ b/src/tabs/presets/PresetsRepoIndexed/PresetsGithubRepo.js
@@ -1,7 +1,7 @@
import PresetsRepoIndexed from "./PresetsRepoIndexed";
export default class PresetsGithubRepo extends PresetsRepoIndexed {
- constructor(urlRepo, branch) {
+ constructor(urlRepo, branch, official, name) {
let correctUrlRepo = urlRepo.trim();
if (!correctUrlRepo.endsWith("/")) {
@@ -21,6 +21,6 @@ export default class PresetsGithubRepo extends PresetsRepoIndexed {
const urlRaw = `https://raw.githubusercontent.com${correctUrlRepo.slice("https://github.com".length)}${correctBranch}/`;
const urlViewOnline = `${correctUrlRepo}blob/${correctBranch}/`;
- super(urlRaw, urlViewOnline);
+ super(urlRaw, urlViewOnline, official, name);
}
}
diff --git a/src/tabs/presets/PresetsRepoIndexed/PresetsRepoIndexed.js b/src/tabs/presets/PresetsRepoIndexed/PresetsRepoIndexed.js
index 4455d0d8..1b0f0207 100644
--- a/src/tabs/presets/PresetsRepoIndexed/PresetsRepoIndexed.js
+++ b/src/tabs/presets/PresetsRepoIndexed/PresetsRepoIndexed.js
@@ -1,16 +1,26 @@
import PresetParser from "./PresetParser";
export default class PresetsRepoIndexed {
- constructor(urlRaw, urlViewOnline) {
+ constructor(urlRaw, urlViewOnline, official, name) {
this._urlRaw = urlRaw;
this._urlViewOnline = urlViewOnline;
this._index = null;
+ this._name = name;
+ this._official = official;
}
get index() {
return this._index;
}
+ get official() {
+ return this._official;
+ }
+
+ get name() {
+ return this._name;
+ }
+
loadIndex() {
return fetch(`${this._urlRaw}index.json`, {cache: "no-cache"})
.then(res => res.json())
diff --git a/src/tabs/presets/PresetsRepoIndexed/PresetsWebsiteRepo.js b/src/tabs/presets/PresetsRepoIndexed/PresetsWebsiteRepo.js
index 28388cd6..c9d8a089 100644
--- a/src/tabs/presets/PresetsRepoIndexed/PresetsWebsiteRepo.js
+++ b/src/tabs/presets/PresetsRepoIndexed/PresetsWebsiteRepo.js
@@ -1,7 +1,7 @@
import PresetsRepoIndexed from "./PresetsRepoIndexed";
export default class PresetsWebsiteRepo extends PresetsRepoIndexed {
- constructor(url) {
+ constructor(url, official, name) {
let correctUrl = url.trim();
if (!correctUrl.endsWith("/")) {
@@ -11,6 +11,6 @@ export default class PresetsWebsiteRepo extends PresetsRepoIndexed {
const urlRaw = correctUrl;
const urlViewOnline = correctUrl;
- super(urlRaw, urlViewOnline);
+ super(urlRaw, urlViewOnline, official, name);
}
}
diff --git a/src/tabs/presets/SourcesDialog/SourcePanel.html b/src/tabs/presets/SourcesDialog/SourcePanel.html
index 72b275c8..4193097a 100644
--- a/src/tabs/presets/SourcesDialog/SourcePanel.html
+++ b/src/tabs/presets/SourcesDialog/SourcePanel.html
@@ -21,6 +21,7 @@
+
diff --git a/src/tabs/presets/SourcesDialog/SourcePanel.js b/src/tabs/presets/SourcesDialog/SourcePanel.js
index a930b8a5..273a62d9 100644
--- a/src/tabs/presets/SourcesDialog/SourcePanel.js
+++ b/src/tabs/presets/SourcesDialog/SourcePanel.js
@@ -47,6 +47,12 @@ export default class SourcePanel {
this._onActivateCallback = onActivateCallback;
}
+ setOnDeactivateCallback(onDeactivateCallback) {
+ // callback with this (SourcePanel) argument
+ // so that consumer knew which panel was clicked on
+ this._onDeactivateCallback = onDeactivateCallback;
+ }
+
setOnSaveCallback(onSaveCallback) {
// callback with this (SourcePanel) argument
// so that consumer knew which panel was clicked on
@@ -65,6 +71,7 @@ export default class SourcePanel {
this._active = isActive;
this._domDivSelectedIndicator.toggle(this._active);
this._domButtonActivate.toggle(!isActive);
+ this._domButtonDeactivate.toggle(isActive);
}
_setUiOfficial() {
@@ -120,6 +127,7 @@ export default class SourcePanel {
this._domButtonReset.on("click", () => this._onResetButtonClick());
this._domButtonDelete.on("click", () => this._onDeleteButtonClick());
this._domButtonActivate.on("click", () => this._onActivateButtonClick());
+ this._domButtonDeactivate.on("click", () => this._onDeactivateButtonClick());
this._domEditName.on("input", () => this._onInputChange());
this._domEditUrl.on("input", () => this._onInputChange());
@@ -168,6 +176,12 @@ export default class SourcePanel {
this._onActivateCallback?.(this);
}
+ _onDeactivateButtonClick() {
+ this._onSaveButtonClick();
+ this.setActive(false);
+ this._onDeactivateCallback?.(this);
+ }
+
_setIsSaved(isSaved) {
if (isSaved) {
this._domButtonSave.addClass(GUI.buttonDisabledClass);
@@ -190,6 +204,7 @@ export default class SourcePanel {
this._domButtonSave = this._domWrapperDiv.find(".presets_source_panel_save");
this._domButtonReset = this._domWrapperDiv.find(".presets_source_panel_reset");
this._domButtonActivate = this._domWrapperDiv.find(".presets_source_panel_activate");
+ this._domButtonDeactivate = this._domWrapperDiv.find(".presets_source_panel_deactivate");
this._domButtonDelete = this._domWrapperDiv.find(".presets_source_panel_delete");
this._domDivGithubBranch = this._domWrapperDiv.find(".presets_source_panel_editing_github_branch");
this._domDivNoEditingName = this._domWrapperDiv.find(".presets_source_panel_no_editing_name");
diff --git a/src/tabs/presets/SourcesDialog/SourcesDialog.js b/src/tabs/presets/SourcesDialog/SourcesDialog.js
index bf9679d5..671b4846 100644
--- a/src/tabs/presets/SourcesDialog/SourcesDialog.js
+++ b/src/tabs/presets/SourcesDialog/SourcesDialog.js
@@ -9,7 +9,7 @@ export default class PresetsSourcesDialog {
this._sourceSelectedPromiseResolve = null;
this._sourcesPanels = [];
this._sources = [];
- this._activeSourceIndex = 0;
+ this._activeSourceIndexes = [0];
}
load() {
@@ -28,20 +28,20 @@ export default class PresetsSourcesDialog {
return new Promise(resolve => this._sourceSelectedPromiseResolve = resolve);
}
- getActivePresetSource() {
- return this._sources[this._activeSourceIndex];
+ getActivePresetSources() {
+ return this._activeSourceIndexes.map(index => this._sources[index]);
}
- get isOfficialActive() {
- return this._activeSourceIndex === 0;
+ get isThirdPartyActive() {
+ return this.getActivePresetSources().filter(source => !source.official).length > 0;
}
_initializeSources() {
this._sources = this._readSourcesFromStorage();
- this._activeSourceIndex = this._readActiveSourceIndexFromStorage(this._sources.length);
+ this._activeSourceIndexes = this._readActiveSourceIndexFromStorage(this._sources.length);
for (let i = 0; i < this._sources.length; i++) {
- const isActive = this._activeSourceIndex === i;
+ const isActive = this._activeSourceIndexes.includes(i);
this._addNewSourcePanel(this._sources[i], isActive, false);
}
}
@@ -67,15 +67,8 @@ export default class PresetsSourcesDialog {
}
_readActiveSourceIndexFromStorage(sourcesCount) {
- const obj = getConfig('PresetSourcesActiveIndex');
- const index = Number(obj.PresetSourcesActiveIndex);
- let result = 0;
-
- if (index && Number.isInteger(index) && index < sourcesCount) {
- result = index;
- }
-
- return result;
+ const obj = getConfig('PresetSourcesActiveIndexes');
+ return obj.PresetSourcesActiveIndexes || [0];
}
_createOfficialSource() {
@@ -117,6 +110,7 @@ export default class PresetsSourcesDialog {
sourcePanel.setOnSelectedCallback(selectedPanel => this._onSourcePanelSelected(selectedPanel));
sourcePanel.setOnDeleteCallback(selectedPanel => this._onSourcePanelDeleted(selectedPanel));
sourcePanel.setOnActivateCallback(selectedPanel => this._onSourcePanelActivated(selectedPanel));
+ sourcePanel.setOnDeactivateCallback(selectedPanel => this._onSourcePanelDeactivated(selectedPanel));
sourcePanel.setOnSaveCallback(() => this._onSourcePanelSaved());
sourcePanel.setActive(isActive);
if (isSelected) {
@@ -140,18 +134,18 @@ export default class PresetsSourcesDialog {
_readPanels() {
this._sources = [];
- this._activeSourceIndex = 0;
- for(let i = 0; i < this._sourcesPanels.length; i++) {
+ this._activeSourceIndexes = [];
+ for (let i = 0; i < this._sourcesPanels.length; i++) {
this._sources.push(this._sourcesPanels[i].presetSource);
if (this._sourcesPanels[i].active) {
- this._activeSourceIndex = i;
+ this._activeSourceIndexes.push(i);
}
}
}
_saveSources() {
setConfig({'PresetSources': this._sources});
- setConfig({'PresetSourcesActiveIndex': this._activeSourceIndex});
+ setConfig({'PresetSourcesActiveIndexes': this._activeSourceIndexes});
}
_updateSourcesFromPanels() {
@@ -183,15 +177,22 @@ export default class PresetsSourcesDialog {
_onSourcePanelActivated(selectedPanel) {
for (const panel of this._sourcesPanels) {
- if (panel !== selectedPanel) {
- panel.setActive(false);
- } else {
+ if (panel === selectedPanel) {
panel.setActive(true);
}
}
this._updateSourcesFromPanels();
}
+ _onSourcePanelDeactivated(selectedPanel) {
+ for (const panel of this._sourcesPanels) {
+ if (panel === selectedPanel) {
+ panel.setActive(false);
+ }
+ }
+ this._updateSourcesFromPanels();
+ }
+
_readDom() {
this._domButtonAddNew = $("#presets_sources_dialog_add_new");
this._domButtonClose = $("#presets_sources_dialog_close");
diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.css b/src/tabs/presets/TitlePanel/PresetTitlePanel.css
index e9481d12..65a320e8 100644
--- a/src/tabs/presets/TitlePanel/PresetTitlePanel.css
+++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.css
@@ -20,7 +20,7 @@
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
- width: calc(100% - 30px);
+ width: calc(100% - 60px);
}
.preset_title_panel_star {
@@ -37,6 +37,20 @@
top: -5px;
}
+.preset_title_panel_betaflight_official {
+ background-image: url(../../../images/icons/cf_icon_welcome_orange.svg);
+ width: 25px;
+ height: 25px;
+ background-size: cover;
+ border-radius: 5px;
+ padding: 5px;
+ background-origin: content-box;
+ background-repeat: no-repeat;
+ position: absolute;
+ right: 26px;
+ top: -5px;
+}
+
.preset_title_panel_category {
color: var(--mutedText);
font-weight: bold;
@@ -75,6 +89,12 @@
text-overflow: ellipsis;
}
+.preset_title_panel_repository_text {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
.presets_title_panel_table {
table-layout: fixed;
width: 100%;
diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.js b/src/tabs/presets/TitlePanel/PresetTitlePanel.js
index 373fdcb7..a74efd72 100644
--- a/src/tabs/presets/TitlePanel/PresetTitlePanel.js
+++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.js
@@ -2,13 +2,15 @@ import { i18n } from "../../../js/localization";
export default class PresetTitlePanel
{
- constructor(parentDiv, preset, clickable, onLoadedCallback, favoritePresets)
+ constructor(parentDiv, preset, presetRepo, clickable, showPresetRepoName, onLoadedCallback, favoritePresets)
{
PresetTitlePanel.s_panelCounter ++;
this._parentDiv = parentDiv;
this._onLoadedCallback = onLoadedCallback;
this._domId = `preset_title_panel_${PresetTitlePanel.s_panelCounter}`;
this._preset = preset;
+ this._presetRepo = presetRepo;
+ this._showPresetRepoName = showPresetRepoName;
this._clickable = clickable;
this._favoritePresets = favoritePresets;
@@ -68,7 +70,7 @@ export default class PresetTitlePanel
}
_showPresetsDetailedDialog(presetsDetailedDialog, presetsRepo) {
- presetsDetailedDialog.open(this._preset, presetsRepo).then(isPresetPicked => {
+ presetsDetailedDialog.open(this._preset, presetsRepo, this._showPresetRepoName).then(isPresetPicked => {
if (isPresetPicked) {
const color = this._domWrapperDiv.css( "background-color" );
this._domWrapperDiv.css('background-color', 'green');
@@ -103,11 +105,16 @@ export default class PresetTitlePanel
this._domTitle.prop("title", this._preset.title);
this._domAuthor.text(this._preset.author);
this._domVersions.text(this._preset.firmware_version?.join("; "));
+ this._domSourceRepository.text(this._presetRepo.name);
+ this._domSourceRepositoryRow.toggle(this._showPresetRepoName);
+
this._domKeywords.text(this._preset.keywords?.join("; "));
this._domKeywords.prop("title", this._preset.keywords?.join("; "));
this._domStatusOfficial.toggle(this._preset.status === "OFFICIAL");
this._domStatusCommunity.toggle(this._preset.status === "COMMUNITY");
this._domStatusExperimental.toggle(this._preset.status === "EXPERIMENTAL");
+ this._domOfficialSourceIcon.toggle(this._presetRepo.official);
+
this.setPicked(this._preset.isPicked);
this._setupStar();
@@ -128,10 +135,13 @@ export default class PresetTitlePanel
this._domCategory = this._domWrapperDiv.find('.preset_title_panel_category');
this._domAuthor = this._domWrapperDiv.find('.preset_title_panel_author_text');
this._domKeywords = this._domWrapperDiv.find('.preset_title_panel_keywords_text');
+ this._domSourceRepository = this._domWrapperDiv.find('.preset_title_panel_repository_text');
+ this._domSourceRepositoryRow = this._domWrapperDiv.find('.preset_title_panel_repository_row');
this._domVersions = this._domWrapperDiv.find('.preset_title_panel_versions_text');
this._domStatusOfficial = this._domWrapperDiv.find('.preset_title_panel_status_official');
this._domStatusCommunity = this._domWrapperDiv.find('.preset_title_panel_status_community');
this._domStatusExperimental = this._domWrapperDiv.find('.preset_title_panel_status_experimental');
+ this._domOfficialSourceIcon = this._domWrapperDiv.find('.preset_title_panel_betaflight_official');
}
_setupStar() {
@@ -145,9 +155,9 @@ export default class PresetTitlePanel
_processStarClick() {
if (this._preset.lastPickDate) {
- this._favoritePresets.delete(this._preset);
+ this._favoritePresets.delete(this._preset, this._presetRepo);
} else {
- this._favoritePresets.add(this._preset);
+ this._favoritePresets.add(this._preset, this._presetRepo);
}
this._favoritePresets.saveToStorage();
diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html
index 7dd031ba..132959c3 100644
--- a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html
+++ b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html
@@ -1,4 +1,5 @@
+
@@ -40,6 +41,14 @@
+
+
+
+ |
+
+
+ |
+
diff --git a/src/tabs/presets/presets.html b/src/tabs/presets/presets.html
index 97c2ff9b..5b5873cf 100644
--- a/src/tabs/presets/presets.html
+++ b/src/tabs/presets/presets.html
@@ -17,6 +17,7 @@
+
Don't show again
diff --git a/src/tabs/presets/presets.js b/src/tabs/presets/presets.js
index f731bbfd..79a9d8a6 100644
--- a/src/tabs/presets/presets.js
+++ b/src/tabs/presets/presets.js
@@ -17,7 +17,7 @@ import PresetsSourcesDialog from './SourcesDialog/SourcesDialog';
import PresetSource from './SourcesDialog/PresetSource';
const presets = {
- presetsRepo: null,
+ presetsRepo: [],
cliEngine: null,
pickedPresetList: [],
majorVersion: 1,
@@ -65,6 +65,7 @@ presets.readDom = function() {
this._domButtonPresetSources = $(".presets_sources_show");
this._domWarningNotOfficialSource = $(".presets_warning_not_official_source");
+ this._domWarningFailedToLoadRepositories = $(".presets_failed_to_load_repositories");
this._domWarningBackup = $(".presets_warning_backup");
this._domButtonHideBackupWarning = $(".presets_warning_backup_button_hide");
@@ -116,8 +117,10 @@ presets.onSaveClick = function() {
};
presets.markPickedPresetsAsFavorites = function() {
- for(const pickedPreset of this.pickedPresetList) {
- favoritePresets.add(pickedPreset.preset);
+ for (const pickedPreset of this.pickedPresetList) {
+ if (pickedPreset.presetRepo !== undefined){
+ favoritePresets.add(pickedPreset.preset, pickedPreset.presetRepo);
+ }
}
favoritePresets.saveToStorage();
@@ -134,7 +137,7 @@ presets.setupMenuButtons = function() {
this._domButtonCancel.on("click", () => {
- for(const pickedPreset of this.pickedPresetList) {
+ for (const pickedPreset of this.pickedPresetList) {
pickedPreset.preset.isPicked = false;
}
@@ -268,7 +271,7 @@ presets.onLoadConfigClick = function() {
.then(text => {
if (text) {
const cliStrings = text.split("\n");
- const pickedPreset = new PickedPreset({title: "user configuration"}, cliStrings);
+ const pickedPreset = new PickedPreset({title: "user configuration"}, cliStrings, undefined);
this.pickedPresetList.push(pickedPreset);
this.onSaveClick();
}
@@ -316,23 +319,32 @@ presets.reload = function() {
};
presets.tryLoadPresets = function() {
- const presetSource = this.presetsSourcesDialog.getActivePresetSource();
+ const presetSources = this.presetsSourcesDialog.getActivePresetSources();
- if (PresetSource.isUrlGithubRepo(presetSource.url)) {
- this.presetsRepo = new PresetsGithubRepo(presetSource.url, presetSource.gitHubBranch);
- } else {
- this.presetsRepo = new PresetsWebsiteRepo(presetSource.url);
- }
+ this.presetsRepo = presetSources.map(source => {
+ if (PresetSource.isUrlGithubRepo(source.url)) {
+ return new PresetsGithubRepo(source.url, source.gitHubBranch, source.official, source.name);
+ } else {
+ return new PresetsWebsiteRepo(source.url, source.official, source.name);
+ }
+ });
this._divMainContent.toggle(false);
this._divGlobalLoadingError.toggle(false);
this._divGlobalLoading.toggle(true);
- this._domWarningNotOfficialSource.toggle(!this.presetsSourcesDialog.isOfficialActive);
+ this._domWarningNotOfficialSource.toggle(this.presetsSourcesDialog.isThirdPartyActive);
- this.presetsRepo.loadIndex()
- .then(() => this.checkPresetSourceVersion())
+ const failedToLoad = [];
+
+ Promise.all(this.presetsRepo.map(p => p.loadIndex().catch((reason => failedToLoad.push(p)))))
.then(() => {
- favoritePresets.addLastPickDate(this.presetsRepo.index.presets);
+ this._domWarningFailedToLoadRepositories.toggle(failedToLoad.length > 0);
+ this._domWarningFailedToLoadRepositories.html(i18n.getMessage("presetsFailedToLoadRepositories", {"repos": failedToLoad.map(repo => repo.name).join("; ")}));
+ this.presetsRepo = this.presetsRepo.filter(repo => !failedToLoad.includes(repo));
+ return this.checkPresetSourceVersion();
+ })
+ .then(() => {
+ this.presetsRepo.forEach(p => favoritePresets.addLastPickDate(p.index.presets, p));
this.prepareFilterFields();
this._divGlobalLoading.toggle(false);
this._divMainContent.toggle(true);
@@ -365,11 +377,12 @@ presets.checkPresetSourceVersion = function() {
const self = this;
return new Promise((resolve, reject) => {
- if (self.majorVersion === self.presetsRepo.index.majorVersion) {
+ const differentMajorVersionsRepos = self.presetsRepo.filter(pr => self.majorVersion !== pr.index.majorVersion);
+ if (differentMajorVersionsRepos.length === 0) {
resolve();
} else {
const versionRequired = `${self.majorVersion}.X`;
- const versionSource = `${self.presetsRepo.index.majorVersion}.${self.presetsRepo.index.minorVersion}`;
+ const versionSource = `${differentMajorVersionsRepos[0].index.majorVersion}.${differentMajorVersionsRepos[0].index.minorVersion}`;
const dialogSettings = {
title: i18n.getMessage("presetsWarningDialogTitle"),
@@ -377,7 +390,7 @@ presets.checkPresetSourceVersion = function() {
buttonYesText: i18n.getMessage("yes"),
buttonNoText: i18n.getMessage("no"),
buttonYesCallback: () => resolve(),
- buttonNoCallback: () => reject("Prset source version mismatch"),
+ buttonNoCallback: () => reject("Preset source version mismatch"),
};
GUI.showYesNoDialog(dialogSettings);
@@ -385,13 +398,21 @@ presets.checkPresetSourceVersion = function() {
});
};
+function getUniqueValues(objects, extractor) {
+ let values = objects.map(extractor);
+ let uniqueValues = [...values.reduce((a, b) => new Set([...a, ...b]), new Set())];
+ return uniqueValues.sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}));
+}
+
presets.prepareFilterFields = function() {
this._freezeSearch = true;
- this.prepareFilterSelectField(this._selectCategory, this.presetsRepo.index.uniqueValues.category, 3);
- this.prepareFilterSelectField(this._selectKeyword, this.presetsRepo.index.uniqueValues.keywords, 3);
- this.prepareFilterSelectField(this._selectAuthor, this.presetsRepo.index.uniqueValues.author, 1);
- this.prepareFilterSelectField(this._selectFirmwareVersion, this.presetsRepo.index.uniqueValues.firmware_version, 2);
- this.prepareFilterSelectField(this._selectStatus, this.presetsRepo.index.settings.PresetStatusEnum, 2);
+
+ this.prepareFilterSelectField(this._selectCategory, getUniqueValues(this.presetsRepo, x => x.index.uniqueValues.category), 3);
+ this.prepareFilterSelectField(this._selectKeyword, getUniqueValues(this.presetsRepo, x => x.index.uniqueValues.keywords), 3);
+ this.prepareFilterSelectField(this._selectAuthor, getUniqueValues(this.presetsRepo, x => x.index.uniqueValues.author), 1);
+ this.prepareFilterSelectField(this._selectFirmwareVersion, getUniqueValues(this.presetsRepo, x => x.index.uniqueValues.firmware_version), 2);
+ this.prepareFilterSelectField(this._selectStatus, getUniqueValues(this.presetsRepo, x => x.index.settings.PresetStatusEnum), 2);
+
this.multipleSelectComponentScrollFix().then(() => {
this.preselectFilterFields();
this._inputTextFilter.on('input', () => this.updateSearchResults());
@@ -404,9 +425,11 @@ presets.preselectFilterFields = function() {
const currentVersion = FC.CONFIG.flightControllerVersion;
const selectedVersions = [];
- for(const bfVersion of this.presetsRepo.index.uniqueValues.firmware_version) {
- if (currentVersion.startsWith(bfVersion)) {
- selectedVersions.push(bfVersion);
+ for (const repo of this.presetsRepo) {
+ for (const bfVersion of repo.index.uniqueValues.firmware_version) {
+ if (currentVersion.startsWith(bfVersion)) {
+ selectedVersions.push(bfVersion);
+ }
}
}
@@ -474,25 +497,29 @@ presets.displayPresets = function(fitPresets) {
this._domListNoFound.toggle(fitPresets.length === 0);
fitPresets.forEach(preset => {
- const presetPanel = new PresetTitlePanel(this._divPresetList, preset, true, undefined, favoritePresets);
+ const presetPanel = new PresetTitlePanel(this._divPresetList, preset[0], preset[1], true, this.presetsSourcesDialog.isThirdPartyActive, favoritePresets);
presetPanel.load();
this._presetPanels.push(presetPanel);
- presetPanel.subscribeClick(this.presetsDetailedDialog, this.presetsRepo);
+ presetPanel.subscribeClick(this.presetsDetailedDialog, preset[1]);
});
this._domListTooManyFound.appendTo(this._divPresetList);
};
+
presets.getFitPresets = function(searchParams) {
const result = [];
-
- for(const preset of this.presetsRepo.index.presets) {
- if(this.isPresetFitSearch(preset, searchParams)) {
- result.push(preset);
+ const seenHashes = new Set();
+ for (const repo of this.presetsRepo){
+ for (const preset of repo.index.presets) {
+ if (this.isPresetFitSearch(preset, searchParams) && !seenHashes.has(preset.hash)) {
+ result.push([preset, repo]);
+ seenHashes.add(preset.hash);
+ }
}
}
- result.sort((a, b) => this.presetSearchPriorityComparer(a,b));
+ result.sort((a, b) => this.presetSearchPriorityComparer(a[0], b[0]));
return result;
};
@@ -653,7 +680,7 @@ presets.cleanup = function(callback) {
presets.resetInitialValues = function() {
CONFIGURATOR.cliEngineActive = false;
CONFIGURATOR.cliEngineValid = false;
- TABS.presets.presetsRepo = null;
+ TABS.presets.presetsRepo = [];
TABS.presets.pickedPresetList.length = 0;
this._domProgressDialog.close();
};