Plan cloud bulk upload progress in app core

This commit is contained in:
2026-06-02 23:42:27 +02:00
parent 8a7db3bca8
commit d9be3f910a
9 changed files with 148 additions and 8 deletions

View File

@@ -422,6 +422,11 @@ Known local toolchain state:
new-document warning, publish prompt, and save-before-upload planning as JSON; new-document warning, publish prompt, and save-before-upload planning as JSON;
the live cloud upload command consumes the same start contract before the live cloud upload command consumes the same start contract before
reaching legacy UI, canvas save, and network upload execution. reaching legacy UI, canvas save, and network upload execution.
- `pano_cli plan-cloud-upload-all` exposes bulk cloud upload file-count,
progress UI availability, and progress-total clamping as JSON; the live
upload-all command consumes the same contract before reaching legacy asset
file listing, OpenGL context guard, progress UI, and network upload
execution.
- `pano_cli plan-cloud-browse` exposes `pp_app_core` cloud browse availability - `pano_cli plan-cloud-browse` exposes `pp_app_core` cloud browse availability
and selected-file download planning as JSON; the live cloud browse command and selected-file download planning as JSON; the live cloud browse command
consumes those contracts before reaching legacy dialog, network download, consumes those contracts before reaching legacy dialog, network download,
@@ -441,7 +446,8 @@ Known local toolchain state:
- `pp_app_core_document_cloud_tests` covers cloud upload no-canvas, - `pp_app_core_document_cloud_tests` covers cloud upload no-canvas,
new-document warning, clean publish prompt, and dirty save-before-upload new-document warning, clean publish prompt, and dirty save-before-upload
decisions, plus cloud browse no-canvas/show-browser and selected-download decisions, plus cloud browse no-canvas/show-browser and selected-download
decisions. decisions, plus bulk upload progress visibility, zero-file, and clamped
progress-total decisions.
- `pp_app_core_document_session_tests` covers clean and dirty app session, - `pp_app_core_document_session_tests` covers clean and dirty app session,
document-open action planning, save-request, save-before-workflow, document-open action planning, save-request, save-before-workflow,
new-document target/resolution/overwrite planning, document file target, new-document target/resolution/overwrite planning, document file target,

View File

@@ -77,7 +77,7 @@ and validation command.
| Capability | Current Area | Target Owner | Required Tests | | Capability | Current Area | Target Owner | Required Tests |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Upload/download/browse | `app_cloud`, CURL helpers | `pp_app_core`, app service, `pp_platform_*` | Upload prompt/new-doc/no-canvas decision tests, browse/selection decision tests, mocked HTTP and timeout tests | | Upload/download/browse | `app_cloud`, CURL helpers | `pp_app_core`, app service, `pp_platform_*` | Upload prompt/new-doc/no-canvas decision tests, bulk-upload progress decision tests, browse/selection decision tests, mocked HTTP and timeout tests |
| License/check flows | app/cloud code | app service | Mocked response tests | | License/check flows | app/cloud code | app service | Mocked response tests |
| Logging/crash reporting | `log`, BugTrap/AppCenter | `pp_foundation`, platform wrappers | Log formatting and platform compile | | Logging/crash reporting | `log`, BugTrap/AppCenter | `pp_foundation`, platform wrappers | Log formatting and platform compile |
| Headless automation | none yet | `tools/pano_cli` | JSON command fixtures | | Headless automation | none yet | `tools/pano_cli` | JSON command fixtures |

View File

