Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,4 @@ photon-client/playwright-report/
photon-client/blob-report/
photon-client/playwright/.cache/
photon-client/playwright/.auth/
photon-client/package-lock.json
45 changes: 43 additions & 2 deletions photon-client/src/components/settings/DeviceCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { inject, computed, ref, watch } from "vue";
import { useStateStore } from "@/stores/StateStore";
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
import PvSelect from "@/components/common/pv-select.vue";
import PvSwitch from "@/components/common/pv-switch.vue";
import PvDeleteModal from "@/components/common/pv-delete-modal.vue";
import MetricsChart from "./MetricsChart.vue";
import { useTheme } from "vuetify";
Expand Down Expand Up @@ -128,9 +129,15 @@ const openExportLogsPrompt = () => {
};

const exportSettings = ref();
const showExportDialog = ref(false);
const excludeImages = ref(false);
const openExportSettingsPrompt = () => {
exportSettings.value.click();
};
const doExportSettings = () => {
showExportDialog.value = false;
exportSettings.value.click();
};

enum ImportType {
AllSettings,
Expand Down Expand Up @@ -356,7 +363,7 @@ watch(metricsHistorySnapshot, () => {
<v-btn
color="buttonPassive"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="openExportSettingsPrompt"
@click="() => (showExportDialog = true)"
>
<v-icon start class="open-icon" size="large"> mdi-export </v-icon>
<span class="open-label">Export Settings</span>
Expand Down Expand Up @@ -540,6 +547,40 @@ watch(metricsHistorySnapshot, () => {
</v-card>
</v-dialog>

<!-- Export settings modal -->
<v-dialog
v-model="showExportDialog"
width="600"
@update:modelValue="
() => {
excludeImages = false;
}
"
>
<v-card color="surface" dark>
<v-card-title class="pb-0">Export Settings</v-card-title>
<v-card-text>
Download a ZIP archive of all PhotonVision settings from this device
<div class="pa-5 pb-0">
<pv-switch
v-model="excludeImages"
label="Exclude calibration images"
tooltip="Exclude saved calibration images and snapshots from the export to reduce file size"
/>
<v-btn
color="primary"
class="mt-4"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="doExportSettings"
>
<v-icon start class="open-icon"> mdi-export </v-icon>
<span class="open-label">Export Settings</span>
</v-btn>
</div>
</v-card-text>
</v-card>
</v-dialog>

<v-dialog v-model="offlineUpdateDialog.show" :width="700" dark>
<v-card color="surface" flat>
<v-card-title style="display: flex; justify-content: center"> Offline Update </v-card-title>
Expand Down Expand Up @@ -570,7 +611,7 @@ watch(metricsHistorySnapshot, () => {
<a
ref="exportSettings"
style="color: black; text-decoration: none; display: none"
:href="`http://${address}/api/settings/photonvision_config.zip`"
:href="`http://${address}/api/settings/photonvision_config.zip${excludeImages ? '?excludeImages=true' : ''}`"
download="photonvision-settings.zip"
target="_blank"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,28 @@ public void saveModule(CameraConfiguration config, String uniqueName) {
}

public File getSettingsFolderAsZip() {
return getSettingsFolderAsZip(false);
}

public File getSettingsFolderAsZip(boolean excludeImages) {
File out = Path.of(System.getProperty("java.io.tmpdir"), "photonvision-settings.zip").toFile();
try {
ZipUtil.pack(configDirectoryFile, out);
if (excludeImages) {
ZipUtil.pack(
configDirectoryFile,
out,
name -> {
// Exclude calibration images and saved snapshots
if (name.startsWith("calibImgs/")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good software is DRY - this hardcodes an assumption about the names of the directories, but there's other varibles which define those already.

|| name.startsWith("calibration/")
|| name.startsWith("imgSaves/")) {
return null;
}
return name;
});
} else {
ZipUtil.pack(configDirectoryFile, out);
}
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,11 @@ public static void onSettingsImportRequest(Context ctx) {
}

public static void onSettingsExportRequest(Context ctx) {
logger.info("Exporting Settings to ZIP Archive");
boolean excludeImages = Boolean.parseBoolean(ctx.queryParam("excludeImages"));
logger.info("Exporting Settings to ZIP Archive (excludeImages=" + excludeImages + ")");

try {
var zip = ConfigManager.getInstance().getSettingsFolderAsZip();
var zip = ConfigManager.getInstance().getSettingsFolderAsZip(excludeImages);
var stream = new FileInputStream(zip);
logger.info("Uploading settings with size " + stream.available());

Expand Down
Loading