@@ -22,7 +22,7 @@ agent or engineer to remove them without reconstructing context from chat.
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| DEBT-0001 | Open | Modernization | Existing platform build files remain alongside new CMake | Required for incremental migration without losing platform coverage | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets | | DEBT-0001 | Open | Modernization | Existing platform build files remain alongside new CMake | Required for incremental migration without losing platform coverage | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets |
| DEBT-0002 | Open | Modernization | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only, patched, or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace with vcpkg packages or document permanent vendored status after triplet evaluation | | DEBT-0002 | Open | Modernization | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only, patched, or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace with vcpkg packages or document permanent vendored status after triplet evaluation |
| DEBT-0003 | Open | Modernization | Existing singletons remain during initial split; `App::open_document`, `App::request_close`, `App::cloud_upload`, `App::cloud_browse`, file-menu save actions, `NodeCanvas` save hotkeys, new/open/browse dirty-document workflow prompts, new-document target/resolution/overwrite decisions, save-as document file naming and overwrite decisions, save-version target decisions, export start/target naming/path decisions, cloud-upload prompt/save-before-upload decisions, cloud-browse availability and selected-download decisions, `pano_cli classify-open`, `pano_cli plan-open-route`, `pano_cli plan-new-document`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `pano_cli plan-export-start`, `pano_cli plan-export-target`, `pano_cli plan-cloud-upload`, `pano_cli plan-cloud-browse`, and `pano_cli simulate-app-session` now consume pure `pp_app_core` route/session/export/cloud contracts, but document creation/loading, brush import execution, saving, export execution, cloud upload execution, and cloud browse/download execution still reach legacy `Canvas::I`/UI/network singletons | Avoid behavior changes while introducing component boundaries | App launch and component tests; `pp_app_core_document_route_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_cloud_tests`; `pp_app_core_document_session_tests`; `pano_cli classify-open --path D:/Paint/demo.ppi`; `pano_cli plan-open-route --path D:/Paint/demo.ppi --unsaved`; `pano_cli plan-new-document --work-dir D:/Paint --name demo --resolution-index 3 --target-exists`; `pano_cli plan-document-file --work-dir D:/Paint --name demo --target-exists`; `pano_cli plan-document-version --directory D:/Paint --doc-name demo.01 --existing-path D:/Paint/demo.02.ppi`; `pano_cli plan-export-start --requires-license --demo`; `pano_cli plan-export-target --kind file --work-dir D:/Paint --doc-name demo --extension .png`; `pano_cli plan-cloud-upload --new-document --unsaved`; `pano_cli plan-cloud-browse --selected-file demo.ppi`; `pano_cli simulate-app-session --unsaved --save-intent save-dirty-version`; `pano_cli simulate-app-session --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Replace singleton reaches with context/service injection at component boundaries | | DEBT-0003 | Open | Modernization | Existing singletons remain during initial split; `App::open_document`, `App::request_close`, `App::cloud_upload`, `App::cloud_upload_all`, `App::cloud_browse`, file-menu save actions, `NodeCanvas` save hotkeys, new/open/browse dirty-document workflow prompts, new-document target/resolution/overwrite decisions, save-as document file naming and overwrite decisions, save-version target decisions, export start/target naming/path decisions, cloud-upload prompt/save-before-upload decisions, cloud-browse availability and selected-download decisions, bulk cloud-upload progress decisions, `pano_cli classify-open`, `pano_cli plan-open-route`, `pano_cli plan-new-document`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `pano_cli plan-export-start`, `pano_cli plan-export-target`, `pano_cli plan-cloud-upload`, `pano_cli plan-cloud-browse`, `pano_cli plan-cloud-upload-all`, and `pano_cli simulate-app-session` now consume pure `pp_app_core` route/session/export/cloud contracts, but document creation/loading, brush import execution, saving, export execution, cloud upload execution, and cloud browse/download execution still reach legacy `Canvas::I`/UI/network singletons | Avoid behavior changes while introducing component boundaries | App launch and component tests; `pp_app_core_document_route_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_cloud_tests`; `pp_app_core_document_session_tests`; `pano_cli classify-open --path D:/Paint/demo.ppi`; `pano_cli plan-open-route --path D:/Paint/demo.ppi --unsaved`; `pano_cli plan-new-document --work-dir D:/Paint --name demo --resolution-index 3 --target-exists`; `pano_cli plan-document-file --work-dir D:/Paint --name demo --target-exists`; `pano_cli plan-document-version --directory D:/Paint --doc-name demo.01 --existing-path D:/Paint/demo.02.ppi`; `pano_cli plan-export-start --requires-license --demo`; `pano_cli plan-export-target --kind file --work-dir D:/Paint --doc-name demo --extension .png`; `pano_cli plan-cloud-upload --new-document --unsaved`; `pano_cli plan-cloud-browse --selected-file demo.ppi`; `pano_cli plan-cloud-upload-all --file-count 3`; `pano_cli simulate-app-session --unsaved --save-intent save-dirty-version`; `pano_cli simulate-app-session --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Replace singleton reaches with context/service injection at component boundaries |
| DEBT-0004 | Open | Modernization | Android, Linux, WebGL, Apple, and AppX build files remain platform-specific until root CMake alignment reaches them | Prevent platform regressions during incremental migration; raw Windows `.sln/.vcxproj` files were removed on 2026-05-31 by user decision | `cmake --preset windows-msvc-default`; platform-specific configure/build smoke checks as each platform is migrated | Root CMake owns every platform source list and package path | | DEBT-0004 | Open | Modernization | Android, Linux, WebGL, Apple, and AppX build files remain platform-specific until root CMake alignment reaches them | Prevent platform regressions during incremental migration; raw Windows `.sln/.vcxproj` files were removed on 2026-05-31 by user decision | `cmake --preset windows-msvc-default`; platform-specific configure/build smoke checks as each platform is migrated | Root CMake owns every platform source list and package path |
| DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | `vcpkg` is not currently on PATH, but headless tests need to run now | `ctest --preset desktop-fast --build-config Debug` | Replace `tests/test_harness.h` tests with Catch2 tests once vcpkg toolchain/presets are validated | | DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | `vcpkg` is not currently on PATH, but headless tests need to run now | `ctest --preset desktop-fast --build-config Debug` | Replace `tests/test_harness.h` tests with Catch2 tests once vcpkg toolchain/presets are validated |
| DEBT-0007 | Open | Modernization | `vcpkg.json` and `windows-msvc-vcpkg-headless` are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven | Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | `$env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless`; `ctest --preset desktop-fast-vcpkg --build-config Debug` | Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions | | DEBT-0007 | Open | Modernization | `vcpkg.json` and `windows-msvc-vcpkg-headless` are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven | Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | `$env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless`; `ctest --preset desktop-fast-vcpkg --build-config Debug` | Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions |

View File

@@ -448,6 +448,10 @@ canvas/recording export execution.
the live cloud upload command for missing-canvas, new-document warning, publish the live cloud upload command for missing-canvas, new-document warning, publish
prompt, and dirty-document save-before-upload states before legacy UI, canvas, prompt, and dirty-document save-before-upload states before legacy UI, canvas,
and network execution continue. and network execution continue.
`pano_cli plan-cloud-upload-all` exposes the app-core bulk upload file-count,
progress UI, and progress-total clamping decision used by the live upload-all
command before legacy asset listing, OpenGL context guard, progress UI, and
network upload execution continue.
`pano_cli plan-cloud-browse` exposes the app-core cloud browse and selected `pano_cli plan-cloud-browse` exposes the app-core cloud browse and selected
download decisions used by the live cloud browse command before legacy dialog, download decisions used by the live cloud browse command before legacy dialog,
network download, canvas project-open, layer UI, and action-history execution network download, canvas project-open, layer UI, and action-history execution
@@ -900,12 +904,16 @@ Results:
- `pp_app_core_document_cloud_tests` passed, covering cloud upload no-canvas, - `pp_app_core_document_cloud_tests` passed, covering cloud upload no-canvas,
new-document warning, clean publish prompt, and dirty save-before-upload new-document warning, clean publish prompt, and dirty save-before-upload
decisions, plus cloud browse no-canvas/show-browser and selected-download decisions, plus cloud browse no-canvas/show-browser and selected-download
decisions. decisions, plus bulk upload progress visibility, zero-file, and clamped
progress-total decisions.
- `pano_cli_plan_cloud_upload_clean_smoke`, - `pano_cli_plan_cloud_upload_clean_smoke`,
`pano_cli_plan_cloud_upload_unsaved_smoke`, `pano_cli_plan_cloud_upload_unsaved_smoke`,
`pano_cli_plan_cloud_upload_new_document_smoke`, and `pano_cli_plan_cloud_upload_new_document_smoke`, and
`pano_cli_plan_cloud_upload_no_canvas_smoke` passed and expose those app-core `pano_cli_plan_cloud_upload_no_canvas_smoke` passed and expose those app-core
cloud upload decisions as JSON. cloud upload decisions as JSON.
- `pano_cli_plan_cloud_upload_all_progress_smoke` and
`pano_cli_plan_cloud_upload_all_headless_smoke` passed and expose app-core
bulk upload progress decisions as JSON.
- `pano_cli_plan_cloud_browse_waiting_smoke`, - `pano_cli_plan_cloud_browse_waiting_smoke`,
`pano_cli_plan_cloud_browse_selected_smoke`, and `pano_cli_plan_cloud_browse_selected_smoke`, and
`pano_cli_plan_cloud_browse_no_canvas_smoke` passed and expose app-core cloud `pano_cli_plan_cloud_browse_no_canvas_smoke` passed and expose app-core cloud

View File

@@ -60,22 +60,23 @@ void App::cloud_upload_all()
BT_SetTerminate(); BT_SetTerminate();
auto names = Asset::list_files(data_path, ".*\\.ppi"); auto names = Asset::list_files(data_path, ".*\\.ppi");
const auto plan = pp::app::plan_cloud_bulk_upload(names.size(), layout.m_loaded);
gl_state gl; gl_state gl;
std::shared_ptr<NodeProgressBar> pb; std::shared_ptr<NodeProgressBar> pb;
if (layout.m_loaded) if (plan.show_progress)
pb = show_progress("Export Pano Image", names.size()); pb = show_progress("Export Pano Image", plan.progress_total);
for (const auto& n : names) for (const auto& n : names)
{ {
std::string path = data_path + "/" + n; std::string path = data_path + "/" + n;
upload(path); upload(path);
if (layout.m_loaded) if (plan.show_progress)
pb->increment(); pb->increment();
} }
if (layout.m_loaded) if (plan.show_progress)
pb->destroy(); pb->destroy();
}).detach(); }).detach();

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <cstddef>
#include <limits>
#include <string_view> #include <string_view>
namespace pp::app { namespace pp::app {
@@ -25,6 +27,12 @@ struct CloudUploadPlan {
bool save_before_upload = false; bool save_before_upload = false;
}; };
struct CloudBulkUploadPlan {
std::size_t file_count = 0;
int progress_total = 0;
bool show_progress = false;
};
[[nodiscard]] constexpr CloudUploadPlan plan_cloud_upload( [[nodiscard]] constexpr CloudUploadPlan plan_cloud_upload(
bool has_canvas, bool has_canvas,
bool is_new_document, bool is_new_document,
@@ -56,4 +64,16 @@ struct CloudUploadPlan {
: CloudDownloadSelectionAction::start_download; : CloudDownloadSelectionAction::start_download;
} }
[[nodiscard]] constexpr CloudBulkUploadPlan plan_cloud_bulk_upload(
std::size_t file_count,
bool progress_ui_available) noexcept
{
const auto max_progress_total = static_cast<std::size_t>(std::numeric_limits<int>::max());
return {
file_count,
file_count > max_progress_total ? std::numeric_limits<int>::max() : static_cast<int>(file_count),
progress_ui_available,
};
}
} }

View File

@@ -531,6 +531,18 @@ if(TARGET pano_cli)
LABELS "app;integration;desktop-fast;fuzz" LABELS "app;integration;desktop-fast;fuzz"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-browse\".*\"hasCanvas\":false.*\"browseDecision\":\"unavailable-no-canvas\".*\"selectionDecision\":\"start-download\"") PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-browse\".*\"hasCanvas\":false.*\"browseDecision\":\"unavailable-no-canvas\".*\"selectionDecision\":\"start-download\"")
add_test(NAME pano_cli_plan_cloud_upload_all_progress_smoke
COMMAND pano_cli plan-cloud-upload-all --file-count 3)
set_tests_properties(pano_cli_plan_cloud_upload_all_progress_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload-all\".*\"fileCount\":3.*\"progressUiAvailable\":true.*\"progressTotal\":3.*\"showProgress\":true")
add_test(NAME pano_cli_plan_cloud_upload_all_headless_smoke
COMMAND pano_cli plan-cloud-upload-all --file-count 3 --no-progress-ui)
set_tests_properties(pano_cli_plan_cloud_upload_all_headless_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload-all\".*\"fileCount\":3.*\"progressUiAvailable\":false.*\"progressTotal\":3.*\"showProgress\":false")
add_test(NAME pano_cli_simulate_app_session_clean_smoke add_test(NAME pano_cli_simulate_app_session_clean_smoke
COMMAND pano_cli simulate-app-session) COMMAND pano_cli simulate-app-session)
set_tests_properties(pano_cli_simulate_app_session_clean_smoke PROPERTIES set_tests_properties(pano_cli_simulate_app_session_clean_smoke PROPERTIES

View File

@@ -55,6 +55,39 @@ void cloud_download_selection_starts_for_selected_file(pp::tests::Harness& harne
pp::app::plan_cloud_download_selection("demo.ppi") == pp::app::CloudDownloadSelectionAction::start_download); pp::app::plan_cloud_download_selection("demo.ppi") == pp::app::CloudDownloadSelectionAction::start_download);
} }
void cloud_bulk_upload_shows_progress_when_ui_available(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_cloud_bulk_upload(3, true);
PP_EXPECT(harness, plan.file_count == 3);
PP_EXPECT(harness, plan.progress_total == 3);
PP_EXPECT(harness, plan.show_progress);
}
void cloud_bulk_upload_runs_without_progress_when_ui_unavailable(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_cloud_bulk_upload(3, false);
PP_EXPECT(harness, plan.file_count == 3);
PP_EXPECT(harness, plan.progress_total == 3);
PP_EXPECT(harness, !plan.show_progress);
}
void cloud_bulk_upload_keeps_zero_file_progress_explicit(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_cloud_bulk_upload(0, true);
PP_EXPECT(harness, plan.file_count == 0);
PP_EXPECT(harness, plan.progress_total == 0);
PP_EXPECT(harness, plan.show_progress);
}
void cloud_bulk_upload_clamps_progress_total(pp::tests::Harness& harness)
{
const auto too_many_files = static_cast<std::size_t>(std::numeric_limits<int>::max()) + 1U;
const auto plan = pp::app::plan_cloud_bulk_upload(too_many_files, true);
PP_EXPECT(harness, plan.file_count == too_many_files);
PP_EXPECT(harness, plan.progress_total == std::numeric_limits<int>::max());
PP_EXPECT(harness, plan.show_progress);
}
} }
int main() int main()
@@ -68,5 +101,9 @@ int main()
harness.run("cloud browse shows browser with canvas", cloud_browse_shows_browser_with_canvas); harness.run("cloud browse shows browser with canvas", cloud_browse_shows_browser_with_canvas);
harness.run("cloud download selection waits for empty file", cloud_download_selection_waits_for_empty_file); harness.run("cloud download selection waits for empty file", cloud_download_selection_waits_for_empty_file);
harness.run("cloud download selection starts for selected file", cloud_download_selection_starts_for_selected_file); harness.run("cloud download selection starts for selected file", cloud_download_selection_starts_for_selected_file);
harness.run("cloud bulk upload shows progress when ui available", cloud_bulk_upload_shows_progress_when_ui_available);
harness.run("cloud bulk upload runs without progress when ui unavailable", cloud_bulk_upload_runs_without_progress_when_ui_unavailable);
harness.run("cloud bulk upload keeps zero file progress explicit", cloud_bulk_upload_keeps_zero_file_progress_explicit);
harness.run("cloud bulk upload clamps progress total", cloud_bulk_upload_clamps_progress_total);
return harness.finish(); return harness.finish();
} }

View File

@@ -148,6 +148,11 @@ struct PlanCloudBrowseArgs {
std::string selected_file; std::string selected_file;
}; };
struct PlanCloudUploadAllArgs {
std::uint32_t file_count = 0;
bool progress_ui_available = true;
};
struct SimulateAppSessionArgs { struct SimulateAppSessionArgs {
bool has_canvas = true; bool has_canvas = true;
bool new_document = false; bool new_document = false;
@@ -483,6 +488,7 @@ void print_help()
<< " plan-export-target --kind file|collection|stem|name --doc-name NAME [--work-dir DIR] [--directory DIR] [--extension EXT] [--suffix SUFFIX]\n" << " plan-export-target --kind file|collection|stem|name --doc-name NAME [--work-dir DIR] [--directory DIR] [--extension EXT] [--suffix SUFFIX]\n"
<< " plan-cloud-upload [--no-canvas] [--new-document] [--unsaved]\n" << " plan-cloud-upload [--no-canvas] [--new-document] [--unsaved]\n"
<< " plan-cloud-browse [--no-canvas] [--selected-file FILE]\n" << " plan-cloud-browse [--no-canvas] [--selected-file FILE]\n"
<< " plan-cloud-upload-all [--file-count N] [--no-progress-ui]\n"
<< " load-project --path FILE\n" << " load-project --path FILE\n"
<< " parse-layout --path FILE\n" << " parse-layout --path FILE\n"
<< " record-render [--width N] [--height N] [--exercise-clear]\n" << " record-render [--width N] [--height N] [--exercise-clear]\n"
@@ -1712,6 +1718,52 @@ int plan_cloud_browse(int argc, char** argv)
return 0; return 0;
} }
pp::foundation::Status parse_plan_cloud_upload_all_args(
int argc,
char** argv,
PlanCloudUploadAllArgs& args)
{
for (int i = 2; i < argc; ++i) {
const std::string_view key(argv[i]);
if (key == "--file-count") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
const auto value = pp::foundation::parse_u32(argv[++i]);
if (!value) {
return value.status();
}
args.file_count = value.value();
} else if (key == "--no-progress-ui") {
args.progress_ui_available = false;
} else {
return pp::foundation::Status::invalid_argument("unknown option");
}
}
return pp::foundation::Status::success();
}
int plan_cloud_upload_all(int argc, char** argv)
{
PlanCloudUploadAllArgs args;
const auto status = parse_plan_cloud_upload_all_args(argc, argv, args);
if (!status.ok()) {
print_error("plan-cloud-upload-all", status.message);
return 2;
}
const auto plan = pp::app::plan_cloud_bulk_upload(args.file_count, args.progress_ui_available);
std::cout << "{\"ok\":true,\"command\":\"plan-cloud-upload-all\""
<< ",\"state\":{\"fileCount\":" << args.file_count
<< ",\"progressUiAvailable\":" << json_bool(args.progress_ui_available)
<< "},\"plan\":{\"fileCount\":" << plan.file_count
<< ",\"progressTotal\":" << plan.progress_total
<< ",\"showProgress\":" << json_bool(plan.show_progress)
<< "}}\n";
return 0;
}
pp::foundation::Status parse_plan_export_target_args( pp::foundation::Status parse_plan_export_target_args(
int argc, int argc,
char** argv, char** argv,
@@ -3871,6 +3923,10 @@ int main(int argc, char** argv)
return plan_cloud_browse(argc, argv); return plan_cloud_browse(argc, argv);
} }
if (command == "plan-cloud-upload-all") {
return plan_cloud_upload_all(argc, argv);
}
if (command == "load-project") { if (command == "load-project") {
return load_project(argc, argv); return load_project(argc, argv);
} }