Compare commits

...

1,973 commits

Author SHA1 Message Date
anatawa12
9a1044df51
Merge pull request #2941 from nekobako/feature/project-sorting-by-creation-date
プロジェクトの登録順ソート
2026-06-18 22:40:23 +09:00
anatawa12
e71c48141b
chore: Apply localization suggestions from code review
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2026-06-18 22:34:31 +09:00
nekobako
467434903a docs(changelog-gui): update changelog 2026-06-17 23:20:01 +09:00
nekobako
ba8606d312 chore(gui): adjust project list spacing 2026-06-17 23:20:01 +09:00
nekobako
ed42cdfca4 feat(gui): implement project sorting by creation date 2026-06-17 23:20:01 +09:00
anatawa12
dbd479fbc9
Merge pull request #2976 from vrc-get/dependabot/cargo/uuid-1.23.3
chore(deps): bump uuid from 1.23.2 to 1.23.3
2026-06-15 19:44:33 +09:00
anatawa12
db54f0c8ae
Merge pull request #2970 from vrc-get/native-package
build: use package manager native toolchain to build linux packages
2026-06-15 17:46:38 +09:00
dependabot[bot]
da419a0374
chore(deps): bump uuid from 1.23.2 to 1.23.3
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.23.2 to 1.23.3.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.23.2...v1.23.3)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.23.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-15 07:43:41 +00:00
anatawa12
8351270552
chore!: remove deb / rpm build command 2026-06-15 16:01:18 +09:00
anatawa12
50fccc9a50
ci: migrate publish workflow to package manager native building toolchain 2026-06-15 09:56:40 +09:00
anatawa12
cf7075a6d5
fix: version name in bult binary is separated by ~ 2026-06-15 09:25:05 +09:00
anatawa12
5e4709209f
ci: do not patch source code in spec file, in source tar instead 2026-06-15 08:08:52 +09:00
anatawa12
269cb8aeda
ci: use jammy for building debian package 2026-06-15 00:29:45 +09:00
anatawa12
ba9ad1f59c
ci: add debian package and build on ci 2026-06-14 02:16:31 +09:00
anatawa12
23b1bb2515
ci: add rpm spec file and build on ci 2026-06-11 15:09:19 +09:00
github-actions[bot]
2c36473e6e chore: prepare for next version: gui 1.1.7 2026-06-02 10:44:59 +00:00
github-actions[bot]
791e50d94f gui v1.1.6 2026-06-02 10:29:07 +00:00
anatawa12
a77ab4a0a3
chore: better url handling 2026-06-02 19:26:07 +09:00
anatawa12
aa14673468
Merge pull request #2951 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-8.0.16
chore(deps-dev): bump vite from 8.0.14 to 8.0.16 in /vrc-get-gui
2026-06-02 16:21:30 +09:00
anatawa12
36aa59b304
Merge pull request #2949 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/biomejs/biome-2.4.16
chore(deps-dev): bump @biomejs/biome from 2.4.15 to 2.4.16 in /vrc-get-gui
2026-06-02 16:10:27 +09:00
anatawa12
b61c44c64a
Merge pull request #2950 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-1.17.0
chore(deps): bump lucide-react from 1.16.0 to 1.17.0 in /vrc-get-gui
2026-06-02 16:10:11 +09:00
anatawa12
0a5ab490b8
Merge pull request #2947 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-f873b873ff
chore(deps): bump i18next from 26.2.0 to 26.3.0 in /vrc-get-gui in the i18next group across 1 directory
2026-06-02 16:09:50 +09:00
dependabot[bot]
cfc1b627eb
chore(deps-dev): bump vite from 8.0.14 to 8.0.16 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.14 to 8.0.16.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 01:32:47 +00:00
dependabot[bot]
1b2065afe0
chore(deps-dev): bump @biomejs/biome in /vrc-get-gui
Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.4.15 to 2.4.16.
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.16/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 01:32:23 +00:00
anatawa12
4634c42410
Merge pull request #2946 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-116e156dcc
chore(deps): bump the tanstack-router group across 1 directory with 2 updates
2026-06-02 10:30:13 +09:00
dependabot[bot]
fd8b735ac9
chore(deps): bump the tanstack-router group across 1 directory with 2 updates
Bumps the tanstack-router group with 2 updates in the /vrc-get-gui directory: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.170.8 to 1.170.10
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.170.10/packages/react-router)

Updates `@tanstack/router-plugin` from 1.168.11 to 1.168.13
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-plugin/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-plugin@1.168.13/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.170.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.168.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 01:13:54 +00:00
anatawa12
580c8da047
Merge pull request #2948 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/rollup/pluginutils-5.4.0
chore(deps-dev): bump @rollup/pluginutils from 5.3.0 to 5.4.0 in /vrc-get-gui
2026-06-02 10:07:13 +09:00
dependabot[bot]
0ebfb25263
chore(deps): bump lucide-react from 1.16.0 to 1.17.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.17.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 01:06:55 +00:00
dependabot[bot]
9eaf99b3d1
chore(deps): bump i18next
Bumps the i18next group with 1 update in the /vrc-get-gui directory: [i18next](https://github.com/i18next/i18next).


Updates `i18next` from 26.2.0 to 26.3.0
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.2.0...v26.3.0)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 26.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 01:06:08 +00:00
anatawa12
87753ceffa
Merge pull request #2945 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-cd43639a56
chore(deps): bump the react group in /vrc-get-gui with 3 updates
2026-06-02 10:02:18 +09:00
anatawa12
0fa954cef0
Merge pull request #2944 from vrc-get/dependabot/cargo/uuid-1.23.2
chore(deps): bump uuid from 1.23.1 to 1.23.2
2026-06-02 10:00:32 +09:00
anatawa12
41e25d4e86
Merge pull request #2943 from vrc-get/dependabot/cargo/sysinfo-0.39.3
chore(deps): bump sysinfo from 0.39.2 to 0.39.3
2026-06-02 10:00:15 +09:00
anatawa12
3c499f9d6a
Merge pull request #2942 from vrc-get/dependabot/cargo/reqwest-0.13.4
chore(deps): bump reqwest from 0.13.3 to 0.13.4
2026-06-02 09:59:47 +09:00
dependabot[bot]
65e37ff7af
chore(deps-dev): bump @rollup/pluginutils in /vrc-get-gui
Bumps [@rollup/pluginutils](https://github.com/rollup/plugins/tree/HEAD/packages/pluginutils) from 5.3.0 to 5.4.0.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/pluginutils/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/pluginutils-v5.4.0/packages/pluginutils)

---
updated-dependencies:
- dependency-name: "@rollup/pluginutils"
  dependency-version: 5.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 00:15:03 +00:00
dependabot[bot]
48e1866ff3
chore(deps): bump the react group in /vrc-get-gui with 3 updates
Bumps the react group in /vrc-get-gui with 3 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react)

Updates `@types/react` from 19.2.15 to 19.2.16
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom)

Updates `@types/react` from 19.2.15 to 19.2.16
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 00:14:30 +00:00
dependabot[bot]
968ae63a4c
chore(deps): bump uuid from 1.23.1 to 1.23.2
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.23.1 to 1.23.2.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.23.1...v1.23.2)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.23.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 00:13:19 +00:00
dependabot[bot]
805be35ac6
chore(deps): bump sysinfo from 0.39.2 to 0.39.3
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.39.2 to 0.39.3.
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.39.2...v0.39.3)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-version: 0.39.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 00:12:47 +00:00
dependabot[bot]
901368c9bf
chore(deps): bump reqwest from 0.13.3 to 0.13.4
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.13.3 to 0.13.4.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.13.3...v0.13.4)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.13.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-02 00:12:33 +00:00
github-actions[bot]
09c8190634 v1.9.2-rc.0 2026-05-30 16:11:35 +00:00
anatawa12
5eed047fa4
Merge pull request #2940 from vrc-get/publish-workflow-crash
build: check-static-link for aarch64 linux is broken
2026-05-31 01:10:13 +09:00
anatawa12
056073834c
build: check-static-link for aarch64 linux is broken 2026-05-31 00:58:26 +09:00
anatawa12
c4117c7457
ci: allow dry-run for non-master branch 2026-05-31 00:37:37 +09:00
anatawa12
3bf6b96b93
ci: dry-run for cli build 2026-05-31 00:33:40 +09:00
anatawa12
00fb4d8546
ci: upload artifacts regardless build failure 2026-05-31 00:28:53 +09:00
github-actions[bot]
4d4c0c27d3 gui v1.1.6-rc.0 2026-05-30 14:43:02 +00:00
anatawa12
a31c947c1a
Merge pull request #2935 from nekochanfood/feat/reorder-user-repos
feat: リポジトリ一覧で並び替えができるようにする
2026-05-30 21:48:44 +09:00
nekochanfood
f6e677909c fix(gui): reject remove/reorder when settings.json drifted externally
remove/reorder targeted userRepos entries by array position only. An
external write to settings.json (another ALCOM instance, VCC, vrc-get
CLI, manual edit) between the frontend's last fetch and the call
could silently delete or reorder the wrong repo.

The frontend already has the expected id (part of TauriUserRepository),
so send it alongside the index and have the backend verify the repo at
that index still has the expected id before mutating. On mismatch,
reject with an `unrecoverable_str` error; the frontend's existing
onError + onSettled refetch rolls back optimistic state and shows the
on-disk truth.

- environment_remove_repository takes (index, expected_id)
- environment_reorder_repositories takes Vec<TauriUserRepositoryRef>;
  all pairs verified up front, no partial reorder on mismatch
- verify_repo_at_index helper centralises the lookup + comparison
2026-05-30 20:50:24 +09:00
nekochanfood
8b58270235 chore: move the order of the change 2026-05-30 20:27:04 +09:00
nekochanfood
c1b297e02a chore: clean up changelog entries for reorder/remove repo changes 2026-05-30 20:21:02 +09:00
Kissa Ruokanen
a0ec779fab
Merge pull request #1 from nekochanfood/feat/improve-duplicate-repo-handling
Feat/improve duplicate repo handling
2026-05-30 14:56:51 +09:00
nekochanfood
800278a0c3 style(vpm): satisfy fmt and clippy on reorder_user_repos_by_indices
Auto-applied cargo fmt for the collect-chain split, then folded the
nested `if let` into a let-chain and replaced the manual `if let Some`
loop with `into_iter().flatten()`.
2026-05-30 14:55:43 +09:00
nekochanfood
334492e5c6 refactor: clean up issues found in branch review
- vpm: drop unused id-based reorder_user_repos; reorder_user_repos_by_indices is the only caller
- CHANGELOG: reflect the actual public API surface (reorder_user_repos_by_indices, remove_repo_at_index)
- gui: rollback optimistic delete on error in RemoveRepositoryDialog, matching setHideRepository
- gui: demote per-reorder log from info to debug to reduce noise
2026-05-30 14:45:42 +09:00
nekochanfood
1a947b7a6c fix(gui): preserve listId identity for duplicate repos across refetch
Repos with duplicate (id, url) pairs had their per-row React keys
regenerated as `crypto.randomUUID()` on every refetch, causing scroll
reset and remount on the entire list. Stabilizing by `${id} ${url}`
key with an iteration-order counter would normally fix this, but for
duplicate-keyed rows the counter assignment depends on iteration
order: when two such repos swap positions, their slot keys swap, and
the lookup returns each other's UUID — React reconciles by tearing
both rows down (visible as a flicker on the row the dragged row
crossed over).

- Stabilize listId across refetch via listIdMapRef keyed on slot key
- Extract computeSlotKey helper for reuse
- Pin listIds to the new optimistic order in reorderMutation.onMutate
  so the post-refetch augmentation lookup returns the same listIds
- Snapshot and restore the previous map in onError so a failed reorder
  rolls back cleanly
2026-05-30 14:45:13 +09:00
nekochanfood
514f52a419 Revert "fix(gui): fix DnD drop artifact and item displacement flicker"
This reverts commit 6dfdd9c5f3.
2026-05-30 12:53:59 +09:00
nekochanfood
3e42f0de4e Revert "fix(gui): fix double-row artifact and scroll reset on dnd drop"
This reverts commit 21a0e19722.
2026-05-30 12:53:54 +09:00
nekochanfood
6dfdd9c5f3 fix(gui): fix DnD drop artifact and item displacement flicker
Replaced sideEffects-based opacity hack (broken by React re-renders) with
a droppingListId state that keeps the source row hidden for the duration of
the drop animation via React's own style prop.

Removed the visualIndex estimate (rowIndex ± 1 based on transform.y) that
caused continuous className toggling during drag; rows now use their stable
rowIndex for stripe coloring, eliminating the flicker.
2026-05-30 12:50:06 +09:00
nekochanfood
21a0e19722 fix(gui): fix double-row artifact and scroll reset on dnd drop
Two regressions introduced by the listId/UUID change:

- Scroll reset: crypto.randomUUID() in useMemo regenerated all listIds
  on every re-fetch, causing React to unmount/remount all rows and lose
  scroll position. Fixed by using String(r.index) instead — index is
  stable across re-fetches for items that haven't moved, so React can
  reconcile rows in place.

- Double-row artifact: on drop, isDragging becomes false before the
  DragOverlay drop animation completes, making the real row visible at
  the destination while the overlay is still animating there. Fixed by
  using defaultDropAnimationSideEffects to force opacity:0 on the
  original element for the duration of the drop animation.
2026-05-30 12:12:24 +09:00
nekochanfood
6ab9c49c94 fix(gui): stabilize repo list against duplicate IDs in userRepos
Repositories with duplicate `id` values in settings.json caused the
frontend list to break: React keys were non-unique, dnd-kit's
SortableContext misbehaved, and the Map lookup silently discarded
duplicate entries.

- Add `index` field to `TauriUserRepository` (position in the
  userRepos array, never persisted) so operations can target a
  specific entry regardless of ID uniqueness
- Replace ID-based remove/reorder commands with index-based variants
  (`remove_repo_at_index`, `reorder_user_repos_by_indices`) in both
  vpm_settings and the Tauri command layer
- Augment each repo with a frontend-only `listId` (crypto.randomUUID)
  used exclusively as React key and dnd-kit sortable item ID
2026-05-30 11:37:11 +09:00
Kissa Ruokanen
04adf285b5 style(gui): fix CSS selector formatting to satisfy Biome formatter 2026-05-30 09:41:43 +09:00
anatawa12
665513d0fc
Merge branch 'master' into feat/reorder-user-repos 2026-05-30 01:12:28 +09:00
anatawa12
6f8cd53159
Merge pull request #2939 from vrc-get/fix-buildx-devtools-not-working
build: cargo xtask build-alcom --devtools not working
2026-05-30 01:12:17 +09:00
anatawa12
ec6454b0d4
fix: cargo xtask build-alcom --devtools not working 2026-05-30 01:04:29 +09:00
nekochanfood
533a40b1eb fix(gui): account for vertical scrollbar width in ScrollableCardTable
When the vertical scrollbar is visible, its overlay covers the rightmost
10px of the table content. Add pe-2.5 to the content wrapper via CSS
so all ScrollableCardTable instances reserve space for the scrollbar.
2026-05-29 22:19:31 +09:00
nekochanfood
90c7e249cd fix(gui): fix scroll stuttering when dragging repository list items
- Move guiAnimation query and setHideRepository mutation from each
  RepositoryRow to PageBody, passing them down as props. Because
  useSortable subscribes all rows to DnD context, every pointermove
  during drag re-rendered every row. With O(N) expensive hooks per row
  this blocked the main thread for ~130ms per event (~7fps).

- Disable dnd-kit's built-in autoScroll (autoScroll={false}) and replace
  it with a useDragAutoScroll hook. dnd-kit's AutoScroller caused jitter
  due to wrong scroll-container detection in Radix UI ScrollArea and
  double-smoothing from the viewport's scroll-behavior: smooth. The
  custom hook targets the viewport directly via viewportRef and uses
  behavior: instant to avoid CSS smooth-scroll interference.

- Suppress background-color transition on rows during active drag to
  reduce paint operations when rows shift position.

- Replace orderedIds.includes() with a Set lookup in collisionDetection.
2026-05-29 20:56:30 +09:00
Kissa Ruokanen
e057838795 docs(changelog-gui): add entry for drag-and-drop repository reordering 2026-05-29 16:04:20 +09:00
Kissa Ruokanen
437a63bcc6 fix: sort @dnd-kit/core imports to satisfy biome lint 2026-05-29 16:02:18 +09:00
Kissa Ruokanen
836bf82351
Merge branch 'master' into feat/reorder-user-repos 2026-05-29 15:47:06 +09:00
Kissa Ruokanen
316c73a6b6 feat: animate drag overlay row color based on current drop position
Track the hovered droppable via onDragOver and compute the overlay's
visual index so its background color updates in real-time as it moves
between rows, matching the same bg-secondary/30 / transition spec used
by the sortable rows.
2026-05-29 15:38:35 +09:00
Kissa Ruokanen
ec04492af8 Merge branch 'feat/reorder-user-repos' of https://github.com/nekochanfood/vrc-get into feat/reorder-user-repos 2026-05-29 15:26:38 +09:00
Kissa Ruokanen
ebd117afd2 feat: animate row colors during drag with O(k) re-renders
Replace useDndContext() + arrayMove approach with transform.y sign
detection to compute visual row index. Previously all n rows subscribed
to the dnd context and re-rendered on every collision change, each
doing an O(n) arrayMove+indexOf -- O(n^2) total.

Now only rows whose transform changes re-render, and each computes its
visual index in O(1) from the sign of transform.y from useSortable.
Total cost is O(k) where k is the number of displaced rows (typically 1-2).

Also adds background-color to the inline transition string so the
200ms color animation works correctly alongside the transform animation,
and removes guiAnimation prop drilling through RepositoryTableBody.
2026-05-29 15:26:29 +09:00
Kissa Ruokanen
253a0266e6 fix: vertically center checkboxes in repository list
Wrap checkbox in flex container to eliminate inline-block descender
space, which caused the button to align to the text baseline rather
than the vertical center of the cell.
2026-05-29 15:14:27 +09:00
Kissa Ruokanen
0cf635e892 fix: vertically center checkboxes in repository list
Add align-middle to CELL_CLASS so all table cells use vertical-align: middle.
2026-05-29 14:56:48 +09:00
anatawa12
f8923dce1b
Merge pull request #2936 from vrc-get/funding-yml
docs: add FUNDING.yml
2026-05-29 14:52:50 +09:00
anatawa12
9fc228eed0
docs: add FUNDING.yml 2026-05-29 14:46:45 +09:00
Kissa Ruokanen
54113144a8 refactor: clean up animation-related code in repository list
- Remove redundant isDragging state; derive from activeId !== null
- Move TABLE_HEAD and DRAG_OVERLAY_MODIFIERS to module level to avoid
  per-render allocations
- Remove unnecessary ?? true fallback on initialData: true query result
- Eliminate guiAnimation prop drilling through RepositoryTableBody;
  RepositoryRow now reads directly from the shared React Query cache
2026-05-29 14:37:10 +09:00
Kissa Ruokanen
0ab6c9434b feat: add smooth drop animation for repository reordering
Use DragOverlay from @dnd-kit/core to show a floating row clone while
dragging, giving a smooth drop animation on release. The overlay uses
colgroup-based fixed column widths measured from the thead at drag start,
so columns align pixel-perfectly with the underlying table. Movement is
restricted to the vertical axis via a custom modifier.

Animation respects the existing gui-animation setting: dropAnimation is
disabled when animations are turned off, and non-active rows lose their
transition as well.

Extract shared RepositoryRowCells component so the table row and the drag
overlay render identical structure and styling from a single definition.
2026-05-29 14:33:52 +09:00
Kissa Ruokanen
9d94d8b929 refactor: memoize dragStyle and remove redundant index checks in handleDragEnd 2026-05-29 14:14:14 +09:00
Kissa Ruokanen
d1887eb467 fix: eliminate drag stutter by using custom collision detection
Replace live orderedIds updates during onDragOver with a custom
collision detection that filters droppable targets to user repos only.
This ensures `over` is always a valid user repo (clamping to the
boundary when the cursor leaves the list), so dnd-kit handles all
visual movement through CSS transforms without DOM reordering.
Eliminates the position warp that occurred when items swapped.
2026-05-29 14:06:13 +09:00
Kissa Ruokanen
45ed34f573 fix: preserve drag position when cursor leaves list bounds
Track last valid sort order via dragOverOrderRef during onDragOver so
that when the pointer leaves the sortable region (triggering cancel or
landing on a non-user-repo row), the item stays at its last reached
position instead of snapping back or jumping to the end of the list.
Also disable pointer-events on HNavBar while dragging to prevent Radix
UI from stealing pointer capture.
2026-05-29 13:39:11 +09:00
Kissa Ruokanen
930715960e fix: prevent snap-back when dragging outside list bounds
Use closestCenter collision detection so over never becomes null
when the cursor moves beyond the top or bottom of the sortable list.
2026-05-29 13:21:26 +09:00
Kissa Ruokanen
8db24b7b7c feat: implement drag-and-drop reordering of user repositories
Use @dnd-kit/core and @dnd-kit/sortable to wire up the existing drag
handles so users can reorder repositories by dragging. DndContext is
placed at the page level so pointer tracking is not lost when the cursor
moves outside the list area. Adds an info log in the Rust command so the
new order is visible in the app log viewer.
2026-05-29 13:19:33 +09:00
Kissa Ruokanen
44ed683c23 feat: dim drag handle and show not-allowed cursor for non-reorderable repositories
Official and curated repositories cannot be reordered, so their drag
handles are now rendered with opacity-50 and cursor-not-allowed to
visually indicate they are not interactive, consistent with how their
remove buttons are already disabled.
2026-05-29 12:40:56 +09:00
Kissa Ruokanen
c248b0ed55 chore: regenerate bindings.ts with environmentReorderRepositories 2026-05-29 10:57:51 +09:00
Kissa Ruokanen
9d11a5e816
Merge branch 'master' into feat/reorder-user-repos 2026-05-29 10:48:40 +09:00
Kissa Ruokanen
81d66143c9 feat: add environment_reorder_repositories Tauri command
Add `reorder_user_repos` to `VpmSettings` and `Settings`, and expose it
as the `environment_reorder_repositories` Tauri command to allow
reordering `userRepos` in `settings.json`.
2026-05-29 10:36:49 +09:00
anatawa12
6f143ac5e3
Merge pull request #2933 from vrc-get/settings-json-corruption-recover
recover from settings.json corruption with backup file
2026-05-29 10:29:58 +09:00
anatawa12
f44633a2ad
fix: toast are not shown because of delay in webview2 initialization 2026-05-29 09:30:19 +09:00
anatawa12
3fb8281a47
Merge pull request #2934 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2026-05-29 08:53:35 +09:00
JustBuddy
244946c234
chore(l10n): [de_DE] update locale 2026-05-28 22:57:28 +02:00
anatawa12
ccd252f8aa
docs(changelog-gui): We also added a backup file to recover from settings.json corruption 2026-05-28 23:31:10 +09:00
anatawa12
c2b2b9b491
feat: show warning toast when settings.json is recovered from corruption 2026-05-28 23:27:23 +09:00
anatawa12
9decfe400c
feat: create backup of settings.json to recover from corruption caused by VCC
VCC sometimes leaves settings.json corrupted and filled with NUL bytes,
likely because file contents are not fully synced to disk before or during writing.
vrc-get already uses fsynced temp-file replacement when writing settings.json,
but this does not protect against corruption caused by external writes.
This commit adds a backup file to recover from such corruption.
2026-05-28 23:21:41 +09:00
anatawa12
35e7537a90
Merge pull request #2932 from CirnoV/locale/ko-KR
chore(l10n): [ko] update locale
2026-05-28 20:09:32 +09:00
CirnoV
1800951c12 chore(l10n): [ko] update locale 2026-05-28 19:52:48 +09:00
anatawa12
76b0f05651
feat: recover project list from settings.json when settings json is corrupted 2026-05-28 19:46:03 +09:00
anatawa12
f45ee6514e
Merge pull request #2911 from Spokeek/french-translation
Update FR locales for 1.1.6
2026-05-28 10:23:12 +09:00
Spokeek
d421ee04b2
remove === prefix 2026-05-27 18:51:40 +02:00
Spokeek
bd92649248
Fix json5 2026-05-27 18:46:13 +02:00
Spokeek
68be14aa90
Update FR locales for 1.1.6 2026-05-27 18:20:57 +02:00
anatawa12
dd9673c2cb
Merge pull request #2924 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2026-05-27 19:11:15 +09:00
anatawa12
73cfa96f45
Merge pull request #2930 from vrc-get/support-empty-string-for-optional-url-field
chore: allow empty `changelogUrl` and `documentationUrl`
2026-05-26 22:58:20 +09:00
anatawa12
fa22fc3611
docs(changelog): Empty string for documentationUrl and changelogUrl are now allowed and ignored 2026-05-26 21:13:24 +09:00
anatawa12
8b61a0c806
chore: allow blank changelogUrl and documentationUrl 2026-05-26 20:13:55 +09:00
anatawa12
c37758d4c1
chore: allow empty changelogUrl and documentationUrl 2026-05-26 19:49:26 +09:00
夜嵐蝶Alma
37688599ae chore(l10n): [zh_hant] update locale 2026-05-25 21:40:04 +08:00
夜嵐蝶Alma
fcb0c5263d
Merge branch 'vrc-get:master' into master 2026-05-25 21:37:32 +08:00
github-actions[bot]
a7e19a6479 gui v1.1.6-beta.2 2026-05-25 11:36:25 +00:00
anatawa12
f0a7cbd050
Merge pull request #2926 from vrc-get/dependabot/cargo/log-0.4.30
chore(deps): bump log from 0.4.29 to 0.4.30
2026-05-25 20:15:45 +09:00
anatawa12
a9322f4d64
Merge pull request #2927 from vrc-get/dependabot/cargo/tar-0.4.46
chore(deps): bump tar from 0.4.45 to 0.4.46
2026-05-25 20:14:54 +09:00
dependabot[bot]
0c895bf4a5
chore(deps): bump tar from 0.4.45 to 0.4.46
Bumps [tar](https://github.com/composefs/tar-rs) from 0.4.45 to 0.4.46.
- [Release notes](https://github.com/composefs/tar-rs/releases)
- [Commits](https://github.com/composefs/tar-rs/compare/0.4.45...0.4.46)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 0.4.46
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 11:07:42 +00:00
dependabot[bot]
07e7279c31
chore(deps): bump log from 0.4.29 to 0.4.30
Bumps [log](https://github.com/rust-lang/log) from 0.4.29 to 0.4.30.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.29...0.4.30)

---
updated-dependencies:
- dependency-name: log
  dependency-version: 0.4.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 11:07:29 +00:00
anatawa12
a9e135b940
Merge pull request #2862 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/api-2.11.0
chore(deps): bump @tauri-apps/api from 2.10.1 to 2.11.0 in /vrc-get-gui
2026-05-25 19:51:23 +09:00
anatawa12
d2aca1554c
Merge pull request #2890 from vrc-get/dependabot/cargo/tauri-347ba455b6
chore(deps): bump the tauri group across 1 directory with 2 updates
2026-05-25 19:48:59 +09:00
anatawa12
5be2c13984
chore: support LIBDBUS_1_3 versioned symbol 2026-05-25 19:40:21 +09:00
anatawa12
1b1a0eefae
Merge pull request #2923 from vrc-get/dependabot/cargo/rpm-0.24.0
chore(deps): bump rpm from 0.22.0 to 0.24.0
2026-05-25 17:34:11 +09:00
copilot-swe-agent[bot]
3e94514b13
fix(xtask): handle non-numeric ELF symbol versions in linux bundling 2026-05-25 08:05:17 +00:00
copilot-swe-agent[bot]
56a32bad04
fix: add payload feature to rpm dependency to fix compilation errors 2026-05-25 07:59:08 +00:00
dependabot[bot]
fb6a6538d7
chore(deps): bump @tauri-apps/api from 2.10.1 to 2.11.0 in /vrc-get-gui
Bumps [@tauri-apps/api](https://github.com/tauri-apps/tauri) from 2.10.1 to 2.11.0.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.10.1...@tauri-apps/api-v2.11.0)

---
updated-dependencies:
- dependency-name: "@tauri-apps/api"
  dependency-version: 2.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 07:52:24 +00:00
anatawa12
ab64f403a5
Merge pull request #2910 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-fc9df4cbb5
chore(deps): bump the tanstack-router group across 1 directory with 3 updates
2026-05-25 16:50:04 +09:00
dependabot[bot]
96d8ced3bb
chore(deps): bump rpm from 0.22.0 to 0.24.0
Bumps [rpm](https://github.com/rpm-rs/rpm) from 0.22.0 to 0.24.0.
- [Changelog](https://github.com/rpm-rs/rpm-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rpm-rs/rpm/compare/v0.22.0...v0.24.0)

---
updated-dependencies:
- dependency-name: rpm
  dependency-version: 0.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 07:43:39 +00:00
anatawa12
bde10abd3b
Merge pull request #2896 from vrc-get/dependabot/cargo/object-0.39.1
chore(deps): bump object from 0.39.0 to 0.39.1
2026-05-25 16:41:19 +09:00
dependabot[bot]
e3313f0327
chore(deps): bump the tanstack-router group across 1 directory with 3 updates
Bumps the tanstack-router group with 3 updates in the /vrc-get-gui directory: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.168.25 to 1.170.8
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.170.8/packages/react-router)

Updates `@tanstack/router-devtools` from 1.166.13 to 1.167.0
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-devtools/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-devtools@1.167.0/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.167.28 to 1.168.11
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-plugin/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-plugin@1.168.11/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.170.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.167.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.168.6
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 07:40:08 +00:00
anatawa12
bb0b8cda55
Merge pull request #2908 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/cli-2.11.2
chore(deps-dev): bump @tauri-apps/cli from 2.10.1 to 2.11.2 in /vrc-get-gui
2026-05-25 16:37:44 +09:00
anatawa12
11b6b1cad4
Merge pull request #2877 from vrc-get/dependabot/cargo/rpassword-7.5.2
chore(deps): bump rpassword from 7.4.0 to 7.5.3
2026-05-25 15:29:41 +09:00
dependabot[bot]
92cff628c2
chore(deps): bump rpassword from 7.4.0 to 7.5.3
Bumps [rpassword](https://github.com/conradkleinespel/rpassword) from 7.4.0 to 7.5.3.
- [Release notes](https://github.com/conradkleinespel/rpassword/releases)
- [Commits](https://github.com/conradkleinespel/rpassword/compare/v7.4.0...v7.5.3)

---
updated-dependencies:
- dependency-name: rpassword
  dependency-version: 7.5.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:49:03 +00:00
dependabot[bot]
3f3465d74b
chore(deps-dev): bump @tauri-apps/cli in /vrc-get-gui
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 2.10.1 to 2.11.2.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.10.1...@tauri-apps/cli-v2.11.2)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-version: 2.11.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:44:08 +00:00
dependabot[bot]
d1c28f6479
chore(deps): bump the tauri group across 1 directory with 2 updates
Bumps the tauri group with 1 update in the / directory: [tauri](https://github.com/tauri-apps/tauri).


Updates `tauri` from 2.10.3 to 2.11.2
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/tauri-v2.10.3...tauri-v2.11.2)

Updates `tauri-build` from 2.5.6 to 2.6.2
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/tauri-build-v2.5.6...tauri-build-v2.6.2)

---
updated-dependencies:
- dependency-name: tauri
  dependency-version: 2.11.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tauri
- dependency-name: tauri-build
  dependency-version: 2.6.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tauri
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:34:01 +00:00
anatawa12
089427cbfa
Merge pull request #2907 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-1.16.0
chore(deps): bump lucide-react from 1.11.0 to 1.16.0 in /vrc-get-gui
2026-05-25 14:31:21 +09:00
anatawa12
375894c6c3
Merge pull request #2894 from vrc-get/dependabot/cargo/tauri-plugin-single-instance-2.4.2
chore(deps): bump tauri-plugin-single-instance from 2.4.1 to 2.4.2
2026-05-25 14:29:15 +09:00
anatawa12
eed54886b8
Merge pull request #2895 from vrc-get/dependabot/cargo/serde_with-3.20.0
chore(deps): bump serde_with from 3.18.0 to 3.20.0
2026-05-25 14:28:31 +09:00
anatawa12
11c1b7048b
Merge pull request #2914 from vrc-get/dependabot/cargo/openssl-0.10.80
chore(deps): bump openssl from 0.10.77 to 0.10.80
2026-05-25 14:28:08 +09:00
anatawa12
b613f834ea
Merge pull request #2925 from vrc-get/dependabot/cargo/rustls-webpki-0.103.13
chore(deps): bump rustls-webpki from 0.103.12 to 0.103.13
2026-05-25 14:27:17 +09:00
anatawa12
5d9c6ce802
Merge pull request #2870 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-8cf3a4f383
chore(deps-dev): bump @tailwindcss/vite from 4.2.4 to 4.3.0 in /vrc-get-gui in the tailwindcss group across 1 directory
2026-05-25 14:26:24 +09:00
anatawa12
f15e489515
Merge pull request #2868 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-50f7a7efee
chore(deps): bump the i18next group across 1 directory with 2 updates
2026-05-25 14:25:56 +09:00
anatawa12
687904918d
Merge pull request #2891 from vrc-get/dependabot/cargo/clap-4445c6f202
chore(deps): bump clap_complete from 4.6.2 to 4.6.5 in the clap group across 1 directory
2026-05-25 14:25:30 +09:00
anatawa12
c5d38a1f6e
Merge pull request #2892 from vrc-get/dependabot/cargo/tauri-plugin-dialog-2.7.1
chore(deps): bump tauri-plugin-dialog from 2.7.0 to 2.7.1
2026-05-25 14:24:45 +09:00
anatawa12
55635bbe9c
Merge pull request #2893 from vrc-get/dependabot/cargo/nix-0.31.3
chore(deps): bump nix from 0.31.2 to 0.31.3
2026-05-25 14:24:27 +09:00
anatawa12
ca30b889f1
Merge pull request #2906 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-6.0.2
chore(deps-dev): bump @vitejs/plugin-react from 6.0.1 to 6.0.2 in /vrc-get-gui
2026-05-25 14:23:55 +09:00
anatawa12
0a17c9a1cd
Merge pull request #2897 from vrc-get/dependabot/cargo/tokio-1.52.3
chore(deps): bump tokio from 1.52.1 to 1.52.3
2026-05-25 14:22:42 +09:00
anatawa12
50aba0530e
Merge pull request #2899 from vrc-get/dependabot/cargo/plist-1.9.0
chore(deps): bump plist from 1.8.0 to 1.9.0
2026-05-25 14:22:14 +09:00
anatawa12
33be110c7a
Merge pull request #2900 from vrc-get/dependabot/cargo/async-compression-0.4.42
chore(deps): bump async-compression from 0.4.41 to 0.4.42
2026-05-25 14:21:54 +09:00
anatawa12
2aad318387
Merge pull request #2871 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/biomejs/biome-2.4.15
chore(deps-dev): bump @biomejs/biome from 2.4.13 to 2.4.15 in /vrc-get-gui
2026-05-25 14:20:26 +09:00
anatawa12
43ca6755ff
Merge pull request #2872 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwind-merge-3.6.0
chore(deps): bump tailwind-merge from 3.5.0 to 3.6.0 in /vrc-get-gui
2026-05-25 14:19:38 +09:00
anatawa12
92bc6cf38e
Merge pull request #2901 from vrc-get/dependabot/cargo/reqwest-0.13.3
chore(deps): bump reqwest from 0.13.2 to 0.13.3
2026-05-25 14:18:28 +09:00
anatawa12
8d293e5e69
Merge pull request #2902 from vrc-get/dependabot/cargo/open-5.3.5
chore(deps): bump open from 5.3.3 to 5.3.5
2026-05-25 14:16:31 +09:00
anatawa12
1e9a100d9c
Merge pull request #2903 from vrc-get/dependabot/cargo/sysinfo-0.39.2
chore(deps): bump sysinfo from 0.38.4 to 0.39.2
2026-05-25 14:14:20 +09:00
anatawa12
8624950ca5
Merge pull request #2904 from vrc-get/dependabot/cargo/trash-5.2.6
chore(deps): bump trash from 5.2.5 to 5.2.6
2026-05-25 14:12:10 +09:00
anatawa12
57c9a54d37
Merge pull request #2918 from vrc-get/dependabot/cargo/either-1.16.0
chore(deps): bump either from 1.15.0 to 1.16.0
2026-05-25 14:10:28 +09:00
dependabot[bot]
6470169cf1
chore(deps): bump object from 0.39.0 to 0.39.1
Bumps [object](https://github.com/gimli-rs/object) from 0.39.0 to 0.39.1.
- [Changelog](https://github.com/gimli-rs/object/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/v0.39.0...v0.39.1)

---
updated-dependencies:
- dependency-name: object
  dependency-version: 0.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:09:18 +00:00
dependabot[bot]
795699baf0
chore(deps): bump lucide-react from 1.11.0 to 1.16.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.11.0 to 1.16.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.16.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:07:04 +00:00
dependabot[bot]
7fbf8c60d1
chore(deps-dev): bump @vitejs/plugin-react in /vrc-get-gui
Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.2/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.0.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:02:33 +00:00
anatawa12
a5c5d6e128
Merge pull request #2921 from vrc-get/dependabot/cargo/serde_json-1.0.150
chore(deps): bump serde_json from 1.0.149 to 1.0.150
2026-05-25 14:01:58 +09:00
dependabot[bot]
a3aa50256f
chore(deps): bump the i18next group across 1 directory with 2 updates
Bumps the i18next group with 2 updates in the /vrc-get-gui directory: [i18next](https://github.com/i18next/i18next) and [react-i18next](https://github.com/i18next/react-i18next).


Updates `i18next` from 26.0.8 to 26.2.0
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.0.8...v26.2.0)

Updates `react-i18next` from 17.0.4 to 17.0.8
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.4...v17.0.8)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 26.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: i18next
- dependency-name: react-i18next
  dependency-version: 17.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:01:37 +00:00
dependabot[bot]
498eedc1d6
chore(deps): bump tailwind-merge from 3.5.0 to 3.6.0 in /vrc-get-gui
Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.5.0...v3.6.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 05:01:32 +00:00
anatawa12
c863bc4461
Merge pull request #2919 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.100.14
chore(deps): bump @tanstack/react-query from 5.100.5 to 5.100.14 in /vrc-get-gui
2026-05-25 13:58:58 +09:00
anatawa12
8fd964fa83
Merge pull request #2920 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-388b784d7d
chore(deps): bump the react group across 1 directory with 3 updates
2026-05-25 13:57:55 +09:00
dependabot[bot]
c7012c5e81
chore(deps): bump rustls-webpki from 0.103.12 to 0.103.13
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.12 to 0.103.13.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.12...v/0.103.13)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 04:57:40 +00:00
anatawa12
cf6c82adbd
Merge pull request #2922 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-8.0.14
chore(deps-dev): bump vite from 8.0.10 to 8.0.14 in /vrc-get-gui
2026-05-25 13:56:38 +09:00
夜嵐蝶Alma
e0931be79a chore(l10n): [zh_hant] update locale 2026-05-25 11:08:29 +08:00
dependabot[bot]
e0dce679d7
chore(deps): bump serde_json from 1.0.149 to 1.0.150
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.149 to 1.0.150.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.149...v1.0.150)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.150
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:32:04 +00:00
dependabot[bot]
f9ca613378
chore(deps-dev): bump vite from 8.0.10 to 8.0.14 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.10 to 8.0.14.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.14/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:32:04 +00:00
dependabot[bot]
0fa0c7ca00
chore(deps): bump clap_complete in the clap group across 1 directory
Bumps the clap group with 1 update in the / directory: [clap_complete](https://github.com/clap-rs/clap).


Updates `clap_complete` from 4.6.2 to 4.6.5
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.2...clap_complete-v4.6.5)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.6.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: clap
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:31:57 +00:00
dependabot[bot]
9c1465868e
chore(deps): bump the react group across 1 directory with 3 updates
Bumps the react group with 3 updates in the /vrc-get-gui directory: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.5 to 19.2.6
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react)

Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.5 to 19.2.6
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react-dom)

Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:31:52 +00:00
dependabot[bot]
874492f3fc
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.5 to 5.100.14.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.14/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:31:50 +00:00
dependabot[bot]
8588a7276c
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group with 1 update in the /vrc-get-gui directory: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.2.4 to 4.3.0
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.0/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:31:47 +00:00
dependabot[bot]
0a5b9c38eb
chore(deps): bump either from 1.15.0 to 1.16.0
Bumps [either](https://github.com/rayon-rs/either) from 1.15.0 to 1.16.0.
- [Commits](https://github.com/rayon-rs/either/compare/1.15.0...1.16.0)

---
updated-dependencies:
- dependency-name: either
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 02:31:40 +00:00
anatawa12
17a28fa609
Merge pull request #2916 from vrc-get/workaround-world-sdk
chore: workaround VRCDefaultWorldScene generation issue
2026-05-24 02:09:01 +09:00
anatawa12
099883a33d
docs(changelog): Added workaround for VRCDefaultWorldScene generation issue in SDK 3.10.2 or later 2026-05-24 01:49:55 +09:00
anatawa12
5cb60c4002
chore: workaround VRCDefaultWorldScene generation issue
workarounds https://feedback.vrchat.com/sdk-bug-reports/p/3102-3103-vrcscenetemplateinitializer-does-not-create-sample-scene-if-udon-prepr
2026-05-24 01:45:01 +09:00
anatawa12
cdb1b8294d
Merge pull request #2915 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2026-05-23 23:43:50 +09:00
Sayamame-beans
0de963736f chore(l10n): [ja] update locale 2026-05-23 02:33:25 +09:00
anatawa12
0026f5029c
Merge pull request #2731 from lonelyicer/feat/show-hidden-packages
feat: show hidden packages
2026-05-22 18:26:18 +09:00
dependabot[bot]
987357354e
chore(deps): bump openssl from 0.10.77 to 0.10.80
Bumps [openssl](https://github.com/rust-openssl/rust-openssl) from 0.10.77 to 0.10.80.
- [Release notes](https://github.com/rust-openssl/rust-openssl/releases)
- [Commits](https://github.com/rust-openssl/rust-openssl/compare/openssl-v0.10.77...openssl-v0.10.80)

---
updated-dependencies:
- dependency-name: openssl
  dependency-version: 0.10.80
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 06:41:01 +00:00
anatawa12
f13add3409
Merge pull request #2888 from vrc-get/fix-updater
Fix updater.exe
2026-05-22 15:39:37 +09:00
anatawa12
2d7fefb34c
fix: shlwapi.dll is not part of static link checker 2026-05-22 09:19:44 +09:00
RingLo_
e625630856
feat: show list of sources that we should enable 2026-05-20 05:01:37 +08:00
anatawa12
4943a671e0
fix: compile error 2026-05-19 00:31:16 +09:00
dependabot[bot]
6e63cdba25
chore(deps): bump trash from 5.2.5 to 5.2.6
Bumps [trash](https://github.com/ArturKovacs/trash) from 5.2.5 to 5.2.6.
- [Release notes](https://github.com/ArturKovacs/trash/releases)
- [Changelog](https://github.com/Byron/trash-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ArturKovacs/trash/compare/v5.2.5...v5.2.6)

---
updated-dependencies:
- dependency-name: trash
  dependency-version: 5.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:26:43 +00:00
dependabot[bot]
e04d1ee919
chore(deps): bump sysinfo from 0.38.4 to 0.39.2
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.38.4 to 0.39.2.
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.38.4...v0.39.2)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-version: 0.39.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:26:23 +00:00
dependabot[bot]
a4992e3973
chore(deps): bump open from 5.3.3 to 5.3.5
Bumps [open](https://github.com/Byron/open-rs) from 5.3.3 to 5.3.5.
- [Release notes](https://github.com/Byron/open-rs/releases)
- [Changelog](https://github.com/Byron/open-rs/blob/main/changelog.md)
- [Commits](https://github.com/Byron/open-rs/compare/v5.3.3...v5.3.5)

---
updated-dependencies:
- dependency-name: open
  dependency-version: 5.3.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:26:01 +00:00
dependabot[bot]
185b7aa8b7
chore(deps): bump reqwest from 0.13.2 to 0.13.3
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.13.2 to 0.13.3.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.13.2...v0.13.3)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.13.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:25:48 +00:00
dependabot[bot]
24ae2b33de
chore(deps): bump async-compression from 0.4.41 to 0.4.42
Bumps [async-compression](https://github.com/Nullus157/async-compression) from 0.4.41 to 0.4.42.
- [Release notes](https://github.com/Nullus157/async-compression/releases)
- [Commits](https://github.com/Nullus157/async-compression/compare/async-compression-v0.4.41...async-compression-v0.4.42)

---
updated-dependencies:
- dependency-name: async-compression
  dependency-version: 0.4.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:25:32 +00:00
dependabot[bot]
1b928b150b
chore(deps): bump plist from 1.8.0 to 1.9.0
Bumps [plist](https://github.com/ebarnard/rust-plist) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/ebarnard/rust-plist/releases)
- [Changelog](https://github.com/ebarnard/rust-plist/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ebarnard/rust-plist/compare/v1.8.0...v1.9.0)

---
updated-dependencies:
- dependency-name: plist
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:25:19 +00:00
dependabot[bot]
2d859d993e
chore(deps): bump tokio from 1.52.1 to 1.52.3
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.1 to 1.52.3.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.52.1...tokio-1.52.3)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.52.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:24:49 +00:00
dependabot[bot]
4018f718a7
chore(deps): bump serde_with from 3.18.0 to 3.20.0
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.18.0 to 3.20.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.18.0...v3.20.0)

---
updated-dependencies:
- dependency-name: serde_with
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:24:21 +00:00
dependabot[bot]
de73063b98
chore(deps): bump tauri-plugin-single-instance from 2.4.1 to 2.4.2
Bumps [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/fs-v2.4.1...fs-v2.4.2)

---
updated-dependencies:
- dependency-name: tauri-plugin-single-instance
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:24:08 +00:00
dependabot[bot]
d6ea9b3079
chore(deps): bump nix from 0.31.2 to 0.31.3
Bumps [nix](https://github.com/nix-rust/nix) from 0.31.2 to 0.31.3.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.31.2...v0.31.3)

---
updated-dependencies:
- dependency-name: nix
  dependency-version: 0.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:23:53 +00:00
dependabot[bot]
eaf09ecb6a
chore(deps): bump tauri-plugin-dialog from 2.7.0 to 2.7.1
Bumps [tauri-plugin-dialog](https://github.com/tauri-apps/plugins-workspace) from 2.7.0 to 2.7.1.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/log-v2.7.0...log-v2.7.1)

---
updated-dependencies:
- dependency-name: tauri-plugin-dialog
  dependency-version: 2.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 12:23:37 +00:00
RingLo_
d74c7b16b8
chore: use visibleSources in package list and add tooltip 2026-05-18 12:04:38 +08:00
RingLo_
6c46983cae
Merge branch 'master' into feat/show-hidden-packages 2026-05-18 11:40:16 +08:00
anatawa12
36b76933fc
docs(changelog-gui): add pr number to changelog entry 2026-05-17 03:11:52 +09:00
anatawa12
ad7efa259e
Merge pull request #2887 from fivezett/fix-toastify-dark-theme
fix(style): keep react-toastify toasts in sync with dark mode
2026-05-17 03:08:19 +09:00
anatawa12
97042ebc6a
chore: add windows manifest resource to disable Installer detection technology 2026-05-17 03:03:34 +09:00
anatawa12
e135092745
fix: installer file should always have .exe extension 2026-05-17 02:58:19 +09:00
fivezett
5607daf7b5 fix(style): keep react-toastify toasts in sync with dark mode
react-toastify 11.1.0 changed its CSS injection to append the <style>
to the end of <head> on mount, so its `:root` variable defaults
started overriding ours by source order, and toasts stopped following
the dark theme.

Declaring the `--toastify-*` overrides on `body` instead of `:root`
makes toasts inherit them regardless of stylesheet order, since
react-toastify only declares these variables on `:root`.
2026-05-17 01:51:08 +09:00
github-actions[bot]
2861fcaa68 gui v1.1.6-beta.1 2026-05-15 15:15:00 +00:00
anatawa12
8a71e426d6
Merge pull request #2882 from vrc-get/additional-headers-for-future-extension
feat: include version number and os in the header for future extension
2026-05-15 22:25:20 +09:00
anatawa12
cd242e389b
docs(changelog): add pr number to changelog 2026-05-15 22:14:36 +09:00
anatawa12
95dc46666b
feat: include version number and os in the header for future extension 2026-05-15 22:12:32 +09:00
anatawa12
f0c4de7d78
Merge pull request #2881 from vrc-get/updater-windows-fixes
windows updater fixes
2026-05-15 22:06:32 +09:00
anatawa12
e9a994a932
Merge pull request #2880 from fivezett/createProject1RowLoading
style: align creating project dialog spinner and label on one row
2026-05-15 19:28:46 +09:00
anatawa12
803fbf3395
fix: non-windows platform build failure 2026-05-15 19:22:05 +09:00
anatawa12
20d24b496b
docs(changelog): add pr number to changelog entry 2026-05-15 19:21:52 +09:00
anatawa12
a1ff52fed4
fix: updater json does not include args 2026-05-15 19:18:56 +09:00
anatawa12
4a99cfe4c9
Merge branch 'master' into createProject1RowLoading 2026-05-15 17:31:17 +09:00
fivezett
8b13244b74 style: align creating project dialog spinner and label on one row 2026-05-15 17:24:50 +09:00
anatawa12
875a989d52
fix: failure from ShellExecuteW is not handled 2026-05-15 15:19:05 +09:00
anatawa12
973c91c9c0
fix: close file before launching installer 2026-05-15 15:16:45 +09:00
anatawa12
3d2dd2e058
Merge pull request #2875 from vrc-get/setup-exe-in-zip
fix: setup.exe.zip is unexpectedly unavailable
2026-05-15 03:50:00 +09:00
anatawa12
16d8a787ec
Merge pull request #2876 from vrc-get/debug-only-updater-override
feat: debug-only updater overrides
2026-05-15 03:49:46 +09:00
anatawa12
4ccc7d7bc8
feat: debug-only updater overrides 2026-05-14 14:58:29 +09:00
anatawa12
8c8315f57d
fix: setup.exe.zip is unexpectedly unavailable 2026-05-14 14:47:04 +09:00
anatawa12
4cac964713
Merge pull request #2867 from vrc-get/copy-parallelism-limit
fix: too many open files when copying project
2026-05-14 00:54:16 +09:00
anatawa12
fb32bd97cd
docs(changelog-gui): Too many open files when copying project 2026-05-14 00:33:41 +09:00
anatawa12
1a70d2db82
Merge pull request #2851 from vrc-get/datailed-error-message
chore: much detailed error message
2026-05-14 00:32:27 +09:00
dependabot[bot]
cacb9a5e9a
chore(deps-dev): bump @biomejs/biome in /vrc-get-gui
Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.4.13 to 2.4.15.
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.15/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 09:56:18 +00:00
anatawa12
4700bfa2c0
fix: too many open files when copying project 2026-05-08 20:41:53 +09:00
anatawa12
223be38368
Merge pull request #2850 from vrc-get/unity-hub
fix: Unity from editors-v2.json may not be recognized
2026-05-02 14:54:02 +09:00
anatawa12
523ede22ea
docs(changelog): New Unity Hub loading method fixes 2026-05-02 14:47:58 +09:00
anatawa12
38a7649fbd
Merge pull request #2852 from vrc-get/copilot/fix-typo-in-documentation
Fix typo in SHA256 hash mismatch error message
2026-05-02 03:09:38 +09:00
anatawa12
d61b46ded8
fix: incorrect configuration dir for unity hub on linux 2026-05-02 00:54:33 +09:00
copilot-swe-agent[bot]
4756f6c115
fix: fix typo in SHA256 hash error message (his -> This)
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/bea04e30-e11e-4933-9ea9-2b563af74d47

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-05-01 02:19:14 +00:00
anatawa12
e14806c72c
chore: much detailed error message 2026-05-01 09:56:02 +09:00
anatawa12
8324a4ec04
fix: Unity from editors-v2.json may not be recognized 2026-05-01 09:29:07 +09:00
anatawa12
a9f2a9713f
Merge pull request #2849 from vrc-get/enforce-zip-hash
chore!: package hash check is now enforced when installing package
2026-04-30 19:22:18 +09:00
anatawa12
40cd4487d5
Merge pull request #2848 from vrc-get/improve-error-messages
fix: fix "[object Object]" appearing as an error message
2026-04-30 10:33:55 +09:00
anatawa12
56a2139df6
docs(changelog): Package hash checks are now enforced when installing packages 2026-04-30 10:00:48 +09:00
anatawa12
175008956c
style: biome format fix 2026-04-30 09:58:55 +09:00
anatawa12
00a928e58e
chore!: package hash check is now enforced when installing package 2026-04-30 09:56:17 +09:00
anatawa12
7037a758bc
docs(changelog): Uninformative [object Object] appearing as an error message 2026-04-30 09:39:27 +09:00
anatawa12
f457ffcc69
fix: fix "[object Object]" appearing as an error message
We show JSON instead
2026-04-30 09:24:48 +09:00
anatawa12
9291853c19
Merge pull request #2847 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2026-04-30 01:08:27 +09:00
JustBuddy
0e6d011ee5
chore(l10n): [de_DE] update locale 2026-04-29 17:34:45 +02:00
anatawa12
be5c9aa765
Merge pull request #2846 from vrc-get/copilot/fix-template-export-extension-issue
Fix missing file extensions in save dialog default names
2026-04-29 23:11:06 +09:00
anatawa12
b090c440ac
Merge pull request #2845 from vrc-get/backslash-in-path
feat: replace backslashes with slash extracting zip on unix
2026-04-29 22:54:29 +09:00
copilot-swe-agent[bot]
3c51a2de31
docs: add changelog entry for PR #2846
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/379a1c4c-6953-48f9-86f7-1c0134e08af9

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-29 13:51:37 +00:00
copilot-swe-agent[bot]
04fa1f8244
fix: append file extension to default file names in save dialogs
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/379a1c4c-6953-48f9-86f7-1c0134e08af9

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-29 13:51:17 +00:00
anatawa12
35b26d9322
docs(changelog): Backslashes in path in zip file are now treated as path separator on unix 2026-04-29 22:47:45 +09:00
copilot-swe-agent[bot]
478c25b03a
Initial plan 2026-04-29 13:47:25 +00:00
anatawa12
20e5836985
feat: replace backslashes with slash extracting zip on unix 2026-04-29 22:32:17 +09:00
anatawa12
ce8de700a7
Merge pull request #2844 from vrc-get/improved-package-installation
Improved robustness for package installation errors
2026-04-29 22:02:31 +09:00
anatawa12
3076713ea6
docs(changelog): Improved robustness for package installation errors 2026-04-29 17:38:09 +09:00
anatawa12
75974f4ad9
test: add test for error while downloading package 2026-04-29 17:30:04 +09:00
anatawa12
4eadf2bdcd
feat: installing vpm package is more atomic now 2026-04-29 17:23:01 +09:00
anatawa12
c43ed4a828
Merge pull request #2842 from vrc-get/improve-error-for-bad-version-range
Improve error for bad version range
2026-04-29 00:59:31 +09:00
anatawa12
f675d29173
docs(changelog): Unclear error message for invalid version name or version range 2026-04-28 19:51:56 +09:00
anatawa12
c45e4e399f
Merge pull request #2843 from vrc-get/copilot/add-retry-logic-for-hdiutil
fix: retry hdiutil create with exponential backoff on failure
2026-04-28 19:30:55 +09:00
anatawa12
f5f7ac794e
docs: remove changelog entry 2026-04-28 16:36:40 +09:00
copilot-swe-agent[bot]
88fd6a06a7
fix: extract retry constants and move changelog entry to bottom of Fixed section
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/a90adc5d-6de2-4b6f-aed9-fe753c4a2232

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-28 06:31:13 +00:00
copilot-swe-agent[bot]
c3020225f3
fix: retry hdiutil create with exponential backoff on failure
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/a90adc5d-6de2-4b6f-aed9-fe753c4a2232

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-28 06:27:32 +00:00
anatawa12
d2f9a39b67
chore: improve error message for other string value with format 2026-04-28 15:02:18 +09:00
anatawa12
776bd4b4e8
chore: improve error message for invalid version or invalid version range 2026-04-28 14:50:24 +09:00
anatawa12
4ae3507f96
Merge pull request #2833 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-034c7544f4
chore(deps): bump the tanstack-router group across 1 directory with 2 updates
2026-04-27 22:31:07 +09:00
dependabot[bot]
7b105639f9
chore(deps): bump the tanstack-router group across 1 directory with 2 updates
Bumps the tanstack-router group with 2 updates in the /vrc-get-gui directory: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.168.23 to 1.168.25
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.168.25/packages/react-router)

Updates `@tanstack/router-plugin` from 1.167.22 to 1.167.28
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-plugin/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-plugin@1.167.28/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.168.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.167.28
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 13:24:30 +00:00
anatawa12
fc177add7c
Merge pull request #2834 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-a1e0053666
chore(deps-dev): bump @tailwindcss/vite from 4.2.2 to 4.2.4 in /vrc-get-gui in the tailwindcss group
2026-04-27 22:22:52 +09:00
anatawa12
4063021e2a
Merge pull request #2837 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.100.5
chore(deps): bump @tanstack/react-query from 5.99.2 to 5.100.5 in /vrc-get-gui
2026-04-27 22:21:07 +09:00
anatawa12
463b4c5df7
Merge pull request #2838 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/biomejs/biome-2.4.13
chore(deps-dev): bump @biomejs/biome from 2.4.12 to 2.4.13 in /vrc-get-gui
2026-04-27 19:55:48 +09:00
anatawa12
bbbbd19926
Merge pull request #2836 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-1.11.0
chore(deps): bump lucide-react from 1.8.0 to 1.11.0 in /vrc-get-gui
2026-04-27 19:53:14 +09:00
anatawa12
3d7b2b8e22
Merge pull request #2835 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-498519f72f
chore(deps): bump i18next from 26.0.6 to 26.0.8 in /vrc-get-gui in the i18next group
2026-04-27 19:52:58 +09:00
anatawa12
b24bcf1c38
Merge pull request #2839 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-8.0.10
chore(deps-dev): bump vite from 8.0.9 to 8.0.10 in /vrc-get-gui
2026-04-27 17:36:32 +09:00
dependabot[bot]
19bde29c6b
chore(deps-dev): bump vite from 8.0.9 to 8.0.10 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.9 to 8.0.10.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.10/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:20:37 +00:00
dependabot[bot]
f18bc14777
chore(deps-dev): bump @biomejs/biome in /vrc-get-gui
Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.4.12 to 2.4.13.
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.13/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:20:24 +00:00
dependabot[bot]
07a5eb27b3
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.99.2 to 5.100.5.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.5/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:20:16 +00:00
dependabot[bot]
6a5c60a79e
chore(deps): bump lucide-react from 1.8.0 to 1.11.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.8.0 to 1.11.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.11.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:20:07 +00:00
dependabot[bot]
2b04760299
chore(deps): bump i18next in /vrc-get-gui in the i18next group
Bumps the i18next group in /vrc-get-gui with 1 update: [i18next](https://github.com/i18next/i18next).


Updates `i18next` from 26.0.6 to 26.0.8
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.0.6...v26.0.8)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 26.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:19:59 +00:00
dependabot[bot]
1845e8083d
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.2.2 to 4.2.4
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.4/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 08:19:53 +00:00
anatawa12
faf432fd61
Merge pull request #2831 from CirnoV/locale/ko-KR
chore(l10n): [ko] update locale
2026-04-26 15:18:07 +09:00
CirnoV
45942829df chore(l10n): [ko] update locale 2026-04-26 12:55:04 +09:00
anatawa12
b64e09dc55
Merge pull request #2830 from lonelyicer/patch-1
chore(l10N): [zh_Hans] update for #2827
2026-04-26 03:21:41 +09:00
RingLo_
dee9a2fb78
chore(l10N): [zh_Hans] update for #2827 2026-04-26 02:02:12 +08:00
anatawa12
508d62b3e6
Merge pull request #2827 from vrc-get/copilot/fix-backup-warning-roaming-folder
Fix AppData warning missing for Roaming and LocalLow backup/project paths
2026-04-24 19:58:53 +09:00
anatawa12
f119b203f9
Merge pull request #2828 from vrc-get/linux-deps
fix: missing libc dependencies information for deb/rpm distribution
2026-04-24 14:27:20 +09:00
anatawa12
a64cb3af9b
chore: change i18n key to "settings⚠️in-app-data" 2026-04-23 23:13:37 +09:00
anatawa12
70f7f8c78e
chore: remove localappdata from global settings 2026-04-23 23:12:57 +09:00
anatawa12
b64058cab0
docs(changelog): Missing glibc and libgcc_s dependency notation in .deb / .rpm distributon 2026-04-23 23:05:56 +09:00
anatawa12
3e8d5cc9d9
fix: missing dependencies information for deb/rpm distribution 2026-04-23 23:03:57 +09:00
anatawa12
2809d94996
fix: bad tar archive was generated 2026-04-23 23:03:57 +09:00
copilot-swe-agent[bot]
dccd85be31
fix: show AppData warning for Roaming/LocalLow folders, not just Local
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/ed7b1ab9-d3da-4a4d-abd5-d130fe90ee2b

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-23 00:58:06 +00:00
copilot-swe-agent[bot]
726ca0c068
Initial plan 2026-04-23 00:52:20 +00:00
anatawa12
5887c5631c
Merge pull request #2826 from vrc-get/fix-timeout
chore(gui): extend connect/read timeout to 1 min
2026-04-23 09:35:32 +09:00
anatawa12
a57de0d7f1
docs(changelog): Extended some timeouts to 1 minutes 2026-04-23 09:28:55 +09:00
anatawa12
9bc7d26fff
Merge branch 'master' into fix-timeout 2026-04-23 09:26:07 +09:00
anatawa12
20c20a49b0
Merge pull request #2824 from vrc-get/copilot/remove-added-packages-suggestion
Template Editor: Exclude already-added packages from package name suggestions
2026-04-23 09:25:34 +09:00
anatawa12
6a4648ddbb
chore(gui): extend connect/read timeout to 1 min 2026-04-23 09:15:52 +09:00
anatawa12
4783761910
Merge pull request #2825 from vrc-get/copilot-instruction
dev: update copilot instruction
2026-04-23 00:32:58 +09:00
anatawa12
1fdb97d04a
dev: update copilot instruction 2026-04-23 00:26:15 +09:00
anatawa12
b3430d926b
fix: useReorderableList().value always return new array 2026-04-23 00:22:31 +09:00
copilot-swe-agent[bot]
4edda28776
Address review feedback: move changelog to Changed, use useMemo for addedPackageNames set
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/3de0d89e-1f21-4b64-8f9e-4869f497f742

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-22 15:13:27 +00:00
anatawa12
b8903da155
Merge pull request #2823 from vrc-get/copilot/update-bulkupdate-card-padding
style: compact BulkUpdateCard in compact mode
2026-04-23 00:12:46 +09:00
copilot-swe-agent[bot]
38ac981d22
Filter already-added packages from template editor suggestions
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/df9f3421-a51d-44c1-b81b-bab02f9f7d30

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-22 14:56:30 +00:00
anatawa12
9fa4d25637
Merge pull request #2822 from vrc-get/dependency-locked
fix: panic when resolving projects where dependency packages depend on newer versions of locked packages
2026-04-22 23:53:48 +09:00
copilot-swe-agent[bot]
490190606c
Initial plan 2026-04-22 14:52:35 +00:00
copilot-swe-agent[bot]
fd6eb27b09
style: reduce BulkUpdateCard padding in compact mode
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/5dc5a118-7d9b-410d-a016-e4a711a76895

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-22 14:51:41 +00:00
copilot-swe-agent[bot]
5fd5109f3b
Initial plan 2026-04-22 14:50:33 +00:00
anatawa12
496a1c91c1
docs(changelog): Panic when resolving projects where dependency packages depend on newer versions of locked packages 2026-04-22 23:39:39 +09:00
anatawa12
42f1835360
test: panic when resolving projects where dependency packages depend on newer versions of locked packages 2026-04-22 23:38:21 +09:00
anatawa12
4b89aec67a
fix: panic when resolving projects where dependency packages depend on newer versions of locked packages 2026-04-22 23:38:21 +09:00
anatawa12
422b4b1b8d
chore: add more information to panic 2026-04-22 23:38:21 +09:00
anatawa12
98cde02985
Merge pull request #2811 from vrc-get/wording-updates
chore(i18n): breaking changes => may affect compatibility
2026-04-22 20:48:47 +09:00
anatawa12
b6cb3f51f7
chore(i18n): Apply suggestions from code review
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2026-04-22 20:25:36 +09:00
anatawa12
50bc72d662
Merge pull request #2821 from vrc-get/fix-unitypackage-import
fixes for unitypackage import feature
2026-04-22 19:55:58 +09:00
anatawa12
9655865ba9
docs(changelog): Unabled to import some untypackages 2026-04-22 19:49:42 +09:00
anatawa12
827042c827
fix: some unitypackages won't work well
some unitypackages may have `\n00.meta` at the end of their pathname and ALCOM saves it as-is so fs error on Windows or bad file name on unix platforms ocurs.
Unity removes any text after last `\n` so we implement this to fix the problem
2026-04-22 19:46:34 +09:00
anatawa12
e265b8fcdb
Merge pull request #2820 from Misaka-L/patch-3
chore(l10n): [zh_hans] update locale
2026-04-22 19:39:23 +09:00
Misaka_L
3394e59e49
chore(l10n): [zh_hans] update locale 2026-04-22 15:04:16 +08:00
anatawa12
dccfbc2867
Merge pull request #2819 from vrc-get/copilot-instructions
dev: copilot instructions
2026-04-22 14:54:47 +09:00
anatawa12
1cbc34bb30
chore: add warning log when non-assets unitypackage found 2026-04-22 14:52:38 +09:00
anatawa12
61832aa154
Merge pull request #2818 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2026-04-22 14:50:06 +09:00
anatawa12
b696c7cc31
dev: copilot instructions 2026-04-22 14:48:26 +09:00
Sayamame-beans
847d76cb5c chore(l10n): [ja] update locale 2026-04-22 14:17:15 +09:00
anatawa12
a29a9bc9e2
Merge pull request #2817 from vrc-get/error-message-for-noexec
chore(en): Improve error message for noexec filesystem issues
2026-04-22 12:18:58 +09:00
anatawa12
72103a67a5
chore(en): Improve error message for noexec filesystem 2026-04-22 11:44:52 +09:00
anatawa12
7f1be1818e
chore(en): Improve error message for noexec filesystem issues 2026-04-22 11:27:27 +09:00
anatawa12
6a7d60d89c
Merge pull request #2814 from vrc-get/copilot/add-warning-for-noexec-mounts-again
Warn when opening Unity projects on noexec mount points (Linux/macOS)
2026-04-22 09:41:35 +09:00
anatawa12
7df14594d1
docs(changelog): ALCOM now refuses launching project if project is on noexec mount points 2026-04-22 09:35:44 +09:00
anatawa12
001a6a330e
style: rustfmt 2026-04-22 09:34:27 +09:00
anatawa12
9ff7c8e1e7
chore: remove locales other than ja/en 2026-04-22 09:34:15 +09:00
anatawa12
17f315a44a
chore: handle error in one place 2026-04-22 09:31:12 +09:00
copilot-swe-agent[bot]
d2cdc980e2
Fix unlocalized error message in open-unity.tsx
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/cd0fa504-9fd3-4469-a12c-7509f26a5b52

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-21 17:34:57 +00:00
copilot-swe-agent[bot]
9c9e8b8f9c
Add noexec filesystem check when opening Unity projects on Linux/macOS
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/cd0fa504-9fd3-4469-a12c-7509f26a5b52

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-21 17:31:27 +00:00
copilot-swe-agent[bot]
b7dc45c2c3
Initial plan 2026-04-21 17:12:31 +00:00
anatawa12
ebb17f10e3
Merge pull request #2812 from vrc-get/copilot/fix-xdg-data-home-fallback
Fix XDG_DATA_HOME fallback for FLATPAK_USER_INSTALLATION path
2026-04-22 01:44:52 +09:00
anatawa12
da26f04917
docs(changelog): ALCOM cannot detect per-user flatpak installation of unity hub 2026-04-22 00:07:59 +09:00
copilot-swe-agent[bot]
930c79d649
Fix FLATPAK_USER_INSTALLATION: use $HOME/.local/share as fallback for XDG_DATA_HOME
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/b5341545-defb-4ca1-81b4-9cdd2d37d523

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-21 14:47:23 +00:00
copilot-swe-agent[bot]
f19b9d0084
Initial plan 2026-04-21 14:45:54 +00:00
anatawa12
c771de380a
chore(i18n): Apply suggestions from code review
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2026-04-21 23:01:54 +09:00
anatawa12
bb26d062de
chore(i18n): breaking changes => may affect compatibility 2026-04-21 20:27:29 +09:00
anatawa12
41b1514f66
Merge pull request #2809 from vrc-get/linux-build-improvement
feat: add --bundle buildroot for package manager distributions
2026-04-21 09:22:13 +09:00
anatawa12
09aebbcb8b
fix: compile error on windows 2026-04-21 01:20:28 +09:00
anatawa12
df8174341e
fix: setting permission is not valid on non-unix 2026-04-21 00:42:56 +09:00
anatawa12
93012d8bd1
Merge pull request #2808 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-toastify-11.1.0
chore(deps): bump react-toastify from 11.0.5 to 11.1.0 in /vrc-get-gui
2026-04-21 00:38:33 +09:00
anatawa12
9a739177bc
Merge pull request #2803 from vrc-get/copilot/red-untag-button
Make "Clear Selection" button warning (yellow) in package management
2026-04-21 00:34:49 +09:00
anatawa12
34ef49a629
feat: add --bundle buildroot for package manager distributions 2026-04-21 00:04:55 +09:00
anatawa12
647799180a
Merge pull request #2801 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-ba25c5e4f4
chore(deps): bump i18next from 26.0.5 to 26.0.6 in /vrc-get-gui in the i18next group across 1 directory
2026-04-20 19:22:26 +09:00
anatawa12
e00162180f
Merge pull request #2805 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-999b6383b5
chore(deps): bump @tanstack/react-router from 1.168.22 to 1.168.23 in /vrc-get-gui in the tanstack-router group
2026-04-20 19:21:39 +09:00
anatawa12
1567b9dec2
Merge pull request #2806 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-8.0.9
chore(deps-dev): bump vite from 8.0.8 to 8.0.9 in /vrc-get-gui
2026-04-20 19:20:11 +09:00
anatawa12
2e5962422a
Merge pull request #2807 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.99.2
chore(deps): bump @tanstack/react-query from 5.99.0 to 5.99.2 in /vrc-get-gui
2026-04-20 19:15:52 +09:00
anatawa12
fb292da426
Merge pull request #2802 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_hans] update locale
2026-04-20 18:10:53 +09:00
anatawa12
98b8df7bb2
Merge pull request #2804 from vrc-get/dependabot/github_actions/samypr100/setup-dev-drive-4
chore(deps): bump samypr100/setup-dev-drive from 3 to 4
2026-04-20 18:05:48 +09:00
dependabot[bot]
a5355dd287
chore(deps): bump react-toastify from 11.0.5 to 11.1.0 in /vrc-get-gui
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 11.0.5 to 11.1.0.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v11.0.5...v11.1.0)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-version: 11.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:03:28 +00:00
dependabot[bot]
8915177909
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.99.0 to 5.99.2.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.2/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.99.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:03:21 +00:00
dependabot[bot]
ad232e3506
chore(deps-dev): bump vite from 8.0.8 to 8.0.9 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.8 to 8.0.9.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:03:13 +00:00
dependabot[bot]
a8aed0a011
chore(deps): bump @tanstack/react-router
Bumps the tanstack-router group in /vrc-get-gui with 1 update: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router).


Updates `@tanstack/react-router` from 1.168.22 to 1.168.23
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.168.23/packages/react-router)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.168.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:03:01 +00:00
dependabot[bot]
79b7776e40
chore(deps): bump samypr100/setup-dev-drive from 3 to 4
Bumps [samypr100/setup-dev-drive](https://github.com/samypr100/setup-dev-drive) from 3 to 4.
- [Release notes](https://github.com/samypr100/setup-dev-drive/releases)
- [Changelog](https://github.com/samypr100/setup-dev-drive/blob/main/CHANGELOG.md)
- [Commits](https://github.com/samypr100/setup-dev-drive/compare/v3...v4)

---
updated-dependencies:
- dependency-name: samypr100/setup-dev-drive
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:02:44 +00:00
copilot-swe-agent[bot]
d96ae23a60
Change Clear Selection button variant from destructive to warning
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/6da5a28d-c1db-48e8-9ada-1c98934996ed

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-20 05:56:39 +00:00
copilot-swe-agent[bot]
c44bbe2584
Make the Clear Selection button red (destructive) in package management
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/aaf4dce4-b804-43e8-85b8-bd1d7dcf30e1

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-20 05:29:17 +00:00
copilot-swe-agent[bot]
fa05c2bc30
Initial plan 2026-04-20 05:26:41 +00:00
RingLo_
9b26a5fdb3
chore(l10n): [zh_hans] update locale 2026-04-20 11:49:08 +08:00
RingLo_
c8b0cf89c8
chore: fix type 2026-04-20 11:31:22 +08:00
RingLo_
911c0a5e51
feat: always show installed packages
also hide hidden sources
2026-04-20 11:22:51 +08:00
RingLo_
8773f3d3e6
Merge branch 'master' into feat/show-hidden-packages 2026-04-20 11:01:27 +08:00
dependabot[bot]
974a195a3c
chore(deps): bump i18next
Bumps the i18next group with 1 update in the /vrc-get-gui directory: [i18next](https://github.com/i18next/i18next).


Updates `i18next` from 26.0.5 to 26.0.6
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.0.5...v26.0.6)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 26.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-18 20:20:32 +00:00
anatawa12
9b63d1919f
Merge pull request #2799 from vrc-get/bump-deps
Bump deps
2026-04-19 04:36:48 +09:00
anatawa12
04b65168b8
fix: bad import 2026-04-19 03:51:51 +09:00
anatawa12
f2ce2829eb
chore(deps): migrate to vite 8 2026-04-19 01:00:00 +09:00
anatawa12
d3d127efb8
chore(deps): upgrade dependencies (including breaking changes) 2026-04-19 01:00:00 +09:00
anatawa12
98a9bf6938
Merge pull request #2798 from CirnoV/locale/ko-KR
chore(l10n): [ko] update locale
2026-04-19 00:57:29 +09:00
CirnoV
56f586974e chore(l10n): [ko] update locale 2026-04-18 22:54:32 +09:00
anatawa12
2f6e52032e
Merge pull request #2797 from vrc-get/update_locale_en_ja
chore(l10n): [en/ja] update locale
2026-04-18 22:25:12 +09:00
anatawa12
09d60c804f
chore(ja): Apply suggestions from code review
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2026-04-18 21:58:39 +09:00
Sayamame-beans
8c210c248f chore(l10n): [ja] update locale 2026-04-18 21:43:27 +09:00
Sayamame-beans
3f6ba916c0 chore(l10n): [en] chore message 2026-04-18 21:43:01 +09:00
anatawa12
3213f9288a
Merge pull request #2635 from vrc-get/feat-2633
feat: allow reselecting unitypackage path on Template Editor
2026-04-18 21:11:52 +09:00
anatawa12
2411f7482b
Merge branch 'master' into feat-2633 2026-04-18 20:59:19 +09:00
anatawa12
7ac0b41800
Merge pull request #2795 from vrc-get/copilot/add-notice-for-prerelease-packages
Add stability warning and confirmation dialog for "Show Prerelease Packages"
2026-04-18 19:09:59 +09:00
anatawa12
03f1140d71
chore(i18n): Apply suggestions from code review
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2026-04-18 18:43:01 +09:00
Sayamame-beans
3e58fc6d1a
Merge branch 'master' into feat-2633 2026-04-18 18:04:11 +09:00
anatawa12
fe0f711d62
docs(changelog): We added dialog on enabling "Show Prerelease Packages" 2026-04-18 01:21:27 +09:00
anatawa12
dbd5fbbca8
chore: change button level to warning 2026-04-18 01:21:10 +09:00
copilot-swe-agent[bot]
da12ba3cad
Use direct bug language, rename Enable to Show, make button destructive
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/7a06eb84-7c48-4632-945b-21d68b087265

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-17 16:14:13 +00:00
copilot-swe-agent[bot]
1178e151ef
Add error handling to prerelease dialog promise
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/5ef365b7-5da5-4179-ad50-ce8ec4a88ba8

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-17 07:50:12 +00:00
copilot-swe-agent[bot]
0cbbaacd12
Add warning and confirmation dialog for prerelease packages option
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/5ef365b7-5da5-4179-ad50-ce8ec4a88ba8

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-17 07:48:50 +00:00
copilot-swe-agent[bot]
bd7f84196b
Initial plan 2026-04-17 07:44:30 +00:00
anatawa12
8babbb0e04
Merge pull request #2746 from siloneco/perf/parallel-zip-compression
perf: improve backup project performance by parallelizing zip compression
2026-04-17 14:49:57 +09:00
anatawa12
63d40420c9
Merge branch 'master' into perf/parallel-zip-compression 2026-04-17 09:54:14 +09:00
anatawa12
6afa1e07b5
Merge pull request #2794 from vrc-get/ci-bundles
ci: ci builds of ALCOM doesn't include any bundles
2026-04-17 09:53:27 +09:00
anatawa12
6f5359c7a3
ci: ci builds of ALCOM doesn't include any bundles 2026-04-17 09:26:36 +09:00
anatawa12
60f20b2b22
Merge remote-tracking branch 'origin/master' into perf/parallel-zip-compression 2026-04-17 09:19:59 +09:00
anatawa12
25e19296d0
Merge pull request #2792 from Misaka-L/patch-2
chore(l10n): [zh_hans] update locale
2026-04-17 08:59:00 +09:00
Misaka_L
fd66eee442
chore(l10n): [zh_hans] update locale 2026-04-17 02:54:28 +08:00
anatawa12
f2809b0d19
Merge pull request #2786 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-1.8.0
chore(deps): bump lucide-react from 1.7.0 to 1.8.0 in /vrc-get-gui
2026-04-17 01:17:56 +09:00
anatawa12
91d8b73fad
Merge pull request #2763 from vrc-get/dependabot/cargo/tauri-plugin-dialog-2.7.0
chore(deps): bump tauri-plugin-dialog from 2.6.0 to 2.7.0
2026-04-17 00:39:52 +09:00
anatawa12
5ac23e1ca3
Merge pull request #2780 from vrc-get/dependabot/github_actions/actions/github-script-9
chore(deps): bump actions/github-script from 8 to 9
2026-04-17 00:36:41 +09:00
anatawa12
0961bcad1d
Merge pull request #2791 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2026-04-17 00:35:53 +09:00
anatawa12
4c8ccea7c3
Merge pull request #2790 from vrc-get/lint
lint: fix new lints
2026-04-17 00:32:45 +09:00
JustBuddy
68ff4c3205
chore(l10n): [de_DE] update locale 2026-04-16 17:06:58 +02:00
anatawa12
b30df5621a
lint: fix new lints 2026-04-16 23:46:33 +09:00
anatawa12
02759caf1c
Merge pull request #2759 from vrc-get/inno-setup
Changes how alcom is installed and how distributed
2026-04-16 23:32:00 +09:00
anatawa12
9df7055ee1
docs: update how to build and add changelog entries 2026-04-16 23:24:27 +09:00
anatawa12
60636fb8c3
build: fix we cannot call npm on windows 2026-04-16 22:33:16 +09:00
anatawa12
1b7263e35e
ci: dev drive is too small 2026-04-16 20:27:00 +09:00
anatawa12
5937594af1
ci: try t to workaround actions/checkout behavior 2026-04-16 20:21:38 +09:00
anatawa12
4da483032e
ci: try dev drive 2026-04-16 19:50:43 +09:00
anatawa12
93cb37ff77
build: merge building web part into xtask 2026-04-16 19:38:53 +09:00
anatawa12
0ae87b7b49
chore: completely remove bundle related options from tauri.toml 2026-04-16 14:11:21 +09:00
anatawa12
dfe9e97b00
fix: macos build part not working 2026-04-16 01:09:56 +09:00
anatawa12
51b7f9ccee
fix: --updater-instruction-message detection not working 2026-04-16 01:04:12 +09:00
anatawa12
44a5f5eadf
fix: configuration for macos overrides everything 2026-04-16 00:58:14 +09:00
anatawa12
a89bcbfa16
chore: remove esigner 2026-04-16 00:44:48 +09:00
anatawa12
3436711467
ci: split building appimage and deb/rpm 2026-04-16 00:41:52 +09:00
anatawa12
dd160c5199
chore: change how do we customize build 2026-04-16 00:11:24 +09:00
anatawa12
4e31d23b0c
chore: change how do we pass customized message 2026-04-15 23:55:39 +09:00
anatawa12
6fb9f631a1
fix: manually specify to use native-tls 2026-04-15 12:55:57 +09:00
anatawa12
fca8805043
chore: use xtask to sign updater artifact 2026-04-15 09:48:18 +09:00
anatawa12
9d533a2051
chore: try to improve ci speed 2026-04-15 09:36:09 +09:00
anatawa12
f7a0099b53
Merge remote-tracking branch 'origin/master' into inno-setup 2026-04-14 22:10:38 +09:00
anatawa12
d98339017f
fix: artifact name conflict 2026-04-14 19:36:15 +09:00
anatawa12
6bc973dd66
ci: configure signing windows build 2026-04-14 13:38:27 +09:00
anatawa12
7fca14868f
ci: split setup exe and updater exe
the updater won't be signed and will only be used by legacy updater
2026-04-14 09:27:03 +09:00
anatawa12
a9378ac341
ci: fix sign-alcom does not support base64 with newlines 2026-04-13 19:38:13 +09:00
anatawa12
09bca3b5fd
ci: fix file name mismatch and improve 2026-04-13 19:34:05 +09:00
dependabot[bot]
001880b49d
chore(deps): bump lucide-react from 1.7.0 to 1.8.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.8.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 07:54:04 +00:00
dependabot[bot]
bcb7131054
chore(deps): bump actions/github-script from 8 to 9
Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v8...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 07:53:15 +00:00
anatawa12
b5d93a3bab
ci: use --release for publishing gui 2026-04-13 15:11:27 +09:00
anatawa12
6c411dd7a2
fix(rpm): version name cannot include '-' 2026-04-13 14:56:07 +09:00
anatawa12
3e3b2155cd
lint: remove unused imports 2026-04-13 14:55:47 +09:00
anatawa12
95d8af8559
fix(rpm): file permission instead of mode 2026-04-13 14:43:23 +09:00
anatawa12
358ca77692
fix: downloading appimagetool 2026-04-13 09:56:07 +09:00
anatawa12
8ec535701c
fix: downloading appimagetool not working 2026-04-13 09:39:26 +09:00
anatawa12
07472f8622
chore(xtask): remove unused deps 2026-04-13 09:37:05 +09:00
anatawa12
0680a57066
chore(xtask): allow adding features in build-alcom and use them 2026-04-13 09:35:36 +09:00
anatawa12
88fa1c2b3d
ci: build release binary 2026-04-13 09:27:56 +09:00
anatawa12
b38f2393fd
ci: syntax error for windows build 2026-04-13 09:25:18 +09:00
anatawa12
b00beaae70
fix: icon path is not correct 2026-04-13 09:24:10 +09:00
anatawa12
d349e16411
fix: build directory is not correct for dev build 2026-04-13 09:15:32 +09:00
anatawa12
13e53bfba0
ci: run ci for non-master prs 2026-04-13 08:05:07 +09:00
anatawa12
281669e6c5
refactor: migrate build-alcom-installer to bundle-alcom 2026-04-13 01:47:33 +09:00
anatawa12
30d49406e4
refactor: remove reading tauri.toml 2026-04-13 01:03:36 +09:00
anatawa12
3fce6e45ea
feat: background for macos installer .dmg 2026-04-13 00:03:39 +09:00
anatawa12
2c8eeec473
fix: build command always passes target so it always cross build 2026-04-12 17:10:36 +09:00
anatawa12
ee527cf95c
chore: move dmg specific part to dmg.rs and update several parameters 2026-04-12 17:08:45 +09:00
copilot-swe-agent[bot]
02fe4e64ac
fix: use consistent number formatting in doc comments
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/fc1392fa-eac7-4db6-8c73-c1472e79ceb8

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-11 15:28:49 +00:00
copilot-swe-agent[bot]
99d526e0cf
feat: add util::ds_store module and write .DS_Store in DMG staging dir
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/fc1392fa-eac7-4db6-8c73-c1472e79ceb8

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-11 15:25:17 +00:00
anatawa12
16b48bb1db
refactor: completely refactors cargo xtask buindle-alcom 2026-04-11 23:53:10 +09:00
anatawa12
3e3ffabf7e
Merge pull request #2766 from vrc-get/dependabot/cargo/arc-swap-1.9.1
chore(deps): bump arc-swap from 1.9.0 to 1.9.1
2026-04-11 02:12:59 +09:00
anatawa12
fcbcf3a504
Merge pull request #2768 from vrc-get/dependabot/cargo/yoke-0.8.2
chore(deps): bump yoke from 0.8.1 to 0.8.2
2026-04-11 02:12:32 +09:00
anatawa12
370dc0f3d8
Merge pull request #2770 from vrc-get/dependabot/cargo/indexmap-2.13.1
chore(deps): bump indexmap from 2.13.0 to 2.13.1
2026-04-11 02:09:14 +09:00
copilot-swe-agent[bot]
8619197e92
feat: add --bundles option to bundle-alcom and new sign-alcom command
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/f6a86c70-4f97-4203-974e-45f12fd853b7

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 12:39:20 +00:00
copilot-swe-agent[bot]
205a60aafc
fix: use explicit format args in panic! macros
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/00d0aa2a-4624-4df5-b43f-73046f95d809

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 04:59:19 +00:00
copilot-swe-agent[bot]
5c0d2789d8
feat: add build-alcom command, fix arch detection, use fs_extra for dir copy
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/00d0aa2a-4624-4df5-b43f-73046f95d809

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 04:55:31 +00:00
copilot-swe-agent[bot]
3790d10f96
refactor: use plist, rpm, and ar crates instead of manual parsing and external commands
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/fe7a550a-71c9-4b7a-b324-4ec4906eacc0

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 01:11:43 +00:00
anatawa12
72e927edd3
chore: hardcode where icons are put 2026-04-10 09:36:22 +09:00
anatawa12
506b389e40
lint: clippy 2026-04-10 09:35:48 +09:00
anatawa12
22a40d64cd
style: rustfmt 2026-04-10 09:33:59 +09:00
copilot-swe-agent[bot]
4586b5f5b3
fix: address code review issues (plist parser underflow, unwrap on parent)
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/38030954-a556-4574-a386-7e075f2f66b1

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 00:13:25 +00:00
copilot-swe-agent[bot]
9a46a49c36
feat: add bundle-alcom xtask command and migrate CI from tauri-action
Agent-Logs-Url: https://github.com/vrc-get/vrc-get/sessions/38030954-a556-4574-a386-7e075f2f66b1

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2026-04-10 00:09:33 +00:00
copilot-swe-agent[bot]
bf53c697a3
Initial plan 2026-04-09 23:54:38 +00:00
anatawa12
96fd94e2a1
feat: allow user to install different directory than previous installation 2026-04-09 09:34:57 +09:00
anatawa12
bbda611499
feat: new updater system 2026-04-09 09:34:57 +09:00
dependabot[bot]
083d320cf1
chore(deps): bump indexmap from 2.13.0 to 2.13.1
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.13.0 to 2.13.1.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.13.0...2.13.1)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-version: 2.13.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-06 07:44:46 +00:00
dependabot[bot]
d79cd05fe6
chore(deps): bump yoke from 0.8.1 to 0.8.2
Bumps [yoke](https://github.com/unicode-org/icu4x) from 0.8.1 to 0.8.2.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: yoke
  dependency-version: 0.8.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-06 07:44:27 +00:00
dependabot[bot]
1411a7405f
chore(deps): bump arc-swap from 1.9.0 to 1.9.1
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.9.0 to 1.9.1.
- [Changelog](https://github.com/vorner/arc-swap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/arc-swap/compare/v1.9.0...v1.9.1)

---
updated-dependencies:
- dependency-name: arc-swap
  dependency-version: 1.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-06 07:44:15 +00:00
dependabot[bot]
7639563544
chore(deps): bump tauri-plugin-dialog from 2.6.0 to 2.7.0
Bumps [tauri-plugin-dialog](https://github.com/tauri-apps/plugins-workspace) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/log-v2.6.0...log-v2.7.0)

---
updated-dependencies:
- dependency-name: tauri-plugin-dialog
  dependency-version: 2.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-06 07:43:34 +00:00
siloneco
4c8f24da3f fix: move unreachable code to correct position 2026-04-05 15:37:19 +09:00
anatawa12
1ae45e3b47
Merge remote-tracking branch 'origin/master' into inno-setup 2026-04-05 15:13:37 +09:00
siloneco
19ef64ef32 docs: add changelog for this performance improvements 2026-04-05 14:21:47 +09:00
siloneco
650d0bf8ff fix: increase file descriptor limit on app init 2026-04-05 14:10:12 +09:00
siloneco
7ba6106a63 refactor: fix clippy warnings 2026-04-05 14:10:12 +09:00
siloneco
52234179f3 chore: remove hard-coded memory usage soft limit 2026-04-05 14:10:12 +09:00
siloneco
976fd95517 fix: unable to create zip file with Compression::Stored 2026-04-05 14:10:12 +09:00
siloneco
ee2a73994e chore: delete unnecessary lock file 2026-04-05 14:10:12 +09:00
siloneco
439a639d15 fix: change default compression level to zip-fast 2026-04-05 14:10:12 +09:00
siloneco
9c57629211 feat: show finalizing message until all merge tasks are complete 2026-04-05 13:10:24 +09:00
anatawa12
fa7dc36c83
ci: fix mising env vars
Add environment variables for Tauri signing in Windows installer build step.
2026-04-05 03:10:55 +09:00
anatawa12
06cdd8d5cc
Merge pull request #2751 from vrc-get/dependabot/cargo/object-0.39.0
chore(deps): bump object from 0.38.1 to 0.39.0
2026-04-05 02:50:08 +09:00
anatawa12
d28d8dcdc6
Merge pull request #2752 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-1.7.0
chore(deps): bump lucide-react from 0.577.0 to 1.7.0 in /vrc-get-gui
2026-04-05 02:16:59 +09:00
anatawa12
23d087e6cc
Merge pull request #2753 from vrc-get/dependabot/cargo/env_logger-0.11.10
chore(deps): bump env_logger from 0.11.9 to 0.11.10
2026-04-05 02:13:51 +09:00
anatawa12
a657a77633
Merge pull request #2756 from vrc-get/dependabot/cargo/sha2-0.11.0
chore(deps): bump sha2 from 0.10.9 to 0.11.0
2026-04-05 02:12:03 +09:00
anatawa12
6e0b28ee2c
fix: calling windows installer sign script does not work as expected 2026-04-05 02:10:06 +09:00
anatawa12
727f963923
ci: update publish action to migrate installer 2026-04-05 01:13:46 +09:00
anatawa12
7229201ad3
fix: nsis settings is not correctly removed 2026-04-05 00:52:33 +09:00
anatawa12
042dfa9f69
fix: missing system libraries in current dependencies (typo fix) 2026-04-05 00:01:55 +09:00
anatawa12
bdd312152c
fix: missing system libraries in current dependencies 2026-04-04 23:54:45 +09:00
anatawa12
00051c6e53
chore: remove nsis installer from build bundle 2026-04-04 23:38:14 +09:00
siloneco
4f6cee33c2 feat: implement soft limit for memory usage during compression 2026-04-04 22:17:26 +09:00
anatawa12
02fcb00bb3
chore: change wrapper exe name to alcom-setup.exe 2026-04-04 17:04:09 +09:00
anatawa12
0e62041ab4
ci: exclude windows-installer-wrapper from clippy lint 2026-04-04 16:55:45 +09:00
anatawa12
06fe826379
ci: change how to handle .exe 2026-04-04 16:53:57 +09:00
anatawa12
57ae7c7df8
fix: skip rlibs 2026-04-04 01:06:45 +09:00
anatawa12
40b3edc0e2
ci: fix xtask is not called correctly 2026-04-04 00:59:33 +09:00
anatawa12
7f1d7f36e8
feat: add xbuild task to build alcom installer 2026-04-04 00:42:18 +09:00
anatawa12
dd645a5b5b
feat: add installer wrapper for nsis compatibility 2026-04-04 00:40:37 +09:00
anatawa12
da81afe549
fix: removal of build-updater-json in not committed 2026-04-01 09:29:40 +09:00
anatawa12
e29fafa6d2
feat: add inno setup based installer 2026-04-01 01:47:35 +09:00
siloneco
571a6e71fb feat: use async_zip crate instead of zip and rayon crate 2026-03-31 03:31:15 +09:00
dependabot[bot]
27835f9ce0
chore(deps): bump sha2 from 0.10.9 to 0.11.0
Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.9 to 0.11.0.
- [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0)

---
updated-dependencies:
- dependency-name: sha2
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 07:46:52 +00:00
dependabot[bot]
b0a1f5b6d9
chore(deps): bump env_logger from 0.11.9 to 0.11.10
Bumps [env_logger](https://github.com/rust-cli/env_logger) from 0.11.9 to 0.11.10.
- [Release notes](https://github.com/rust-cli/env_logger/releases)
- [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-cli/env_logger/compare/v0.11.9...v0.11.10)

---
updated-dependencies:
- dependency-name: env_logger
  dependency-version: 0.11.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 07:46:29 +00:00
dependabot[bot]
a9474fae66
chore(deps): bump lucide-react from 0.577.0 to 1.7.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.577.0 to 1.7.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.7.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 07:46:22 +00:00
dependabot[bot]
301ae004b6
chore(deps): bump object from 0.38.1 to 0.39.0
Bumps [object](https://github.com/gimli-rs/object) from 0.38.1 to 0.39.0.
- [Changelog](https://github.com/gimli-rs/object/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.38.1...v0.39.0)

---
updated-dependencies:
- dependency-name: object
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 07:46:17 +00:00
siloneco
d32d7f854a perf: avoid loading the entire file at once 2026-03-30 02:24:57 +09:00
siloneco
7eda8cedde refactor: use FileSystemTree instead of original struct 2026-03-30 02:19:38 +09:00
siloneco
0f63d3bc4e perf: remove unnecessary semaphore 2026-03-30 02:10:43 +09:00
siloneco
9cb256d4ec fix: keep duplicate code to ensure maintainability 2026-03-30 02:09:51 +09:00
anatawa12
2a87edcaa3
chore: migrate build-updater-json to xtask 2026-03-29 23:50:09 +09:00
siloneco
e543d5329f perf: parallelize backups to speed up execution 2026-03-29 19:50:06 +09:00
anatawa12
0943241884
chore: migrate build-check-static-link to xtask 2026-03-28 20:37:10 +09:00
anatawa12
d0a90046b7
Merge pull request #2737 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-845dc2c481
chore(deps): bump the tanstack-router group in /vrc-get-gui with 3 updates
2026-03-24 23:18:44 +09:00
anatawa12
9922e0da2c
Merge pull request #2732 from vrc-get/dependabot/cargo/tar-0.4.45
chore(deps): bump tar from 0.4.44 to 0.4.45
2026-03-24 22:39:04 +09:00
dependabot[bot]
2cc9c692d7
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.166.3 to 1.168.2
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.168.2/packages/react-router)

Updates `@tanstack/router-devtools` from 1.166.3 to 1.166.11
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-devtools/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-devtools@1.166.11/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.166.3 to 1.167.3
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-plugin/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-plugin@1.167.3/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.168.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.166.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.167.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 13:04:25 +00:00
anatawa12
93609bb42d
Merge pull request #2734 from vrc-get/dependabot/cargo/rustls-webpki-0.103.10
chore(deps): bump rustls-webpki from 0.103.9 to 0.103.10
2026-03-24 21:57:42 +09:00
anatawa12
22f50c3e05
Merge pull request #2736 from vrc-get/dependabot/cargo/arc-swap-1.9.0
chore(deps): bump arc-swap from 1.8.2 to 1.9.0
2026-03-24 21:57:12 +09:00
anatawa12
f0854c9a78
Merge pull request #2738 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-c5f55f59c8
chore(deps-dev): bump @tailwindcss/vite from 4.2.1 to 4.2.2 in /vrc-get-gui in the tailwindcss group
2026-03-24 21:54:40 +09:00
anatawa12
82d4babc13
Merge pull request #2739 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.95.0
chore(deps): bump @tanstack/react-query from 5.90.21 to 5.95.0 in /vrc-get-gui
2026-03-24 21:54:29 +09:00
dependabot[bot]
8b7df92640
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.21 to 5.95.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.95.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.95.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 07:44:43 +00:00
dependabot[bot]
ed26112f7e
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.2.1 to 4.2.2
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 07:44:30 +00:00
dependabot[bot]
40a1f6fef7
chore(deps): bump arc-swap from 1.8.2 to 1.9.0
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.8.2 to 1.9.0.
- [Changelog](https://github.com/vorner/arc-swap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/arc-swap/compare/v1.8.2...v1.9.0)

---
updated-dependencies:
- dependency-name: arc-swap
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 07:43:33 +00:00
dependabot[bot]
7b259d47f4
chore(deps): bump rustls-webpki from 0.103.9 to 0.103.10
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.9 to 0.103.10.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.9...v/0.103.10)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.10
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-21 09:41:45 +00:00
dependabot[bot]
faf15cd44a
chore(deps): bump tar from 0.4.44 to 0.4.45
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.44 to 0.4.45.
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.44...0.4.45)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 0.4.45
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 18:09:45 +00:00
RingLo_
40d0786b19
chore: clean code 2026-03-20 08:02:05 +08:00
RingLo_
7fdd1192e1
docs(changelog): update for #2731 2026-03-20 07:54:27 +08:00
RingLo_
d09244291f
feat: show hide packages 2026-03-20 07:47:40 +08:00
anatawa12
eae4745ce6
Merge pull request #2712 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-8d241097f2
chore(deps): bump the tanstack-router group in /vrc-get-gui with 3 updates
2026-03-16 20:42:23 +09:00
anatawa12
9554373332
Merge pull request #2719 from vrc-get/dependabot/github_actions/auguwu/clippy-action-1.5.0
chore(deps): bump auguwu/clippy-action from 1.4.0 to 1.5.0
2026-03-16 20:41:50 +09:00
anatawa12
22d757ed52
Merge pull request #2723 from vrc-get/dependabot/cargo/anstyle-1.0.14
chore(deps): bump anstyle from 1.0.13 to 1.0.14
2026-03-16 20:41:32 +09:00
anatawa12
9fbce2a575
Merge pull request #2724 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-swc-4.3.0
chore(deps-dev): bump @vitejs/plugin-react-swc from 4.2.3 to 4.3.0 in /vrc-get-gui
2026-03-16 20:40:47 +09:00
dependabot[bot]
9257f1fed5
chore(deps): bump anstyle from 1.0.13 to 1.0.14
Bumps [anstyle](https://github.com/rust-cli/anstyle) from 1.0.13 to 1.0.14.
- [Commits](https://github.com/rust-cli/anstyle/compare/v1.0.13...v1.0.14)

---
updated-dependencies:
- dependency-name: anstyle
  dependency-version: 1.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 11:33:56 +00:00
anatawa12
b52b04a81e
Merge pull request #2721 from vrc-get/dependabot/github_actions/actions/create-github-app-token-3
chore(deps): bump actions/create-github-app-token from 2 to 3
2026-03-16 20:30:43 +09:00
anatawa12
3d4757f267
Merge pull request #2718 from vrc-get/dependabot/cargo/clap-712b10af58
chore(deps): bump the clap group with 2 updates
2026-03-16 20:30:07 +09:00
anatawa12
9dd4a13596
Merge pull request #2711 from vrc-get/dependabot/cargo/uuid-1.22.0
chore(deps): bump uuid from 1.21.0 to 1.22.0
2026-03-16 20:29:34 +09:00
anatawa12
2e2ee22add
Merge pull request #2715 from vrc-get/dependabot/cargo/quinn-proto-0.11.14
chore(deps): bump quinn-proto from 0.11.13 to 0.11.14
2026-03-16 20:28:33 +09:00
anatawa12
f852312336
Merge pull request #2720 from vrc-get/dependabot/cargo/serde_with-3.18.0
chore(deps): bump serde_with from 3.17.0 to 3.18.0
2026-03-16 17:29:57 +09:00
dependabot[bot]
0d82e0e5ec
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react-swc) from 4.2.3 to 4.3.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/v4.3.0/packages/plugin-react-swc)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 07:44:13 +00:00
dependabot[bot]
d5434497da
chore(deps): bump actions/create-github-app-token from 2 to 3
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2 to 3.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](https://github.com/actions/create-github-app-token/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 07:43:46 +00:00
dependabot[bot]
78d6ff1a3c
chore(deps): bump serde_with from 3.17.0 to 3.18.0
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.17.0 to 3.18.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.17.0...v3.18.0)

---
updated-dependencies:
- dependency-name: serde_with
  dependency-version: 3.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 07:43:43 +00:00
dependabot[bot]
205c9e66d7
chore(deps): bump auguwu/clippy-action from 1.4.0 to 1.5.0
Bumps [auguwu/clippy-action](https://github.com/auguwu/clippy-action) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/auguwu/clippy-action/releases)
- [Commits](https://github.com/auguwu/clippy-action/compare/1.4.0...1.5.0)

---
updated-dependencies:
- dependency-name: auguwu/clippy-action
  dependency-version: 1.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 07:43:36 +00:00
dependabot[bot]
e5eee65f66
chore(deps): bump the clap group with 2 updates
Bumps the clap group with 2 updates: [clap](https://github.com/clap-rs/clap) and [clap_complete](https://github.com/clap-rs/clap).


Updates `clap` from 4.5.60 to 4.6.0
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.60...clap_complete-v4.6.0)

Updates `clap_complete` from 4.5.66 to 4.6.0
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.66...clap_complete-v4.6.0)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: clap
- dependency-name: clap_complete
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: clap
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 07:43:30 +00:00
dependabot[bot]
714b1b3b8a
chore(deps): bump quinn-proto from 0.11.13 to 0.11.14
Bumps [quinn-proto](https://github.com/quinn-rs/quinn) from 0.11.13 to 0.11.14.
- [Release notes](https://github.com/quinn-rs/quinn/releases)
- [Commits](https://github.com/quinn-rs/quinn/compare/quinn-proto-0.11.13...quinn-proto-0.11.14)

---
updated-dependencies:
- dependency-name: quinn-proto
  dependency-version: 0.11.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 00:21:13 +00:00
dependabot[bot]
fa0a5e4e37
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.163.3 to 1.166.3
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.166.3/packages/react-router)

Updates `@tanstack/router-devtools` from 1.163.3 to 1.166.3
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.166.3/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.164.0 to 1.166.3
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.166.3/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.166.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.166.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.166.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 07:44:40 +00:00
dependabot[bot]
9a430541df
chore(deps): bump uuid from 1.21.0 to 1.22.0
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.21.0 to 1.22.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.21.0...v1.22.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 07:44:11 +00:00
anatawa12
20489da9d6
Merge pull request #2710 from vrc-get/json-with-zeros
chore: treat file filled with \0 as empty file while processing file
2026-03-08 00:57:00 +09:00
anatawa12
2f1755cb03
docs(changelog): File filled with '\0' or whitespace will be treated as empty file 2026-03-08 00:14:40 +09:00
anatawa12
a3b44389ee
chore: treat file filled with \0 as empty file while processing file 2026-03-07 23:44:31 +09:00
anatawa12
ca4cacbfff
Merge pull request #2709 from vrc-get/fix-null
chore: allow null on optional field, treat as omit (default)
2026-03-07 23:18:01 +09:00
anatawa12
fc0b40a27f
docs(changelog): null as vpmDependencies value is not allowed 2026-03-07 23:05:53 +09:00
anatawa12
063639e389
chore: allow null on optional field, treat as omit (default) 2026-03-07 23:02:17 +09:00
anatawa12
b0aafd0411
Merge pull request #2687 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-7.3.1
chore(deps-dev): bump vite from 6.4.1 to 7.3.1 in /vrc-get-gui
2026-03-05 02:09:37 +09:00
anatawa12
87f784b613
Merge pull request #2708 from vrc-get/wmi-0.18
chore(deps): update wmi to 0.18
2026-03-05 01:52:36 +09:00
anatawa12
9f0ba1abfb
chore(deps): update wmi to 0.18 2026-03-05 01:41:31 +09:00
anatawa12
a4a86b0ab1
Merge pull request #2705 from vrc-get/dependabot/cargo/object-0.38.1
chore(deps): bump object from 0.37.3 to 0.38.1
2026-03-05 01:33:27 +09:00
anatawa12
a69ecb0cf1
Merge pull request #2569 from vrc-get/dependabot/github_actions/actions/setup-node-6
chore(deps): bump actions/setup-node from 4 to 6
2026-03-05 01:30:16 +09:00
dependabot[bot]
bb44461bab
chore(deps-dev): bump vite from 6.4.1 to 7.3.1 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.4.1 to 7.3.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 16:25:38 +00:00
anatawa12
4332876651
Merge pull request #2557 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-47b46a4058
chore(deps): bump the react group across 1 directory with 4 updates
2026-03-05 01:23:19 +09:00
anatawa12
50e38cebbe
Merge pull request #2682 from vrc-get/dependabot/cargo/bytes-1.11.1
chore(deps): bump bytes from 1.10.1 to 1.11.1
2026-03-05 01:21:36 +09:00
dependabot[bot]
88a0b77e5d
chore(deps): bump actions/setup-node from 4 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 16:21:15 +00:00
anatawa12
fe7d9d776c
Merge pull request #2686 from vrc-get/dependabot/github_actions/actions/download-artifact-8
chore(deps): bump actions/download-artifact from 5 to 8
2026-03-05 01:20:29 +09:00
anatawa12
9e3171b56c
Merge pull request #2688 from vrc-get/dependabot/github_actions/actions/upload-artifact-7
chore(deps): bump actions/upload-artifact from 4 to 7
2026-03-05 01:20:15 +09:00
anatawa12
df7d7e0f56
Merge pull request #2511 from vrc-get/dependabot/github_actions/actions/github-script-8
chore(deps): bump actions/github-script from 7 to 8
2026-03-05 01:05:14 +09:00
anatawa12
bfe8041047
Merge pull request #2512 from vrc-get/dependabot/github_actions/actions/labeler-6
chore(deps): bump actions/labeler from 5 to 6
2026-03-05 01:04:46 +09:00
anatawa12
96248ade9d
Merge pull request #2620 from vrc-get/dependabot/github_actions/actions/checkout-6
chore(deps): bump actions/checkout from 5 to 6
2026-03-05 01:03:45 +09:00
dependabot[bot]
c8e8ab51d5
chore(deps): bump the react group across 1 directory with 4 updates
Bumps the react group with 4 updates in the /vrc-get-gui directory: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react), [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).


Updates `react` from 19.1.1 to 19.2.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.0/packages/react)

Updates `@types/react` from 19.1.11 to 19.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.1.1 to 19.2.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.0/packages/react-dom)

Updates `@types/react-dom` from 19.1.7 to 19.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `@types/react` from 19.1.11 to 19.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.7 to 19.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 15:56:18 +00:00
anatawa12
d746140499
Merge pull request #2707 from vrc-get/update-deps
chore: update more deps
2026-03-05 00:54:19 +09:00
anatawa12
ce829ccae4
Merge pull request #2647 from vrc-get/dependabot/github_actions/actions/cache-5
chore(deps): bump actions/cache from 4 to 5
2026-03-05 00:48:07 +09:00
anatawa12
b231c500a3
chore: update more deps 2026-03-05 00:38:33 +09:00
dependabot[bot]
911541bac4
chore(deps): bump actions/download-artifact from 5 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 15:38:25 +00:00
anatawa12
5c2385ea96
Merge pull request #2706 from vrc-get/dependabot/cargo/windows-0.62.2
chore(deps): bump windows from 0.61.3 to 0.62.2
2026-03-05 00:36:08 +09:00
anatawa12
29c076dc9a
Merge pull request #2704 from vrc-get/dependabot/cargo/nix-0.31.2
chore(deps): bump nix from 0.30.1 to 0.31.2
2026-03-05 00:35:25 +09:00
anatawa12
fbe3d42492
Merge pull request #2702 from vrc-get/dependabot/cargo/log-0.4.29
chore(deps): bump log from 0.4.27 to 0.4.29
2026-03-05 00:35:09 +09:00
dependabot[bot]
7d74bcec30
chore(deps): bump windows from 0.61.3 to 0.62.2
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.61.3 to 0.62.2.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

---
updated-dependencies:
- dependency-name: windows
  dependency-version: 0.62.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 15:19:15 +00:00
dependabot[bot]
e8505ace12
chore(deps): bump object from 0.37.3 to 0.38.1
Bumps [object](https://github.com/gimli-rs/object) from 0.37.3 to 0.38.1.
- [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.37.3...0.38.1)

---
updated-dependencies:
- dependency-name: object
  dependency-version: 0.38.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 15:18:52 +00:00
dependabot[bot]
2faca4c5a2
chore(deps): bump nix from 0.30.1 to 0.31.2
Bumps [nix](https://github.com/nix-rust/nix) from 0.30.1 to 0.31.2.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.30.1...v0.31.2)

---
updated-dependencies:
- dependency-name: nix
  dependency-version: 0.31.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 15:17:56 +00:00
anatawa12
5252b0e0e6
Merge pull request #2703 from vrc-get/fix-lint
lint: update to fix lints
2026-03-05 00:14:04 +09:00
anatawa12
8d914e3cf4
lint: update to fix lints 2026-03-05 00:04:55 +09:00
anatawa12
bdc5a8ac36
Merge pull request #2681 from vrc-get/update-deps
chore: update deps
2026-03-04 23:55:13 +09:00
anatawa12
483f8dd0fd
chore: register zlib license 2026-03-04 23:43:35 +09:00
anatawa12
b570f01931
chore: match tauri versions 2026-03-04 22:44:50 +09:00
dependabot[bot]
d5ae35c5c1
chore(deps): bump log from 0.4.27 to 0.4.29
Bumps [log](https://github.com/rust-lang/log) from 0.4.27 to 0.4.29.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.27...0.4.29)

---
updated-dependencies:
- dependency-name: log
  dependency-version: 0.4.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 13:43:54 +00:00
dependabot[bot]
345006328d
chore(deps): bump actions/upload-artifact from 4 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 13:35:50 +00:00
anatawa12
d34a1ff529
Merge pull request #2679 from vrc-get/fix-unitypackage-extract
fix: UnityPackages with files Packages fails to extract
2026-03-04 20:41:55 +09:00
dependabot[bot]
408916325b
chore(deps): bump bytes from 1.10.1 to 1.11.1
Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.10.1 to 1.11.1.
- [Release notes](https://github.com/tokio-rs/bytes/releases)
- [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/bytes/compare/v1.10.1...v1.11.1)

---
updated-dependencies:
- dependency-name: bytes
  dependency-version: 1.11.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 11:33:42 +00:00
anatawa12
072e401d82
Merge branch 'master' into fix-unitypackage-extract 2026-03-04 20:24:46 +09:00
anatawa12
a7dbf1e85e
chore: update deps (cargo) 2026-03-04 20:19:25 +09:00
anatawa12
42031f1716
chore: update deps (npm) 2026-03-04 20:17:06 +09:00
anatawa12
3ad5ccb200
Merge pull request #2677 from vrc-get/use-rsvg-convert
chore: use rsvg-convert for generating booth thumbnail
2026-03-04 20:10:01 +09:00
anatawa12
86e5529b0e
docs(changelog): Fails to import UnityPackages with files in Packages directory 2026-03-04 20:07:14 +09:00
dependabot[bot]
f0440d3c40
chore(deps): bump actions/labeler from 5 to 6
Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 11:05:49 +00:00
anatawa12
4695d60b56
fix: UnityPackages with files Packages fails to extract 2026-03-04 20:05:02 +09:00
dependabot[bot]
f846d2c41f
chore(deps): bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 11:02:28 +00:00
anatawa12
cc55272841
chore: use rsvg-convert for generating booth thumbnail 2026-03-04 19:54:56 +09:00
anatawa12
8c85a9cb13
Merge pull request #2671 from Spokeek/update-dependencies
Update NPM Javascript dependencies
2026-03-04 19:29:09 +09:00
anatawa12
21ed073c99
fix: typecheck for SideBar 2026-03-04 19:17:50 +09:00
Spokeek
1544967281
chores: Fix issues with Tanstack Router
Required since upgrade of the tanstack route generation changes that value automatically
Some routines to provide intellisense aren't working, had to temporary disable
2026-02-13 21:43:56 +01:00
Spokeek
d0d8cdaf19
chores: Run npm upgrade
Updates to latest compatible version for JS libraries
2026-02-13 20:56:44 +01:00
Spokeek
c3291d9993
chores: lock version for tauri packages 2026-02-13 20:34:17 +01:00
Spokeek
1de47356ad
lint: Enable TailwindDirectives for Biome linter 2026-02-13 20:26:09 +01:00
Spokeek
9a6475f001
feat: Using a sharp library to prepare the booth preview picture 2026-02-13 20:23:47 +01:00
Spokeek
7c6ee29928
depency: removal of sharp-cli library 2026-02-13 19:53:15 +01:00
Spokeek
2753ffa3db
chore: removed unused serde deserialize use 2026-02-13 19:52:58 +01:00
Spokeek
2228b08b3a
chore: Apply last default route from TanStack Router 2026-02-13 19:30:39 +01:00
Spokeek
aa9dbb0057
chore: cleanup npm lock 2026-02-13 19:29:14 +01:00
dependabot[bot]
61e2a9a78d
chore(deps-dev): bump typescript from 5.9.2 to 5.9.3 in /vrc-get-gui
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.2 to 5.9.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release-publish.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.2...v5.9.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 5.9.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:55 +01:00
dependabot[bot]
b6ac50cc74
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.85.5 to 5.90.12.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.90.12/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.90.12
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:54 +01:00
dependabot[bot]
377b4ce340
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react-swc) from 4.0.1 to 4.2.2.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react-swc@4.2.2/packages/plugin-react-swc)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:54 +01:00
dependabot[bot]
18fc1fa4bd
chore(deps-dev): bump vite-plugin-json5 in /vrc-get-gui
Bumps [vite-plugin-json5](https://github.com/sneakylenny/vite-plugin-json5) from 1.1.9 to 1.2.0.
- [Release notes](https://github.com/sneakylenny/vite-plugin-json5/releases)
- [Commits](https://github.com/sneakylenny/vite-plugin-json5/compare/v1.1.9...v1.2.0)

---
updated-dependencies:
- dependency-name: vite-plugin-json5
  dependency-version: 1.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:54 +01:00
dependabot[bot]
6e2caedc2d
chore(deps-dev): bump tw-animate-css from 1.3.7 to 1.4.0 in /vrc-get-gui
Bumps [tw-animate-css](https://github.com/Wombosvideo/tw-animate-css) from 1.3.7 to 1.4.0.
- [Release notes](https://github.com/Wombosvideo/tw-animate-css/releases)
- [Commits](https://github.com/Wombosvideo/tw-animate-css/compare/v1.3.7...v1.4.0)

---
updated-dependencies:
- dependency-name: tw-animate-css
  dependency-version: 1.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:54 +01:00
dependabot[bot]
b39242c710
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).

Updates `@tanstack/react-router` from 1.131.27 to 1.131.31
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.131.31/packages/react-router)

Updates `@tanstack/router-devtools` from 1.131.27 to 1.131.31
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.131.31/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.131.27 to 1.131.31
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.131.31/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.131.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.131.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.131.31
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:54 +01:00
dependabot[bot]
30c7fb2c1b
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.1.12 to 4.1.13
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.13/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.1.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
dependabot[bot]
03771c8be3
chore(deps): bump tailwind-merge from 3.3.1 to 3.4.0 in /vrc-get-gui
Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.3.1...v3.4.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
dependabot[bot]
b332d12e0b
chore(deps): bump the radix-ui group in /vrc-get-gui with 4 updates
Bumps the radix-ui group in /vrc-get-gui with 4 updates: [@radix-ui/react-label](https://github.com/radix-ui/primitives), [@radix-ui/react-progress](https://github.com/radix-ui/primitives), [@radix-ui/react-separator](https://github.com/radix-ui/primitives) and [@radix-ui/react-slot](https://github.com/radix-ui/primitives).


Updates `@radix-ui/react-label` from 2.1.7 to 2.1.8
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-progress` from 1.1.7 to 1.1.8
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-separator` from 1.1.7 to 1.1.8
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-slot` from 1.2.3 to 1.2.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-label"
  dependency-version: 2.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-progress"
  dependency-version: 1.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-separator"
  dependency-version: 1.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-slot"
  dependency-version: 1.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
dependabot[bot]
df1fc5a591
chore(deps): bump the i18next group across 1 directory with 2 updates
Bumps the i18next group with 2 updates in the /vrc-get-gui directory: [i18next](https://github.com/i18next/i18next) and [react-i18next](https://github.com/i18next/react-i18next).


Updates `i18next` from 25.4.2 to 25.5.2
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v25.4.2...v25.5.2)

Updates `react-i18next` from 15.7.2 to 15.7.3
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v15.7.2...v15.7.3)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 25.5.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: i18next
- dependency-name: react-i18next
  dependency-version: 15.7.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
dependabot[bot]
28be7e8202
chore(deps-dev): bump @biomejs/biome from 2.2.2 to 2.3.8 in /vrc-get-gui
Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.2.2 to 2.3.8.
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.3.8/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.3.8
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
dependabot[bot]
23f09836a0
chore(deps): bump lucide-react from 0.541.0 to 0.561.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.541.0 to 0.561.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.561.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 0.561.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:28:14 +01:00
anatawa12
a9ff68b47a
Merge pull request #2632 from tompointexe/patch-1
Update French translations for ALCOM
2026-01-21 17:24:02 +09:00
anatawa12
edb8c2d2d9
Merge pull request #2641 from o-tr/fix/webkit-transition-bug
fix: アップデートのダウンロード時にプログレスバーがちらつく
2025-12-28 21:46:47 +09:00
anatawa12
3ce9fd58d3
lint: fix biome lint error 2025-12-28 21:36:05 +09:00
anatawa12
73998e7f2c
chore: update to include bugzilla link 2025-12-28 21:29:58 +09:00
dependabot[bot]
51aa98ab2b
chore(deps): bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 07:07:33 +00:00
ootr
df3efbcf65
fix: add comment to describe change from shadcn 2025-12-13 16:43:18 +09:00
ootr
3f28dbe371
fix: replace issue url with pr url 2025-12-13 16:40:27 +09:00
ootr
0abcadb979
chore: update changelog 2025-12-13 16:27:07 +09:00
ootr
e5d7c492d2
fix: remove transition-all to fix a webkit bug
close #2640
2025-12-13 16:21:07 +09:00
Sayamame-beans
670642d8cb chore(l10n): [ja] update locale 2025-12-06 20:59:03 +09:00
Sayamame-beans
d2cabbdc0b chore(l10n): [en] add "general:toast:invalid file" 2025-12-06 20:58:50 +09:00
Sayamame-beans
257a479f3e chore: rename "Id" for ReorderableList to "ReorderableListId" 2025-12-06 20:58:11 +09:00
Sayamame-beans
add44e04a9 chore: run cargo fmt 2025-12-06 18:12:23 +09:00
Sayamame-beans
c1eb9ffc16 docs(changelog-gui): update changelog 2025-12-06 18:09:40 +09:00
Sayamame-beans
6104fc017d feat: allow reselecting unitypackage path on Template Editor 2025-12-06 18:06:44 +09:00
Tom.exe
be4d898668
Update French translation
Changed "Mis en avant" by "Sélection par VRChat"
2025-12-05 11:37:22 +01:00
Tom.exe
a21606f011
Update French translations
Changed importing existing project translation
2025-12-04 13:41:50 +01:00
dependabot[bot]
5859403cad
chore(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 07:32:57 +00:00
github-actions[bot]
b9596cb56a chore: prepare for next version: gui 1.1.6 2025-11-16 09:12:33 +00:00
github-actions[bot]
9c2963b21c gui v1.1.5 2025-11-16 09:00:48 +00:00
github-actions[bot]
194ae0b96d gui v1.1.5-beta.1 2025-11-14 06:54:25 +00:00
anatawa12
d370a5195c
Merge pull request #2608 from vrc-get/anatawa12-patch-1 2025-11-14 14:52:13 +09:00
anatawa12
85edddbf0d
ci: use windows 2022 for publishing 2025-11-14 14:46:30 +09:00
anatawa12
ceaf3a9cce
Merge pull request #2607 from vrc-get/fix-unexpected-detected-loop
fix: unexpected 'Detected Loop' panic
2025-11-14 14:11:05 +09:00
anatawa12
ad5f28ce6a
docs(changelog): Fix 'Detected Loop' panic with valid database file 2025-11-14 14:02:54 +09:00
anatawa12
6251e87fbe
fix: unexpected 'Detected Loop' panic 2025-11-14 14:01:16 +09:00
anatawa12
a239686702
Merge pull request #2589 from lonelyicer/fix/dropdown-overlap
fix: limit max height of package version selector
2025-11-14 13:58:38 +09:00
anatawa12
6f4ded7ed7
Merge branch 'master' into fix/dropdown-overlap 2025-11-14 13:35:08 +09:00
anatawa12
912609d681
Merge pull request #2606 from vrc-get/bump-rust
Bump rust
2025-11-14 12:33:09 +09:00
anatawa12
a64426984c
lint: remove unused import 2025-11-14 12:21:22 +09:00
anatawa12
7a30129796
lint: remove with_added_extension witch is stable in 1.91 2025-11-14 12:20:15 +09:00
RingLo_
c706ce7b27
docs(changelog): add pr number 2025-11-14 07:18:40 +08:00
RingLo_
933933e287 docs(changelog): update for #2589 2025-10-30 20:37:12 +08:00
RingLo_
f5fa8a5e2f fix: limit max height of package version selector 2025-10-30 20:32:29 +08:00
anatawa12
d120156b50
Merge pull request #2562 from tukiminya/style/change-strong-tag
style: change strong to b tag for stylistic emphasis
2025-10-23 01:35:50 +09:00
anatawa12
0c50a14ba7
Merge branch 'master' into style/change-strong-tag 2025-10-23 01:17:20 +09:00
anatawa12
274ef9f33d
Merge pull request #2571 from vrc-get/fix-ci-failure
ci: try to fix the CI failure with aarc64 linux images
2025-10-23 01:15:01 +09:00
anatawa12
94971631a3
ci: override rustflags for static link check 2025-10-23 00:47:49 +09:00
tukimi
3aadcf21d7
style: change strong to b tag for stylistic emphasis 2025-10-18 04:15:03 +09:00
anatawa12
beffbeae47
Merge pull request #2517 from o-tr/fix/dialog
fix: replace some DialogDescription with div in dialog components
2025-09-15 03:43:51 +09:00
ootr
8b0956c6df
fix: formats 2025-09-15 02:29:17 +09:00
ootr
4db0e64e81
fix: update changelog for muted-foreground color fix and remove DialogDescription 2025-09-15 02:28:08 +09:00
ootr
c679ed69fa
fix: replace some DialogDescription with div in dialog components 2025-09-15 02:25:50 +09:00
anatawa12
1394691f4a
Merge pull request #2516 from o-tr/fix/muted-foreground-color
fix: muted-foreground color definition in css
2025-09-15 02:20:57 +09:00
ootr
229118fb9e
fix: update changelog for muted-foreground color fix 2025-09-15 01:56:39 +09:00
ootr
54e4ad3756
fix: muted-foreground color definition in css 2025-09-15 01:47:28 +09:00
github-actions[bot]
ed9a12ee80 chore: prepare for next version: gui 1.1.5 2025-09-02 04:40:32 +00:00
github-actions[bot]
dbe60c6a6e gui v1.1.4 2025-09-02 04:29:13 +00:00
anatawa12
caec80ce05
Merge pull request #2489 from CirnoV/locale/ko-KR
chore(l10n): [ko_kr] update locale
2025-09-02 00:29:42 +09:00
CirnoV
3c3dc35ea3 chore(l10n): [ko_kr] update locale 2025-09-01 22:48:53 +09:00
github-actions[bot]
03cac441dd gui v1.1.4-rc.1 2025-09-01 13:13:46 +00:00
anatawa12
45a9ab02fb
Merge pull request #2485 from vrc-get/less-settings-loss
Improve settings store / load for less error
2025-09-01 19:47:26 +09:00
anatawa12
35bc7ff4a5
docs(changelog): Improved saving interacting with setting files 2025-09-01 19:41:08 +09:00
anatawa12
447f371598
chore: treat empty file as '{}' instead of throwing error 2025-09-01 19:36:13 +09:00
anatawa12
2f71bcf9d3
feat: atomically overwrite existing file
This should improve crash stability
2025-09-01 19:01:55 +09:00
anatawa12
b42e4c29a1
Merge pull request #2482 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-08-27 15:05:38 +09:00
夜嵐蝶Alma
033d8ea05c chore(l10n): [zh_hant] update locale 2025-08-27 13:54:56 +08:00
anatawa12
0a64ce7194
Merge pull request #2481 from Spokeek/french-translation
Updated FR translations for 1.1.4-rc
2025-08-25 22:46:17 +09:00
Spokeek
2362b55407
Updated FR translations for 1.1.4-rc 2025-08-25 15:04:26 +02:00
github-actions[bot]
420e640f00 gui v1.1.4-rc.0 2025-08-24 19:39:07 +00:00
anatawa12
3e60bf15e9
Merge pull request #2479 from vrc-get/localization-summary
Localization summary at discussion
2025-08-25 04:00:06 +09:00
anatawa12
7e240df2c5
ci: update English Localization and Text Representation 2025-08-25 03:54:23 +09:00
anatawa12
da4efddb1c
ci: refactor localization-updates.js 2025-08-25 03:54:23 +09:00
anatawa12
a4e447021c
Merge pull request #2478 from vrc-get/ringbuffer-0.16
chore(deps): ringbuffer 0.16
2025-08-25 03:20:12 +09:00
dependabot[bot]
693fc96583
Merge pull request #2476 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-swc-4.0.1 2025-08-24 18:13:37 +00:00
anatawa12
68b63967db
Merge pull request #2477 from vrc-get/fix-for-old-bug
chore: add a fix for a bug in the previous version of ALCOM
2025-08-25 03:13:25 +09:00
anatawa12
50e458c5c6
chore(deps): ringbuffer 0.16 2025-08-25 03:09:24 +09:00
dependabot[bot]
3204c31447
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react-swc) from 3.11.0 to 4.0.1.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@4.0.1/packages/plugin-react-swc)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-version: 4.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-24 18:01:26 +00:00
dependabot[bot]
416448ddec
Merge pull request #2437 from vrc-get/dependabot/cargo/async_zip-0.0.18 2025-08-24 18:00:31 +00:00
anatawa12
b1ab5c46c0
chore: add a fix for a bug in the previous version of ALCOM 2025-08-25 02:59:14 +09:00
dependabot[bot]
b4eb2e4116
Merge pull request #2431 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-8560841430 2025-08-24 17:58:08 +00:00
dependabot[bot]
3ecd463963
Merge pull request #2475 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/cli-2.8.2 2025-08-24 17:47:44 +00:00
dependabot[bot]
bcb2c9253b
chore(deps): bump async_zip from 0.0.17 to 0.0.18
Bumps [async_zip](https://github.com/Majored/rs-async-zip) from 0.0.17 to 0.0.18.
- [Release notes](https://github.com/Majored/rs-async-zip/releases)
- [Commits](https://github.com/Majored/rs-async-zip/compare/v0.0.17...v0.0.18)

---
updated-dependencies:
- dependency-name: async_zip
  dependency-version: 0.0.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-24 17:45:52 +00:00
dependabot[bot]
874800f371
Merge pull request #2441 from vrc-get/dependabot/github_actions/actions/download-artifact-5 2025-08-24 17:45:37 +00:00
dependabot[bot]
18105daae5
chore(deps-dev): bump @tauri-apps/cli in /vrc-get-gui
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 2.8.1 to 2.8.2.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.8.1...@tauri-apps/cli-v2.8.2)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-version: 2.8.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-24 16:41:05 +00:00
dependabot[bot]
1713fb6f1c
chore(deps): bump the react group across 1 directory with 4 updates
Bumps the react group with 4 updates in the /vrc-get-gui directory: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react), [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).


Updates `react` from 19.1.0 to 19.1.1
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.1/packages/react)

Updates `@types/react` from 19.1.7 to 19.1.9
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.1.0 to 19.1.1
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.1/packages/react-dom)

Updates `@types/react-dom` from 19.1.6 to 19.1.7
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `@types/react` from 19.1.7 to 19.1.9
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.6 to 19.1.7
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.1.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.1.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-24 16:41:03 +00:00
dependabot[bot]
c675d975bd
Merge pull request #2456 from vrc-get/dependabot/github_actions/actions/checkout-5 2025-08-24 16:38:27 +00:00
anatawa12
6c9900ed69
Merge pull request #2473 from vrc-get/update-deps
Update deps
2025-08-25 01:26:02 +09:00
anatawa12
2d83e0dade
fix: suppress unnecessary warnings 2025-08-25 01:19:36 +09:00
anatawa12
048ad943d4
fix: compiler warning with newer version of rust 2025-08-25 00:56:49 +09:00
anatawa12
a1b16b6ac6
chore(deps): update deps 2025-08-25 00:55:26 +09:00
anatawa12
518a8c671b
Merge pull request #2470 from vrc-get/compact-fixes
chore: improve compact mode and basic components
2025-08-24 23:56:40 +09:00
anatawa12
a7170b42c5
docs(changelog-gui): Add PR number to add compact gui option 2025-08-24 23:47:58 +09:00
anatawa12
ed70604b38
chore: improve compact mode and styling rule 2025-08-24 23:34:29 +09:00
anatawa12
30fa3e7bef
Merge pull request #2466 from vrc-get/copilot/fix-2464
Always allow Home/End and Up/Down keys for cursor navigation in autocomplete fields
2025-08-20 21:34:41 +09:00
copilot-swe-agent[bot]
a0e08ce48f Update changelog to include up/down arrow key functionality
Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 11:40:33 +00:00
copilot-swe-agent[bot]
d185db333c Allow up/down keys for cursor navigation when suggestions are not open
Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 10:26:20 +00:00
copilot-swe-agent[bot]
86f1afa140 Fix changelog to use PR number #2466 instead of issue number #2464
Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 10:22:04 +00:00
copilot-swe-agent[bot]
8485f35e17 Always allow Home/End keys for cursor navigation in autocomplete fields
Fixes #2464 where Home/End keys were inconsistently working for cursor navigation in Unity version and package information fields. Previously, these keys would sometimes be captured by the Command component for suggestion list navigation when suggestions were visible.

Now Home/End keys always control text cursor position regardless of autocomplete state, providing consistent behavior and better user experience.

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>

Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 10:07:17 +00:00
copilot-swe-agent[bot]
abcffbd849 Always allow Home/End keys to control cursor in autocomplete
Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 09:44:23 +00:00
copilot-swe-agent[bot]
b7e6d97484 Fix Home/End key navigation in autocomplete fields
Co-authored-by: anatawa12 <22656849+anatawa12@users.noreply.github.com>
2025-08-20 09:37:05 +00:00
copilot-swe-agent[bot]
9026343cdd Initial plan 2025-08-20 09:31:13 +00:00
anatawa12
74062136fd
Merge pull request #2450 from lonelyicer/chore/buton-compact
chore: button compact
2025-08-20 01:41:20 +09:00
Sayamame-beans
ec66e5c2f0
Merge pull request #2452 from vrc-get/fix-2435
fix: specifying a single unityversion doesn't work properly in alcomtemplate
2025-08-19 23:15:32 +09:00
Sayamame-beans
2e5c5da3cb
docs(changelog): Apply suggestion from code review
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-08-19 22:50:54 +09:00
Sayamame-beans
0f0f0aaddb
Merge branch 'master' into fix-2435 2025-08-19 22:50:31 +09:00
RingLo_
5b7861a91e lint(biome): fix format 2025-08-19 21:13:38 +08:00
RingLo_
c90c495a31 chore: Improve compact mode sizing for navbars and buttons 2025-08-19 21:10:28 +08:00
RingLo_
c477121bc5
Merge branch 'master' into chore/buton-compact 2025-08-19 20:20:42 +08:00
RingLo_
7ff3b16c8e chore: Adjust layout spacing and wrapping in UI components 2025-08-19 20:19:44 +08:00
dependabot[bot]
d7b126f82a
chore(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 10:12:58 +00:00
Sayamame-beans
6af3d96cf2 fix: unintended breaking change for check for package version range 2025-08-18 08:04:59 +09:00
anatawa12
6a258a19b3
Merge pull request #2451 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-08-18 02:38:30 +09:00
Sayamame-beans
544a9bd505 chore: apply biome fix 2025-08-18 02:11:26 +09:00
anatawa12
40ce7de7b7
Merge pull request #2449 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_hans] update locale
2025-08-18 01:32:42 +09:00
Sayamame-beans
6866b6f08c docs(changelog-gui): update changelog 2025-08-18 01:31:33 +09:00
Sayamame-beans
bcdb94861b fix: specifying a single unityversion doesn't work properly in alcomtemplate 2025-08-18 01:23:39 +09:00
JustBuddy
c32b59b9bf
chore(l10n): [de_DE] update locale
- Added compact mode keys.
2025-08-17 15:14:41 +02:00
RingLo_
b097013eba docs(changelog-gui): for #2450 2025-08-17 20:31:26 +08:00
RingLo_
d7d369b5fe lint(biome): fix format 2025-08-17 20:29:43 +08:00
RingLo_
520b79e0dd lint(biome): fix 2025-08-17 20:28:13 +08:00
RingLo_
52d3e158d3 chore: icon button size for compact 2025-08-17 19:39:49 +08:00
RingLo_
0a599c806b chore: button compact 2025-08-17 19:22:51 +08:00
RingLo_
16f65ec950 chore(l10n): [zh_hans] update locale 2025-08-17 17:40:35 +08:00
anatawa12
09ccfb9f4f
Merge pull request #2436 from nekobako/feature/compact-gui
feat: add compact gui option
2025-08-17 14:49:44 +09:00
nekobako
4d7a923eaf chore: fix format 2025-08-17 10:18:23 +09:00
nekobako
3c6385e75f feat: adjust compact styles 2025-08-17 10:18:13 +09:00
nekobako
8331d1d978 chore: fix format 2025-08-16 16:57:13 +09:00
nekobako
b1d28f4efc chore: replace Tooltip and Button in SideBar with SideBarButton 2025-08-16 12:40:17 +09:00
nekobako
54fbb7ceff Revert "chore: add TooltipButton"
This reverts commit dce7c74f45.
2025-08-15 19:20:08 +09:00
nekobako
dce7c74f45 chore: add TooltipButton 2025-08-14 21:18:48 +09:00
nekobako
4abb31287f chore: remove redundant element 2025-08-14 21:18:48 +09:00
nekobako
a7bf336674 feat: apply compact style to setup page 2025-08-14 21:18:48 +09:00
nekobako
0cb111bba8 feat: apply compact style to package list and log list 2025-08-13 18:33:46 +09:00
nekobako
68b1ed245b chore: use custom variant for styling 2025-08-13 02:23:59 +09:00
dependabot[bot]
f769dd45a6
chore(deps): bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 11:05:57 +00:00
nekobako
261f3a97cb docs(changelog-gui): Add compact gui option 2025-08-11 18:12:16 +09:00
nekobako
3399b0fa00 feat: add compact gui option 2025-08-09 21:32:17 +09:00
github-actions[bot]
e89e1340a0 chore: prepare for next version: gui 1.1.4 2025-07-28 12:21:30 +00:00
github-actions[bot]
70b0c7c7e6 gui v1.1.3 2025-07-28 12:07:51 +00:00
github-actions[bot]
6eb2422362 chore: prepare for next version: 1.9.2 2025-07-28 12:05:45 +00:00
github-actions[bot]
7b9f009e17 v1.9.1 2025-07-28 11:57:39 +00:00
anatawa12
12f4244814
Merge pull request #2402 from ColorlessColor/patch-1 2025-07-28 20:55:31 +09:00
ColorlessColor
cc139a07e1
chore(l10n): [zh_hans] update locale 2025-07-28 09:12:09 +08:00
github-actions[bot]
42e3ba176d gui v1.1.3-beta.2 2025-07-24 14:58:43 +00:00
anatawa12
0925dcbca6
Merge pull request #2400 from CirnoV/locale/ko-KR
chore(I10n): [ko_KR] update locale
2025-07-24 23:19:33 +09:00
CirnoV
2edaa8c846 chore(I10n): [ko_KR] update locale 2025-07-24 22:13:55 +09:00
anatawa12
f1c0afd6cc
Merge pull request #2398 from Spokeek/french-translation
Add fr translations 1.1.3
2025-07-19 14:39:20 +09:00
Spokeek
1a03dea7c9
fix typo 2025-07-18 18:00:02 +02:00
Spokeek
1ef62e6f79
Add fr translations 1.1.3 2025-07-18 17:58:46 +02:00
anatawa12
ef33365884
Merge pull request #2397 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_hans] update locale
2025-07-18 01:16:06 +09:00
RingLo_
b27a9ce01d chore(l10n): [zh_hans] update locale 2025-07-17 22:18:06 +08:00
anatawa12
13174eba98
Merge pull request #2395 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-07-16 12:05:58 +09:00
夜嵐蝶Alma
0dbf59dd85 chore(l10n): [zh_hant] update locale 2025-07-16 00:35:03 +08:00
dependabot[bot]
7a5aed016d
Merge pull request #2392 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-10c2bfaf3b 2025-07-14 09:59:37 +00:00
dependabot[bot]
8e703a718b
Merge pull request #2389 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/biomejs/biome-2.1.1 2025-07-14 09:58:19 +00:00
anatawa12
a78ebd4f52
Merge pull request #2390 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-07-14 18:56:39 +09:00
dependabot[bot]
3342e069dd
chore(deps): bump i18next in /vrc-get-gui in the i18next group
Bumps the i18next group in /vrc-get-gui with 1 update: [i18next](https://github.com/i18next/i18next).


Updates `i18next` from 25.3.1 to 25.3.2
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v25.3.1...v25.3.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 25.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 09:43:44 +00:00
dependabot[bot]
bde51b52e3
chore(deps-dev): bump @biomejs/biome from 2.0.6 to 2.1.1 in /vrc-get-gui
Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.0.6 to 2.1.1.
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.1.1/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 09:40:40 +00:00
JustBuddy
357ead18ce
chore(l10n): [de_DE] update locale 2025-07-14 11:39:19 +02:00
dependabot[bot]
7c8a40bd2b
Merge pull request #2384 from vrc-get/dependabot/cargo/plist-1.7.4 2025-07-14 09:23:31 +00:00
dependabot[bot]
56d883fa6d
Merge pull request #2385 from vrc-get/dependabot/cargo/clap-8ce38b5983 2025-07-14 09:23:06 +00:00
dependabot[bot]
f69d968680
Merge pull request #2386 from vrc-get/dependabot/cargo/async-compression-0.4.27 2025-07-14 09:22:58 +00:00
dependabot[bot]
d5b4c28b34
chore(deps): bump async-compression from 0.4.25 to 0.4.27
Bumps [async-compression](https://github.com/Nullus157/async-compression) from 0.4.25 to 0.4.27.
- [Release notes](https://github.com/Nullus157/async-compression/releases)
- [Changelog](https://github.com/Nullus157/async-compression/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Nullus157/async-compression/compare/v0.4.25...v0.4.27)

---
updated-dependencies:
- dependency-name: async-compression
  dependency-version: 0.4.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 08:36:11 +00:00
dependabot[bot]
d7c8cea78a
chore(deps): bump the clap group with 2 updates
Bumps the clap group with 2 updates: [clap](https://github.com/clap-rs/clap) and [clap_complete](https://github.com/clap-rs/clap).


Updates `clap` from 4.5.40 to 4.5.41
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.40...clap_complete-v4.5.41)

Updates `clap_complete` from 4.5.54 to 4.5.55
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.54...clap_complete-v4.5.55)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.41
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: clap
- dependency-name: clap_complete
  dependency-version: 4.5.55
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: clap
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 08:27:17 +00:00
dependabot[bot]
aebaf83dde
chore(deps): bump plist from 1.7.3 to 1.7.4
Bumps [plist](https://github.com/ebarnard/rust-plist) from 1.7.3 to 1.7.4.
- [Release notes](https://github.com/ebarnard/rust-plist/releases)
- [Changelog](https://github.com/ebarnard/rust-plist/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ebarnard/rust-plist/compare/v1.7.3...v1.7.4)

---
updated-dependencies:
- dependency-name: plist
  dependency-version: 1.7.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 08:12:36 +00:00
anatawa12
13feb4e889
Merge pull request #2383 from vrc-get/update_l10n_ja
chore(l10n): [ja] update locale
2025-07-09 18:13:20 +09:00
Sayamame-beans
cbcd0a5268 chore(l10n): [ja] update locale 2025-07-09 17:25:24 +09:00
github-actions[bot]
88b8043084 v1.9.1-beta.1 2025-07-08 10:18:01 +00:00
anatawa12
fe95e0f893
Merge pull request #2379 from vrc-get/litedb-on-crates-io
chore(deps): use litedb from crates.io
2025-07-08 15:47:28 +09:00
anatawa12
d741270d43
chore(deps): use litedb from crates.io 2025-07-08 15:40:31 +09:00
github-actions[bot]
ba826a9856 gui v1.1.3-beta.1 2025-07-08 05:47:27 +00:00
anatawa12
73a802103e
Merge pull request #2378 from vrc-get/release-concurrency
ci: set concurrency for publish actions
2025-07-08 14:46:25 +09:00
anatawa12
ecc94f9771
ci: set concurrency for publish actions 2025-07-08 14:40:06 +09:00
dependabot[bot]
92e71a4929
Merge pull request #2345 from vrc-get/dependabot/cargo/tauri-plugin-single-instance-2.3.0 2025-07-08 05:28:28 +00:00
dependabot[bot]
43869ae594
chore(deps): bump tauri-plugin-single-instance from 2.2.4 to 2.3.0
Bumps [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) from 2.2.4 to 2.3.0.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/opener-v2.2.4...os-v2.3.0)

---
updated-dependencies:
- dependency-name: tauri-plugin-single-instance
  dependency-version: 2.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-08 05:17:25 +00:00
anatawa12
9e23a3f794
Merge pull request #2377 from vrc-get/deps
remove svgo dep and update npm deps
2025-07-08 14:07:54 +09:00
anatawa12
5f57cd6954
chore: update installer.nsi for newer macro 2025-07-08 14:01:15 +09:00
dependabot[bot]
19fc2ea44f
Merge pull request #2362 from vrc-get/dependabot/cargo/vrc-get-litedb-f4692f8 2025-07-08 04:36:11 +00:00
anatawa12
77fc446770
chore: update routeTree.gen.ts 2025-07-08 13:35:48 +09:00
anatawa12
28b585a754
chore: add license file logic for unlicense 2025-07-08 13:29:20 +09:00
anatawa12
f0599e37f6
chore: add Unlicense as allowed license 2025-07-08 13:06:58 +09:00
anatawa12
08b4b83cf6
chore(deps): update npm deps 2025-07-08 12:59:26 +09:00
anatawa12
eddf19d989
chore(deps): remove svgo 2025-07-08 12:56:53 +09:00
dependabot[bot]
8830701a43
Merge pull request #2368 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tw-animate-css-1.3.5 2025-07-08 03:08:29 +00:00
dependabot[bot]
8cc0f2c865
chore(deps-dev): bump tw-animate-css from 1.3.4 to 1.3.5 in /vrc-get-gui
Bumps [tw-animate-css](https://github.com/Wombosvideo/tw-animate-css) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/Wombosvideo/tw-animate-css/releases)
- [Commits](https://github.com/Wombosvideo/tw-animate-css/compare/v1.3.4...v1.3.5)

---
updated-dependencies:
- dependency-name: tw-animate-css
  dependency-version: 1.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:53:02 +00:00
dependabot[bot]
50376cd537
Merge pull request #2365 from vrc-get/dependabot/cargo/reqwest-0.12.22 2025-07-07 19:44:15 +00:00
dependabot[bot]
acc97794c7
Merge pull request #2353 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/api-2.6.0 2025-07-07 19:41:53 +00:00
dependabot[bot]
4e85bd674b
Merge pull request #2349 from vrc-get/dependabot/cargo/tauri-plugin-dialog-2.3.0 2025-07-07 19:41:27 +00:00
dependabot[bot]
6085d0c8da
Merge pull request #2352 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/sharp-cli-5.2.0 2025-07-07 19:31:56 +00:00
dependabot[bot]
49d2383d0b
Merge pull request #2351 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/biomejs/biome-2.0.6 2025-07-07 19:31:20 +00:00
dependabot[bot]
3a059b8076
Merge pull request #2363 from vrc-get/dependabot/cargo/tokio-1.46.1 2025-07-07 19:27:31 +00:00
dependabot[bot]
3ea86ca01a
chore(deps): bump tauri-plugin-dialog from 2.2.2 to 2.3.0
Bumps [tauri-plugin-dialog](https://github.com/tauri-apps/plugins-workspace) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/os-v2.2.2...os-v2.3.0)

---
updated-dependencies:
- dependency-name: tauri-plugin-dialog
  dependency-version: 2.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:22:36 +00:00
dependabot[bot]
b06d839f6f
chore(deps): bump @tauri-apps/api from 2.5.0 to 2.6.0 in /vrc-get-gui
Bumps [@tauri-apps/api](https://github.com/tauri-apps/tauri) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.5.0...@tauri-apps/api-v2.6.0)

---
updated-dependencies:
- dependency-name: "@tauri-apps/api"
  dependency-version: 2.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:07:08 +00:00
dependabot[bot]
889abbf080
chore(deps-dev): bump @biomejs/biome from 2.0.0 to 2.0.6 in /vrc-get-gui
---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:06:44 +00:00
dependabot[bot]
e27c81527b
chore(deps-dev): bump sharp-cli from 5.1.0 to 5.2.0 in /vrc-get-gui
Bumps [sharp-cli](https://github.com/vseventer/sharp-cli) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/vseventer/sharp-cli/releases)
- [Changelog](https://github.com/vseventer/sharp-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vseventer/sharp-cli/compare/v5.1.0...v5.2.0)

---
updated-dependencies:
- dependency-name: sharp-cli
  dependency-version: 5.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:06:41 +00:00
dependabot[bot]
2afa04625a
chore(deps): bump reqwest from 0.12.20 to 0.12.22
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.20 to 0.12.22.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.20...v0.12.22)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.12.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:02:21 +00:00
dependabot[bot]
264e7264d2
chore(deps): bump tokio from 1.45.1 to 1.46.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.1 to 1.46.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.1...tokio-1.46.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.46.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 19:01:20 +00:00
dependabot[bot]
fed69c51ae
Merge pull request #2366 from vrc-get/dependabot/cargo/plist-1.7.3 2025-07-07 18:47:50 +00:00
dependabot[bot]
be449abcb0
Merge pull request #2364 from vrc-get/dependabot/cargo/serde_with-3.14.0 2025-07-07 18:47:11 +00:00
dependabot[bot]
d36ad4d5f6
Merge pull request #2346 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-ee6bf6b019 2025-07-07 18:44:42 +00:00
dependabot[bot]
52bf5045d1
Merge pull request #2344 from vrc-get/dependabot/cargo/indexmap-2.10.0 2025-07-07 18:44:26 +00:00
dependabot[bot]
62d65154ac
Merge pull request #2333 from vrc-get/dependabot/cargo/async-compression-0.4.25 2025-07-07 18:44:06 +00:00
anatawa12
a18ee8d27b
Merge pull request #2376 from vrc-get/template-on-creation
feat: favorite templates and preserve last used template
2025-07-08 03:42:44 +09:00
anatawa12
926549727b
Merge branch 'master' into template-on-creation 2025-07-08 03:36:45 +09:00
anatawa12
990c7a4792
docs(changelog-gui): Favorites and last used for templates 2025-07-08 03:36:20 +09:00
anatawa12
13eb2f2d80
lint: npx biome check --fix 2025-07-08 03:35:44 +09:00
anatawa12
f0d77b3c4d
feat: favorite templates and preserve last used template 2025-07-08 03:31:12 +09:00
dependabot[bot]
6c7e362853
chore(deps): bump plist from 1.7.2 to 1.7.3
Bumps [plist](https://github.com/ebarnard/rust-plist) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/ebarnard/rust-plist/releases)
- [Changelog](https://github.com/ebarnard/rust-plist/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ebarnard/rust-plist/compare/v1.7.2...v1.7.3)

---
updated-dependencies:
- dependency-name: plist
  dependency-version: 1.7.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 17:17:19 +00:00
anatawa12
f229e4fcfe
Merge pull request #2327 from vrc-get/remove-migrate-if-user-projects-absent
chore: improve behavior for future VCC versions
2025-07-08 02:15:32 +09:00
anatawa12
99416f5530
Merge branch 'master' into remove-migrate-if-user-projects-absent 2025-07-08 02:05:25 +09:00
anatawa12
b2dc61a903
test: add tests for vcc.litedb settings.json migration 2025-07-08 02:04:57 +09:00
anatawa12
44d6669d3c
Merge pull request #2373 from vrc-get/update-sdk-samples
chore: update project settings of templates to include Item layer
2025-07-08 01:06:53 +09:00
anatawa12
19636c3ee0
Merge pull request #2375 from vrc-get/keywords-support
feat: add support for `keywords` UPM manifest property
2025-07-08 01:05:56 +09:00
anatawa12
f717df3e52
test: add utility function to create template directory 2025-07-08 01:04:47 +09:00
anatawa12
bd79f1a3d7
Merge branch 'master' into remove-migrate-if-user-projects-absent 2025-07-08 01:02:36 +09:00
anatawa12
ab9f9a4ae5
docs(changelog-gui): Add support for keywords UPM manifest field 2025-07-08 00:58:26 +09:00
anatawa12
4bcaa4e564
feat: add support for keywords UPM manifest property 2025-07-08 00:57:18 +09:00
anatawa12
3c79f0c4c1
docs(changelog-gui): Updated project settings of templates to include Item layer 2025-07-08 00:48:04 +09:00
anatawa12
bd934ed698
chore: update project settings of templates to include Item layer 2025-07-08 00:45:09 +09:00
anatawa12
97be14fb5c
Merge pull request #2372 from vrc-get/package-install-uncheck
fix: packages are not deselected after installing packages
2025-07-08 00:38:24 +09:00
anatawa12
08309f1e80
Merge pull request #2371 from vrc-get/template-editor
Template Editor improvement with autocomplete
2025-07-08 00:25:39 +09:00
anatawa12
b8412ea607
docs(changelog-gui): Packages are not deselected after installing packages 2025-07-08 00:18:24 +09:00
anatawa12
7f0afbf3af
fix: packages are not deselected after installing packages 2025-07-08 00:17:20 +09:00
anatawa12
63e4ff482b
lint: npx biome check --fix 2025-07-08 00:06:38 +09:00
anatawa12
ff7f8a5dab
docs(changelog-gui): Improved the Template Editor with AutoComplete 2025-07-08 00:05:53 +09:00
anatawa12
c398d70326
chore: allow search by alias in template editor 2025-07-08 00:04:43 +09:00
anatawa12
4e30f45a3b
chore: improve template editor with autocomplete 2025-07-07 23:58:58 +09:00
anatawa12
4133a7550b
chore: improve autocomplete 2025-07-07 23:55:32 +09:00
anatawa12
9c99b7d19e
feat: add autocomplete component 2025-07-07 19:06:47 +09:00
anatawa12
0d97b76156
chore(deps): add command and popover shadcn elements 2025-07-07 18:48:42 +09:00
dependabot[bot]
e0288af16c
chore(deps): bump serde_with from 3.13.0 to 3.14.0
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.13.0 to 3.14.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.13.0...v3.14.0)

---
updated-dependencies:
- dependency-name: serde_with
  dependency-version: 3.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:54:17 +00:00
dependabot[bot]
8b2e029df8
chore(deps): bump vrc-get-litedb from ec44d07 to f4692f8
Bumps [vrc-get-litedb](https://github.com/anatawa12/litedb-rs) from `ec44d07` to `f4692f8`.
- [Release notes](https://github.com/anatawa12/litedb-rs/releases)
- [Commits](ec44d0740a...f4692f8462)

---
updated-dependencies:
- dependency-name: vrc-get-litedb
  dependency-version: f4692f846282413cdc8b22f960867f35b0dff562
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:41:21 +00:00
dependabot[bot]
5fb465b9e8
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.11/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 07:49:53 +00:00
anatawa12
b75d4772bf
Merge pull request #2358 from vrc-get/images
ci: enable TAURI_BUNDLER_DMG_IGNORE_CI again
2025-07-02 12:56:44 +09:00
anatawa12
45260b65bb
ci: enable TAURI_BUNDLER_DMG_IGNORE_CI again 2025-07-02 10:27:19 +09:00
dependabot[bot]
4b05207f5c
chore(deps): bump indexmap from 2.9.0 to 2.10.0
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.9.0 to 2.10.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.9.0...2.10.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-version: 2.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 09:03:42 +00:00
dependabot[bot]
3ea727bc7d
chore(deps): bump async-compression from 0.4.24 to 0.4.25
Bumps [async-compression](https://github.com/Nullus157/async-compression) from 0.4.24 to 0.4.25.
- [Release notes](https://github.com/Nullus157/async-compression/releases)
- [Changelog](https://github.com/Nullus157/async-compression/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Nullus157/async-compression/compare/v0.4.24...v0.4.25)

---
updated-dependencies:
- dependency-name: async-compression
  dependency-version: 0.4.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 06:24:40 +00:00
github-actions[bot]
de7941e238 chore: prepare for next version: gui 1.1.3 2025-06-30 06:22:25 +00:00
github-actions[bot]
2f17a3f71e gui v1.1.2 2025-06-30 06:09:50 +00:00
github-actions[bot]
9c7d6e188d gui v1.1.2-rc.0 2025-06-29 07:52:50 +00:00
anatawa12
09425bb82e
Merge pull request #2341 from vrc-get/fix-error-when-package-invisible
fix: frontend error on package list update (especially for package removal from list)
2025-06-29 14:24:47 +09:00
anatawa12
e2918bd233
docs(changelog): Frontend error on package list update 2025-06-29 14:17:42 +09:00
anatawa12
803b7ca0e3
lint: remove unused imports 2025-06-29 14:15:55 +09:00
anatawa12
1577bdff55
Merge branch 'master' into fix-error-when-package-invisible 2025-06-29 14:11:24 +09:00
anatawa12
d190956c0f
Merge pull request #2343 from vrc-get/clippy-1.88
lint: fix new lints in rust 1.88 and 1.89 beta
2025-06-29 13:49:58 +09:00
anatawa12
b0d32afb04
lint: fix new lints in rust 1.88 and 1.89 beta 2025-06-29 04:00:50 +09:00
anatawa12
e2c20bb741
fix: frontend error on package list update (especially for package removal from list) 2025-06-27 17:01:12 +09:00
anatawa12
d02734aab8
Merge pull request #2337 from vrc-get/fix-hyphen-range-serialize
fix: serializing a - b version range may not emit correct format
2025-06-27 16:40:25 +09:00
anatawa12
627f1bb565
docs(changelog): Fixed a - b version range is not correctly serialized on the vpm-manifest.json 2025-06-25 16:43:08 +09:00
anatawa12
942cf708e5
fix: serializing a - b version range may not emit correct format 2025-06-25 16:28:05 +09:00
anatawa12
963ed90aec
Merge pull request #2329 from vrc-get/biome-v2
Biome v2
2025-06-23 16:34:23 +09:00
anatawa12
454dd753f3
lint: apply new biome rules 2025-06-23 14:39:26 +09:00
anatawa12
62d3ad81f1
dev: migrate biome.jsonc to v2 2025-06-23 14:14:31 +09:00
anatawa12
6a7bf4187e
chore(deps): install biome v2 2025-06-23 14:11:46 +09:00
github-actions[bot]
e22519b94a chore: prepare for next version: gui 1.1.2 2025-06-21 17:14:22 +00:00
github-actions[bot]
7d20291448 gui v1.1.1 2025-06-21 17:01:57 +00:00
anatawa12
d00609643c
docs: Improved behavior about settings.json to vcc.litedb migration 2025-06-22 01:56:15 +09:00
anatawa12
22e5ed0eb0
chore: improve behavior for future VCC versions 2025-06-22 01:47:31 +09:00
github-actions[bot]
70000416e0 gui v1.1.1-rc.1 2025-06-21 14:30:09 +00:00
anatawa12
7e4a235dca
Merge pull request #2326 from vrc-get/crash-on-creating-project
Crash on creating project
2025-06-21 23:16:22 +09:00
anatawa12
48699d9a88
docs(changelog): Crash on creating a new project on Windows 2025-06-21 23:09:08 +09:00
anatawa12
1207ad493f
lint: ban 'close' global 2025-06-21 22:59:08 +09:00
anatawa12
3e9f1f2814
fix: crash on creating project on windows platform 2025-06-21 22:54:29 +09:00
github-actions[bot]
b2f9d84909 gui v1.1.1-rc.0 2025-06-20 15:40:43 +00:00
anatawa12
a06b66ce56
Merge pull request #2324 from vrc-get/finder-change-workaround-release
ci: set TAURI_BUNDLER_DMG_IGNORE_CI to false in release action
2025-06-21 00:02:31 +09:00
anatawa12
33d01b8796
ci: set TAURI_BUNDLER_DMG_IGNORE_CI to false in release action 2025-06-20 23:49:57 +09:00
anatawa12
b973b00042
Merge pull request #2321 from vrc-get/fix-dedup-unity-hub
chore: deduplicating unity locations
2025-06-20 23:22:52 +09:00
anatawa12
3db966c958
Merge pull request #2322 from vrc-get/provisioner-finder-change-workaround
ci: set TAURI_BUNDLER_DMG_IGNORE_CI to false
2025-06-20 23:04:12 +09:00
anatawa12
136dab4639
ci: set TAURI_BUNDLER_DMG_IGNORE_CI to false 2025-06-20 22:44:15 +09:00
anatawa12
8dbd61ad9a
ci: debug logging 2025-06-20 13:13:27 +09:00
anatawa12
af33c544a9
fix: older unity is not recognized by ALCOM 2025-06-20 11:49:07 +09:00
anatawa12
9b3197ca8d
docs: Unity can be duplicated 2025-06-20 11:49:07 +09:00
anatawa12
370239fb75
chore: deduplicating unity locations 2025-06-20 11:35:41 +09:00
github-actions[bot]
a71c490483 chore: prepare for next version: gui 1.1.1 2025-06-19 07:49:03 +00:00
github-actions[bot]
3fa792d9a1 gui v1.1.0 2025-06-19 07:36:53 +00:00
github-actions[bot]
16b8a5c9df gui v1.1.0-rc.6 2025-06-17 14:49:25 +00:00
anatawa12
58d572be01
Merge pull request #2313 from lonelyicer/fix/scroll-bar-style
fix: package changes list scroll bar style
2025-06-17 23:48:46 +09:00
RingLo_
007e9596f5 docs: restore gitignore 2025-06-17 20:48:14 +08:00
RingLo_
b1aff93c98 docs(changelog): update for #2313 2025-06-16 23:22:21 +08:00
RingLo_
14082a1f11 lint(biome): fix import 2025-06-16 23:20:30 +08:00
RingLo_
f8cfe99e6a chore: remove useMountedOnce() 2025-06-16 23:15:59 +08:00
anatawa12
5be5b76212
Merge pull request #2314 from vrc-get/improve-dialog-behaviour
chore: improve dialog behavior when closing / creating a project
2025-06-16 21:24:16 +09:00
anatawa12
1a41db278d
chore: improve dialog behavior when closing / creating a project 2025-06-16 21:13:33 +09:00
RingLo_
42ff3bc1cc fix: package changes list scroll bar style 2025-06-16 17:14:41 +08:00
github-actions[bot]
083ac23265 gui v1.1.0-rc.5 2025-06-16 03:56:14 +00:00
anatawa12
0b40d291f1
Merge pull request #2128 from Spokeek/french-translation 2025-06-16 12:03:09 +09:00
Spokeek
5bcb59c4a9
Add french translations for 1.1.0 2025-06-15 21:44:55 +02:00
anatawa12
1e35ee34db
Merge pull request #2310 from CirnoV/locale/ko-KR
chore(I10n): [ko_KR] update locale
2025-06-16 03:07:38 +09:00
CirnoV
6d336ee757 chore(I10n): [ko_KR] update locale 2025-06-16 01:53:36 +09:00
anatawa12
50de673c8b
Merge pull request #2308 from i0ntempest/l10n
chore: minor log message improvements
2025-06-16 00:22:04 +09:00
i0ntempest
69b9eae851 chore: minor log message improvements 2025-06-16 01:14:45 +10:00
github-actions[bot]
d28d3def35 gui v1.1.0-rc.4 2025-06-15 14:03:55 +00:00
anatawa12
77c4634b42
Merge pull request #2306 from i0ntempest/l10n
chore: minor log message improvements
2025-06-15 22:59:46 +09:00
anatawa12
8ab5564bc0
Merge pull request #2307 from vrc-get/templates-logs
chore: add a few more logs to template management
2025-06-15 22:59:39 +09:00
anatawa12
c5a86c2a35
chore: add a few more logs to template management 2025-06-15 21:57:54 +09:00
i0ntempest
015319f1c6 chore: minor log message improvements 2025-06-15 22:54:43 +10:00
anatawa12
6cb1db9435
Merge pull request #2305 from vrc-get/update-deps
chore(deps): update deps
2025-06-15 14:22:37 +09:00
anatawa12
8764df161a
chore(deps): update deps 2025-06-15 14:05:38 +09:00
github-actions[bot]
05db375b8d gui v1.1.0-rc.3 2025-06-13 15:30:10 +00:00
anatawa12
52098f29cf
Merge pull request #2303 from vrc-get/update-deps
chore(deps): upgrade deps
2025-06-14 00:24:51 +09:00
anatawa12
cb8b515e69
chore: regenerate routeTree.gen.ts 2025-06-14 00:09:28 +09:00
anatawa12
515c19c3d5
chore: update build license json to support crates without license field 2025-06-14 00:07:51 +09:00
anatawa12
764d2957b6
chore(deps): upgrade all 2025-06-13 23:33:10 +09:00
anatawa12
abf8bd467b
Merge pull request #2302 from ColorlessColor/fix-system-proxy 2025-06-13 19:37:21 +09:00
ColorlessColor
51c9c0b313 chore(deps): bump reqwest from 0.12.19 to 0.12.20 2025-06-13 17:17:14 +08:00
ColorlessColor
c239d51612 fix: set default-features to false again for vrc-get cli, this is needed to avoid linking openssl on Linux. Instead, we manually set the other flags which in the default features. 2025-06-13 16:55:28 +08:00
ColorlessColor
2978813828 fix: update hyper-util to 0.1.14 to fix the bug that cannot use Windows system proxy for https requests. 2025-06-13 15:07:48 +08:00
ColorlessColor
18878b743a fix: remove default-features = false from vrc-get/Cargo.toml , because reqwest 0.12.16 changed the feature flag. We need at least "system-proxy". 2025-06-13 14:58:38 +08:00
github-actions[bot]
10f482845c gui v1.1.0-rc.2 2025-06-11 11:16:25 +00:00
dependabot[bot]
ef374fb611
Merge pull request #2295 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tw-animate-css-1.3.4 2025-06-11 08:57:54 +00:00
dependabot[bot]
458632b261
chore(deps-dev): bump tw-animate-css from 1.3.3 to 1.3.4 in /vrc-get-gui
Bumps [tw-animate-css](https://github.com/Wombosvideo/tw-animate-css) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/Wombosvideo/tw-animate-css/releases)
- [Commits](https://github.com/Wombosvideo/tw-animate-css/compare/v1.3.3...v1.3.4)

---
updated-dependencies:
- dependency-name: tw-animate-css
  dependency-version: 1.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 08:51:51 +00:00
dependabot[bot]
7197805e84
Merge pull request #2300 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-9e441a090c 2025-06-11 08:51:16 +00:00
dependabot[bot]
2ba14b45de
chore(deps-dev): bump the react group across 1 directory with 2 updates
Bumps the react group with 2 updates in the /vrc-get-gui directory: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).


Updates `@types/react` from 19.1.6 to 19.1.7
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.5 to 19.1.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 08:18:16 +00:00
dependabot[bot]
b901fc0180
Merge pull request #2294 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-640bbecfd4 2025-06-11 08:16:18 +00:00
dependabot[bot]
6c66c8ecd9
Merge pull request #2292 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.513.0 2025-06-11 08:15:47 +00:00
dependabot[bot]
ffd1efbcc4
Merge pull request #2291 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-swc-3.10.1 2025-06-11 08:15:37 +00:00
dependabot[bot]
51716471b3
Merge pull request #2290 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.80.6 2025-06-11 08:15:29 +00:00
dependabot[bot]
4facd40148
Merge pull request #2289 from vrc-get/dependabot/cargo/anstyle-1.0.11 2025-06-11 08:15:15 +00:00
dependabot[bot]
20bdbca448
Merge pull request #2288 from vrc-get/dependabot/cargo/reqwest-0.12.19 2025-06-11 08:15:04 +00:00
dependabot[bot]
5fa2c9cf92
Merge pull request #2287 from vrc-get/dependabot/cargo/flate2-1.1.2 2025-06-11 08:14:54 +00:00
dependabot[bot]
18281f6a6d
Merge pull request #2248 from vrc-get/dependabot/cargo/object-0.37.0 2025-06-11 08:14:45 +00:00
anatawa12
73ecf2f052
Merge pull request #2299 from vrc-get/remove-anchoring
chore: try to disable auto anchoring
2025-06-11 16:58:17 +09:00
anatawa12
b082f2d8df
chore: try to disable auto anchoring 2025-06-11 15:11:46 +09:00
anatawa12
94e65ef930
Merge pull request #2298 from vrc-get/reinstall-while-installing
fix: reinstall button can be clicked while installing package
2025-06-11 01:57:42 +09:00
anatawa12
5b921a9808
docs(changelog-gui): Add PR Number to the corresponding entry 2025-06-10 23:44:11 +09:00
anatawa12
d2fde29b20
fix: reinstall button can be clicked while installing package 2025-06-10 23:41:04 +09:00
dependabot[bot]
203e48fb0b
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.120.13 to 1.120.20
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.20/packages/react-router)

Updates `@tanstack/router-devtools` from 1.120.13 to 1.120.20
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.20/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.120.13 to 1.120.20
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.20/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.120.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.120.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.120.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 08:29:27 +00:00
dependabot[bot]
57b976a300
chore(deps): bump lucide-react from 0.511.0 to 0.513.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.511.0 to 0.513.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.513.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 0.513.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 08:26:09 +00:00
dependabot[bot]
91bbe1e55c
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react-swc) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react-swc@3.10.1/packages/plugin-react-swc)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-version: 3.10.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 08:21:02 +00:00
dependabot[bot]
f344813ff8
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.79.0 to 5.80.6.
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.80.6/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.80.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 08:18:50 +00:00
dependabot[bot]
8862d44f79
chore(deps): bump anstyle from 1.0.10 to 1.0.11
Bumps [anstyle](https://github.com/rust-cli/anstyle) from 1.0.10 to 1.0.11.
- [Commits](https://github.com/rust-cli/anstyle/compare/v1.0.10...v1.0.11)

---
updated-dependencies:
- dependency-name: anstyle
  dependency-version: 1.0.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 07:48:38 +00:00
dependabot[bot]
1431b54810
chore(deps): bump reqwest from 0.12.18 to 0.12.19
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.18 to 0.12.19.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.18...v0.12.19)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.12.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 07:48:24 +00:00
dependabot[bot]
1050a2ccfa
chore(deps): bump flate2 from 1.1.1 to 1.1.2
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2)

---
updated-dependencies:
- dependency-name: flate2
  dependency-version: 1.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 07:35:51 +00:00
anatawa12
c9dc6f05f8
Merge pull request #2286 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-06-09 05:08:20 +09:00
夜嵐蝶Alma
26e9bb708b chore(l10n): [zh_hant] update locale 2025-06-08 08:03:33 +08:00
github-actions[bot]
661019985b gui v1.1.0-rc.1 2025-06-07 13:19:21 +00:00
anatawa12
536884d107
Merge pull request #2279 from vrc-get/fix-index-collation
fix: different locales can cause a problem in finding a project by path
2025-06-07 22:18:16 +09:00
anatawa12
26ded7aa24
Merge pull request #2282 from vrc-get/improve_import_template_dialog_msg
Improve import template dialog message
2025-06-07 21:41:07 +09:00
Sayamame-beans
262cb4c80c
chore(l10n): [zh_hans] Apply suggestion from code review
Co-authored-by: RingLo_ <63995099+lonelyicer@users.noreply.github.com>
2025-06-07 21:33:33 +09:00
Sayamame-beans
816e7a6516 chore(l10n): [zh_hans] improve import template dialog message 2025-06-07 20:25:56 +09:00
anatawa12
6afc1c3532
Merge pull request #2281 from vrc-get/rmeove-datetime-format-new
fix: error from browser on instantiating Intl.DateTimeFormat
2025-06-07 20:14:55 +09:00
anatawa12
8ebd0ca2f5
fix: error from browser on instantiating Intl.DateTimeFormat 2025-06-07 20:08:11 +09:00
anatawa12
7aa986be92
Merge pull request #2278 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-06-07 19:36:53 +09:00
anatawa12
3c4547e7a7
fix: different locales can cause a problem in finding a project by path 2025-06-07 19:31:11 +09:00
RingLo_
89304565a2 chore(l10n): [zh_Hans] update locale 2025-06-07 18:20:03 +08:00
Sayamame-beans
4c2df92dfe chore(l10n): [en] improve import template dialog message 2025-06-07 18:58:01 +09:00
anatawa12
9a5b4b11e5
Merge pull request #2277 from vrc-get/fix-reordable-list
fix: a reorderable list may become empty even if allowEmpty = false
2025-06-07 18:42:58 +09:00
anatawa12
3c8d230ee1
fix: a reorderable list may become empty even if allowEmpty = false 2025-06-07 18:31:28 +09:00
anatawa12
f0ed11bdf7
Merge pull request #2276 from vrc-get/last-updated-templates
Last updated of templates in templates page
2025-06-07 18:24:14 +09:00
anatawa12
feb3a1f851
docs(changelog-gui): Too Many Open Files on backing up some projects 2025-06-07 18:16:56 +09:00
anatawa12
55ce29edf8
refactor: move last modified to general category 2025-06-07 18:16:38 +09:00
anatawa12
7ad5771d94
feat: show last modified on the template list 2025-06-07 18:16:38 +09:00
anatawa12
89b757b538
refactor: move functions to show date 2025-06-07 18:16:38 +09:00
anatawa12
d9be937118
Merge pull request #2275 from vrc-get/fix-import-same-id-at-once
fix: fix behaviour when we import multiple templates with the same id
2025-06-07 17:51:53 +09:00
anatawa12
5d17ef477c
docs(changelog-gui): Too Many Open Files on backing up some projects 2025-06-07 17:40:39 +09:00
anatawa12
01ba80ddcd
fix: fix behaviour when we import multiple templates with the same id 2025-06-07 17:40:16 +09:00
anatawa12
63fd4ce399
Merge pull request #2274 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-06-07 17:39:18 +09:00
RingLo_
4d956e126e chore(l10n): [zh_Hans] update locale 2025-06-07 15:57:39 +08:00
anatawa12
73aa231482
Merge pull request #2269 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2025-06-07 14:31:56 +09:00
Sayamame-beans
c1a43e42d7 chore(l10n): [ja] update locale 2025-06-07 07:28:28 +09:00
anatawa12
ac70c654e7
Merge pull request #2263 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-06-07 03:56:02 +09:00
JustBuddy
1ab8d878a2
chore(l10n): [de_DE] update locale
Added new template related keys.
2025-06-06 20:43:42 +02:00
github-actions[bot]
23f553451b gui v1.1.0-rc.0 2025-06-06 18:23:49 +00:00
anatawa12
d050341d7d
Merge pull request #2262 from vrc-get/too-many-open-files
fix: prevent Too Many Open Files on backup
2025-06-07 03:22:48 +09:00
anatawa12
13ec305289
docs(changelog-gui): Too Many Open Files on backing up some projects 2025-06-07 03:16:10 +09:00
anatawa12
b2dc8ea1ab
fix: prevent Too Many Open Files on backup 2025-06-07 03:13:24 +09:00
anatawa12
886ce42567
Merge pull request #2261 from vrc-get/templates-fixes
Templates Fixes
2025-06-07 03:02:38 +09:00
anatawa12
b5dd8b2a92
docs(changelog-gui): Add PR Number to the corresponding entry 2025-06-07 02:54:37 +09:00
anatawa12
0640b13cc8
chore: improve text of button to open VCC templates 2025-06-07 02:50:22 +09:00
anatawa12
8b8c7ad132
fix: the template may contain empty package row 2025-06-07 02:48:49 +09:00
anatawa12
99766d08f3
chore: preserve template id for user templates 2025-06-07 02:44:08 +09:00
anatawa12
e24fe409e2
fix: able to import multiple templates with same id 2025-06-07 02:14:46 +09:00
anatawa12
bd8714afd8
Merge pull request #2260 from vrc-get/alcomtemplate-future-extension
feat: allow .alcomtemplate file to have binary data in the future
2025-06-07 00:40:46 +09:00
anatawa12
5f2805b1d7
docs(changelog-gui): Add PR Number to the corresponding entry 2025-06-07 00:31:35 +09:00
anatawa12
85004cb650
feat: allow .alcomtemplate file to have binary data in the future 2025-06-07 00:26:14 +09:00
anatawa12
417c882c5c
Merge pull request #2259 from vrc-get/badge-icon-of-alcomtemplate-for-macos
chore: set badge icon of .alcomtemplate files
2025-06-07 00:12:41 +09:00
anatawa12
77734f76b4
docs(changelog-gui): Add PR Number to corresponding entry 2025-06-06 23:57:02 +09:00
anatawa12
52f72867df
chore: set badge icon of .alcomtemplate files 2025-06-06 23:54:52 +09:00
anatawa12
b023aa67aa
Merge pull request #2226 from Exerea/2221-hover-cursor
fix: add cursor-pointer to clickable UI components for Tailwind CSS v4 compatibility
2025-06-05 23:20:17 +09:00
Exerea
4f8ef9f110 chore: fix cursor disabled styles to use global CSS rules 2025-06-05 22:04:02 +09:00
anatawa12
c51c4cd967
Merge pull request #2258 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-06-05 13:54:08 +09:00
夜嵐蝶Alma
aa9b82c871 chore(l10n): [zh_hant] update locale 2025-06-05 12:02:51 +08:00
github-actions[bot]
cc0c2a373e gui v1.1.0-beta.3 2025-06-04 15:53:06 +00:00
anatawa12
888d16297f
Merge pull request #2257 from vrc-get/improve_ui_text_gap
Improve appearance of last modified info on grid, and Improve UI text gap
2025-06-04 23:52:31 +09:00
Sayamame-beans
49128107e8 docs(changelog): update changelog 2025-06-04 22:20:08 +09:00
Sayamame-beans
93a21025ce chore: improve appearance of last modified info on grid 2025-06-04 22:01:46 +09:00
Sayamame-beans
def057fdb6 chore(l10n): [*] remove ineffective or excessive space 2025-06-04 22:00:32 +09:00
Sayamame-beans
2993149ace chore: improve ui text gap 2025-06-04 21:57:06 +09:00
anatawa12
3181bd4cf3
Merge pull request #2256 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-06-04 20:51:08 +09:00
JustBuddy
2bc0c7f006
chore(l10n): [de_DE] update locale
Added new sorting keys.
2025-06-04 13:40:37 +02:00
Sayamame-beans
9629d87b56
Merge pull request #2255 from vrc-get/update_locale_ja
[ja] update locale / [en] remove space
2025-06-04 19:48:02 +09:00
Sayamame-beans
0babc534a8 chore(l10n): [en] remove space (elements already have some gap) 2025-06-04 19:08:56 +09:00
Sayamame-beans
99598f395c chore(l10n): [ja] update locale 2025-06-04 19:06:17 +09:00
dependabot[bot]
7468933294
Merge pull request #2242 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/radix-ui-ae2fca5f7d 2025-06-03 06:36:02 +00:00
anatawa12
0abc67eb81
Merge pull request #2245 from lonelyicer/feat/grid-view
feat: project grid view
2025-06-03 11:45:39 +09:00
anatawa12
3dae53cdbb
Merge pull request #2254 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-06-03 03:25:05 +09:00
RingLo_
b28f198c56 chore: sort by last modified first 2025-06-03 01:55:17 +08:00
JustBuddy
dbccc6cfd2
chore(l10n): [de_DE] update locale
Added missing keys and refined others.
2025-06-02 18:08:29 +02:00
RingLo_
aeef431428 chore: apply suggestions 2025-06-02 23:59:35 +08:00
dependabot[bot]
b3be48d457
Merge pull request #2235 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-af945e238e 2025-06-02 13:51:14 +00:00
dependabot[bot]
97b312507e
chore(deps-dev): bump @types/react in /vrc-get-gui in the react group
Bumps the react group in /vrc-get-gui with 1 update: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react).


Updates `@types/react` from 19.1.4 to 19.1.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.1.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 13:42:55 +00:00
dependabot[bot]
59f5be7626
chore(deps): bump the radix-ui group in /vrc-get-gui with 12 updates
Bumps the radix-ui group in /vrc-get-gui with 12 updates:

| Package | From | To |
| --- | --- | --- |
| [@radix-ui/react-accordion](https://github.com/radix-ui/primitives) | `1.2.10` | `1.2.11` |
| [@radix-ui/react-checkbox](https://github.com/radix-ui/primitives) | `1.3.1` | `1.3.2` |
| [@radix-ui/react-dialog](https://github.com/radix-ui/primitives) | `1.1.13` | `1.1.14` |
| [@radix-ui/react-dropdown-menu](https://github.com/radix-ui/primitives) | `2.1.14` | `2.1.15` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives) | `2.1.6` | `2.1.7` |
| [@radix-ui/react-progress](https://github.com/radix-ui/primitives) | `1.1.6` | `1.1.7` |
| [@radix-ui/react-radio-group](https://github.com/radix-ui/primitives) | `1.3.6` | `1.3.7` |
| [@radix-ui/react-scroll-area](https://github.com/radix-ui/primitives) | `1.2.8` | `1.2.9` |
| [@radix-ui/react-select](https://github.com/radix-ui/primitives) | `2.2.4` | `2.2.5` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives) | `1.1.6` | `1.1.7` |
| [@radix-ui/react-slot](https://github.com/radix-ui/primitives) | `1.2.2` | `1.2.3` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives) | `1.2.6` | `1.2.7` |


Updates `@radix-ui/react-accordion` from 1.2.10 to 1.2.11
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-checkbox` from 1.3.1 to 1.3.2
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-dialog` from 1.1.13 to 1.1.14
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-dropdown-menu` from 2.1.14 to 2.1.15
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-label` from 2.1.6 to 2.1.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-progress` from 1.1.6 to 1.1.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-radio-group` from 1.3.6 to 1.3.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-scroll-area` from 1.2.8 to 1.2.9
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-select` from 2.2.4 to 2.2.5
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-separator` from 1.1.6 to 1.1.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-slot` from 1.2.2 to 1.2.3
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

Updates `@radix-ui/react-tooltip` from 1.2.6 to 1.2.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/release-process.md)
- [Commits](https://github.com/radix-ui/primitives/commits)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-accordion"
  dependency-version: 1.2.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-checkbox"
  dependency-version: 1.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-dialog"
  dependency-version: 1.1.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-dropdown-menu"
  dependency-version: 2.1.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-label"
  dependency-version: 2.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-progress"
  dependency-version: 1.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-radio-group"
  dependency-version: 1.3.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-scroll-area"
  dependency-version: 1.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-select"
  dependency-version: 2.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-separator"
  dependency-version: 1.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-slot"
  dependency-version: 1.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
- dependency-name: "@radix-ui/react-tooltip"
  dependency-version: 1.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: radix-ui
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 13:40:57 +00:00
dependabot[bot]
0999d8faea
Merge pull request #2237 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-5cf6f5fdfd 2025-06-02 13:38:59 +00:00
anatawa12
6799b0c0ea
Merge pull request #2250 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2025-06-02 22:38:21 +09:00
dependabot[bot]
45f37e04de
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.120.5 to 1.120.13
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.13/packages/react-router)

Updates `@tanstack/router-devtools` from 1.120.6 to 1.120.13
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.13/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.120.5 to 1.120.13
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.13/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.120.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.120.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.120.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 13:29:21 +00:00
anatawa12
8a779f116b
chore(l10n): [ja] update locale
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2025-06-02 22:25:59 +09:00
dependabot[bot]
e38890bf70
Merge pull request #2238 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.79.0 2025-06-02 13:24:31 +00:00
dependabot[bot]
f09a60742f
Merge pull request #2236 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-88da23bb33 2025-06-02 13:23:57 +00:00
dependabot[bot]
ebf4e1f75f
Merge pull request #2239 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-swc-3.10.0 2025-06-02 13:18:11 +00:00
dependabot[bot]
27982ca202
Merge pull request #2240 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tw-animate-css-1.3.3 2025-06-02 13:16:30 +00:00
dependabot[bot]
b94f993ca5
Merge pull request #2241 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/postcss-8.5.4 2025-06-02 13:16:11 +00:00
dependabot[bot]
83b51e862e
Merge pull request #2246 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-18bde24e6c 2025-06-02 13:15:59 +00:00
anatawa12
4cad684232
Merge pull request #2253 from vrc-get/fix-invalid-selection
Fix mesesages when invalid selection
2025-06-02 22:15:07 +09:00
dependabot[bot]
657a132088
Merge pull request #2232 from vrc-get/dependabot/cargo/reqwest-0.12.18 2025-06-02 13:12:52 +00:00
dependabot[bot]
56d3478774
Merge pull request #2247 from vrc-get/dependabot/cargo/clap-74dd1982ef 2025-06-02 13:12:18 +00:00
anatawa12
c3a8ab32ec
chore: log error when selecting project 2025-06-02 22:04:57 +09:00
anatawa12
4eec379ea3
chore: improve error messages on loading UnityProject 2025-06-02 22:02:17 +09:00
anatawa12
0f43972dcc
refactor: incorrect error will be shown when adding a project 2025-06-02 21:58:56 +09:00
anatawa12
db9a136474
fix: incorrect error will be shown when adding a project 2025-06-02 21:58:27 +09:00
Sayamame-beans
22324777ab chore(l10n): [ja] update locale 2025-06-02 21:42:34 +09:00
RingLo_
fcfc79ed14 chore: dont display favorite button when disabled 2025-06-02 18:40:53 +08:00
RingLo_
d4b3d3fc23 chore(l10n): [zh_Hans] update locale 2025-06-02 18:31:54 +08:00
anatawa12
88d8adcd7b
Merge pull request #2249 from vrc-get/no-autocrlf
chore: always use LF as the EOL char
2025-06-02 19:30:04 +09:00
RingLo_
d08b337c5b docs(changelog): projects page grid view 2025-06-02 18:29:07 +08:00
RingLo_
3106912f6b lint(biome): fix import 2025-06-02 18:23:26 +08:00
RingLo_
bdecb54898 lint(biome): fix format 2025-06-02 18:22:14 +08:00
anatawa12
7f6c10425c
chore: always use lf as the EOL char 2025-06-02 19:15:30 +09:00
RingLo_
6c6b18e1db chore: favorite button style tweaks 2025-06-02 18:05:08 +08:00
dependabot[bot]
e310699e1d
chore(deps): bump object from 0.36.7 to 0.37.0
Bumps [object](https://github.com/gimli-rs/object) from 0.36.7 to 0.37.0.
- [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.36.7...0.37.0)

---
updated-dependencies:
- dependency-name: object
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:47:50 +00:00
dependabot[bot]
9b7082acf3
chore(deps): bump the clap group with 2 updates
Bumps the clap group with 2 updates: [clap](https://github.com/clap-rs/clap) and [clap_complete](https://github.com/clap-rs/clap).


Updates `clap` from 4.5.38 to 4.5.39
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.38...clap_complete-v4.5.39)

Updates `clap_complete` from 4.5.50 to 4.5.52
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.50...clap_complete-v4.5.52)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.39
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: clap
- dependency-name: clap_complete
  dependency-version: 4.5.52
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: clap
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:41:02 +00:00
dependabot[bot]
e26cce8cf4
chore(deps): bump the i18next group in /vrc-get-gui with 2 updates
Bumps the i18next group in /vrc-get-gui with 2 updates: [i18next](https://github.com/i18next/i18next) and [react-i18next](https://github.com/i18next/react-i18next).


Updates `i18next` from 25.1.3 to 25.2.1
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v25.1.3...v25.2.1)

Updates `react-i18next` from 15.5.1 to 15.5.2
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v15.5.1...v15.5.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 25.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: i18next
- dependency-name: react-i18next
  dependency-version: 15.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: i18next
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:39:52 +00:00
RingLo_
534110a5be chore: projects page layout tweaks 2025-06-02 17:36:52 +08:00
dependabot[bot]
6901f6efab
chore(deps-dev): bump postcss from 8.5.3 to 8.5.4 in /vrc-get-gui
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.3 to 8.5.4.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.3...8.5.4)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:19:16 +00:00
dependabot[bot]
617f9f3dc2
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react-swc) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react-swc@3.10.0/packages/plugin-react-swc)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-version: 3.10.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:16:23 +00:00
dependabot[bot]
374240b2be
chore(deps-dev): bump tw-animate-css from 1.3.0 to 1.3.3 in /vrc-get-gui
Bumps [tw-animate-css](https://github.com/Wombosvideo/tw-animate-css) from 1.3.0 to 1.3.3.
- [Release notes](https://github.com/Wombosvideo/tw-animate-css/releases)
- [Commits](https://github.com/Wombosvideo/tw-animate-css/compare/v1.3.0...v1.3.3)

---
updated-dependencies:
- dependency-name: tw-animate-css
  dependency-version: 1.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:15:43 +00:00
anatawa12
830e2f868b
Merge pull request #2243 from vrc-get/remove-postcss-from-direct-dependencies
chore(deps): remove postcss from direct dependencies
2025-06-02 18:14:05 +09:00
dependabot[bot]
b1987328c7
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.1.7 to 4.1.8
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.8/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.1.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:06:48 +00:00
RingLo_
adc224723b fix: sorting options locale wrong 2025-06-02 16:56:58 +08:00
RingLo_
577a0c9398 feat: project grid view 2025-06-02 16:45:43 +08:00
anatawa12
d109ddf2a5
Merge pull request #2244 from vrc-get/dependabot-groups
dev: add dependabot groups
2025-06-02 17:35:31 +09:00
anatawa12
6591e35bcf
dev: add dependabot i18next group 2025-06-02 17:34:02 +09:00
anatawa12
a761e8f544
dev: add dependabot clap group 2025-06-02 17:32:29 +09:00
anatawa12
8d3ed1fdef
chore(deps): remove postcss from direct dependencies
Please note that postcss is needed by vite so no lock dependencies are changed
2025-06-02 17:31:09 +09:00
dependabot[bot]
1aaaccda8c
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.76.1 to 5.79.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.79.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.79.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 08:23:48 +00:00
dependabot[bot]
a6ad974881
chore(deps): bump reqwest from 0.12.15 to 0.12.18
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.15 to 0.12.18.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.15...v0.12.18)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.12.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 08:15:18 +00:00
anatawa12
139619dee5
Merge pull request #2229 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-06-02 15:52:42 +09:00
RingLo_
9cf28f1c3e
chore(l10N): [zh_Hans] remove redundant punctuation 2025-06-02 13:57:07 +08:00
RingLo_
62e4b372f0 chore(l10n): [zh_Hans] update locale 2025-06-02 13:34:54 +08:00
anatawa12
19d6c05dc0
Merge pull request #2228 from lonelyicer/feat/update-last-modified-when-open-unity
feat: update last modified when open unity
2025-06-02 12:53:58 +09:00
anatawa12
999c624c6b
Merge pull request #2227 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-06-02 12:50:58 +09:00
RingLo_
e622744c42 lint(biome): fix import 2025-06-02 03:11:56 +08:00
RingLo_
25976f402c docs(changelog): update for #2228 2025-06-02 03:09:58 +08:00
RingLo_
747acff8a5 lint(type): fix import 2025-06-02 03:06:40 +08:00
RingLo_
70b56fea19 lint(biome): fix fmt 2025-06-02 03:02:33 +08:00
RingLo_
905d2312a0 feat: update last modified when open unity 2025-06-02 02:59:58 +08:00
RingLo_
43de48df65 chore(l10n): [zh_Hans] update locale 2025-06-02 01:42:07 +08:00
anatawa12
5ccb54b956
Merge pull request #2225 from vrc-get/broken-project
Improve behavior for broken project
2025-05-31 23:34:16 +09:00
anatawa12
3910faf693
docs(changelog): Improved behavior when the project directory is not a valid project but the directory exists 2025-05-31 23:24:43 +09:00
anatawa12
82ca0820d8
feat: disallow many operations if the directory is not a valid project 2025-05-31 23:21:32 +09:00
anatawa12
de8ba426b7
chore: make detect_project_type return ProjectType 2025-05-31 22:42:12 +09:00
github-actions[bot]
a36598bc7a gui v1.1.0-beta.2 2025-05-27 02:53:00 +00:00
anatawa12
a89f0b1d76
Merge pull request #2209 from vrc-get/fix-frequent-package-update-error-on-windows
fix: failed to restore package that partially failed packages
2025-05-27 11:32:00 +09:00
anatawa12
073c8ebc1a
docs(changelog): Uninstall package is not reverted successfully if removing package is prevented by ERROR_SHARING_VIOLATION 2025-05-27 11:22:37 +09:00
anatawa12
e160a9bfce
Merge pull request #2219 from vrc-get/copy-everything
chore: keep the library directory for copying project
2025-05-26 23:53:44 +09:00
anatawa12
081079117a
docs(changelog-gui): add PR number to Menu option to copy a project 2025-05-26 23:45:10 +09:00
anatawa12
f76cd350fd
chore: keep the library directory for copying project 2025-05-26 23:42:56 +09:00
anatawa12
7b5f16c38b
Merge pull request #2217 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2025-05-26 23:11:49 +09:00
anatawa12
0152adc681
fix: rollback does not work as expected 2025-05-26 23:09:02 +09:00
Sayamame-beans
9c82184983 chore(l10n): [ja] update locale 2025-05-26 21:42:07 +09:00
anatawa12
d50912c9e1
Merge pull request #2216 from vrc-get/migreate-cocoa
chore: migrate cocoa to objc2_foundation
2025-05-26 18:48:15 +09:00
dependabot[bot]
6cfb174995
Merge pull request #2215 from vrc-get/dependabot/cargo/tokio-1.45.1 2025-05-26 09:41:36 +00:00
anatawa12
81d155cb30
chore: migrate cocoa to objc2_foundation 2025-05-26 18:38:57 +09:00
dependabot[bot]
e194f78d55
Merge pull request #2213 from vrc-get/dependabot/cargo/uuid-1.17.0 2025-05-26 08:59:31 +00:00
dependabot[bot]
e86c6ca63a
chore(deps): bump uuid from 1.16.0 to 1.17.0
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 08:39:47 +00:00
dependabot[bot]
869a7043ab
Merge pull request #2212 from vrc-get/dependabot/cargo/tauri-plugin-single-instance-2.2.4 2025-05-26 08:17:09 +00:00
dependabot[bot]
e23399b29a
Merge pull request #2211 from vrc-get/dependabot/cargo/tauri-plugin-dialog-2.2.2 2025-05-26 08:15:32 +00:00
dependabot[bot]
5a1f5b58cd
chore(deps): bump tokio from 1.45.0 to 1.45.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.0 to 1.45.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.45.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.45.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 07:49:12 +00:00
dependabot[bot]
0ea91c8a4b
chore(deps): bump tauri-plugin-single-instance from 2.2.3 to 2.2.4
Bumps [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/log-v2.2.3...opener-v2.2.4)

---
updated-dependencies:
- dependency-name: tauri-plugin-single-instance
  dependency-version: 2.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 07:48:20 +00:00
dependabot[bot]
edbb579a35
chore(deps): bump tauri-plugin-dialog from 2.2.1 to 2.2.2
Bumps [tauri-plugin-dialog](https://github.com/tauri-apps/plugins-workspace) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/os-v2.2.1...log-v2.2.2)

---
updated-dependencies:
- dependency-name: tauri-plugin-dialog
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 07:47:53 +00:00
anatawa12
5bf5fefbd6
Merge pull request #2210 from vrc-get/margin-for-warning
chore: margin end for package changes warnings
2025-05-26 16:36:14 +09:00
anatawa12
ce7e09a667
chore: margin end for package changes warnings 2025-05-26 16:15:45 +09:00
anatawa12
ed983daf2c
fix: failed to restore package that partially failed packages 2025-05-26 16:08:44 +09:00
anatawa12
6531309b9d
Merge pull request #2208 from vrc-get/reinstall-package
feat: reinstall package from menuitem
2025-05-26 15:57:54 +09:00
anatawa12
0cbb35c2ba
docs(changelog): Open changelog, documentation, and reinstall single package from package list 2025-05-26 15:51:05 +09:00
anatawa12
1d60a620ab
feat: reinstall package from menuitem 2025-05-26 15:49:20 +09:00
anatawa12
81b5f48610
Merge pull request #2206 from vrc-get/link-in-update-description
feat: URLs in update description is now actual browser link
2025-05-25 22:59:42 +09:00
anatawa12
7154062948
feat: URLs in update description is now actual browser link 2025-05-25 22:48:43 +09:00
anatawa12
553fa8b972
Merge pull request #2205 from vrc-get/preserve-last-scene-manager-setup
chore: preserve LastSceneManagerSetup.txt in library for backups / copy projects
2025-05-25 22:26:21 +09:00
anatawa12
64e95677f6
docs(changelog-gui): LastSceneManagerSetup.txt in Library directory will be included in backups or copying project 2025-05-25 22:16:04 +09:00
anatawa12
db5ea5e872
chore: preserve LastSceneManagerSetup.txt in library for backups / copy projects 2025-05-25 22:12:35 +09:00
anatawa12
9c11585dc7
Merge pull request #2204 from vrc-get/fix-vcc-template-compatibility
fix: unable to use VCC templates
2025-05-25 22:00:50 +09:00
anatawa12
712cd48287
docs(changelog-gui): add PR number to changelog entry 2025-05-25 21:53:50 +09:00
anatawa12
548c1f4240
fix: unable to use VCC templates 2025-05-25 21:50:44 +09:00
github-actions[bot]
13e729c060 gui v1.1.0-beta.1 2025-05-24 08:57:38 +00:00
anatawa12
5b4eab46f9
Merge pull request #2199 from vrc-get/next-alcom-1.1.0
chore: next version should be 1.1.0
2025-05-24 17:55:46 +09:00
anatawa12
818312c90a
chore: next version should be 1.1.0 2025-05-24 17:46:51 +09:00
github-actions[bot]
94d70aa649 gui v1.0.2-beta.1 2025-05-24 08:25:29 +00:00
anatawa12
f4a0824491
Merge pull request #2198 from vrc-get/notes-on-gui-changelog
ci: change release notes shown on ALCOM to link to changelog
2025-05-24 16:58:34 +09:00
anatawa12
2353dba140
ci: change release notes shown on ALCOM to link to changelog 2025-05-24 16:09:24 +09:00
anatawa12
312b756d2a
Merge pull request #2197 from vrc-get/fix-bulk-update-reset
chore: do not reset package selection after package list update
2025-05-24 15:45:42 +09:00
anatawa12
e038db5c6c
Merge pull request #2196 from vrc-get/fix_l10n
chore(l10n): [en] fix typo
2025-05-24 13:30:11 +09:00
anatawa12
e53438a9d3
Merge pull request #2195 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2025-05-24 13:29:54 +09:00
Sayamame-beans
ab98620524 chore(l10n): [ja] update locale 2025-05-24 13:21:18 +09:00
Sayamame-beans
e10d9ff0db chore(l10n): [en] fix typo 2025-05-24 13:14:43 +09:00
Sayamame-beans
7627a795fe chore(l10n): [ja] update locale 2025-05-24 12:56:23 +09:00
anatawa12
ea99157ab8
chore: do not reset package selection after package list update 2025-05-23 23:49:34 +09:00
anatawa12
cbc42c0bd2
Merge pull request #2190 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-05-22 20:59:41 +09:00
夜嵐蝶Alma
496f6618ab chore(l10n): [zh_hant] update locale 2025-05-22 19:34:15 +08:00
anatawa12
5381f06388
Merge pull request #2189 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-05-22 11:39:22 +09:00
JustBuddy
861ad01b14
chore(l10n): [de_DE] update locale 2025-05-21 21:04:52 +02:00
anatawa12
93037d1479
Merge pull request #2188 from vrc-get/fix-deprecated
fix: deprecated type name
2025-05-21 12:13:56 +09:00
anatawa12
cadb379775
Merge pull request #1586 from vrc-get/flatpak
feat: add flatpak installation of unity hub to default search path
2025-05-21 12:09:19 +09:00
anatawa12
62490077a0
fix: deprecated type name 2025-05-21 12:02:41 +09:00
anatawa12
7ad56dfb0c
docs(changelog-gui): Support for flatpak installation of unity hub 2025-05-21 12:01:47 +09:00
anatawa12
f0c9365209
feat: add flatpak per-user installation of unity hub to default search path 2025-05-21 12:00:30 +09:00
anatawa12
53c7f0a236
fix: typo in flatpak unityhub wrapper path 2025-05-21 11:55:03 +09:00
anatawa12
c65a3a853b
Merge branch 'master' into flatpak 2025-05-21 11:53:34 +09:00
dependabot[bot]
53c99829c4
Merge pull request #2176 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-d7899f1813 2025-05-19 18:06:20 +00:00
dependabot[bot]
26c61bc1a9
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.120.3 to 1.120.5
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.5/packages/react-router)

Updates `@tanstack/router-devtools` from 1.120.3 to 1.120.6
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.6/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.120.3 to 1.120.5
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.120.5/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.120.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-version: 1.120.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.120.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 17:54:11 +00:00
dependabot[bot]
cb1f8c23cb
Merge pull request #2174 from vrc-get/dependabot/cargo/dispatch2-0.3.0 2025-05-19 17:53:00 +00:00
dependabot[bot]
56f7c1aeae
Merge pull request #2175 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-25ad508957 2025-05-19 17:51:28 +00:00
dependabot[bot]
98a6b8c60f
Merge pull request #2177 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-74e340bcc8 2025-05-19 17:50:50 +00:00
dependabot[bot]
465f0cdbbb
Merge pull request #2178 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-25.1.3 2025-05-19 17:50:32 +00:00
dependabot[bot]
7d4bdef61e
Merge pull request #2179 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.511.0 2025-05-19 17:50:18 +00:00
dependabot[bot]
f2f7305ca3
Merge pull request #2180 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.76.1 2025-05-19 17:50:06 +00:00
dependabot[bot]
c42474707b
Merge pull request #2181 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tw-animate-css-1.3.0 2025-05-19 17:49:47 +00:00
anatawa12
20d0691c36
Merge pull request #2187 from vrc-get/show-versions
feat: show request version range in the missing dependencies dialog
2025-05-20 01:01:18 +09:00
anatawa12
dad01fdc7d
docs(changelog-gui): Show the range of requested package in missing dependencies dialog 2025-05-20 00:51:31 +09:00
anatawa12
9476f019b4
feat: show request version range in the missing dependencies dialog 2025-05-20 00:47:20 +09:00
anatawa12
82116993c6
Merge pull request #2185 from vrc-get/exclude-vpm-packages-from-backups
feat: exclude vpm packages from backups
2025-05-20 00:32:40 +09:00
anatawa12
59609a3419
docs(changelog): Option to exclude VPM Packages from backups 2025-05-19 23:59:52 +09:00
anatawa12
a3c4cb2dd3
chore: update description to match changelog 2025-05-19 23:58:56 +09:00
anatawa12
d291cddc9f
feat: exclude vpm packages from backup if the option is enabled 2025-05-19 23:53:53 +09:00
anatawa12
ac393960a9
feat(gui/frontend): set excludeVpmPackagesFromBackup from gui 2025-05-19 23:53:53 +09:00
anatawa12
456a9080a9
feat: add flag to exclude vpm package from backups 2025-05-19 23:53:53 +09:00
anatawa12
b81bc4f394
Merge pull request #2184 from vrc-get/feat-links-for-package
feat: add changelog and documentation link for package list
2025-05-19 23:25:13 +09:00
anatawa12
26069192f0
lint: fix import ordering 2025-05-19 23:14:33 +09:00
anatawa12
3e7b580627
docs(changelog-gui): Open Changelog and documentation from package list 2025-05-19 23:09:51 +09:00
anatawa12
72d6c60b0e
feat: add changelog and documentation link for package list 2025-05-19 22:58:54 +09:00
anatawa12
99d9a7cc16
Merge pull request #2183 from vrc-get/fix-change-unity-version-from-unknown
fix: unable to change the unity version from "unknown"
2025-05-19 21:42:08 +09:00
anatawa12
47c5f5215d
Merge pull request #2182 from vrc-get/multiple-default-locations
feat: remember recent project locations
2025-05-19 21:38:11 +09:00
anatawa12
4e828f2c1e
docs(changelog-gui): Unable to change the unity version from "unknown" if ProjectVersion.txt does not exists 2025-05-19 21:30:37 +09:00
anatawa12
372cde6583
fix: unable to change the unity version from "unknown" 2025-05-19 21:27:25 +09:00
anatawa12
5caea23f4e
docs(changelog-gui): Remember recent project locations 2025-05-19 21:25:47 +09:00
anatawa12
334f1ac290
feat: remember recent project locations 2025-05-19 21:20:05 +09:00
anatawa12
13b25b935f
refactor: normalize base path at first 2025-05-19 17:40:54 +09:00
dependabot[bot]
58df038df2
chore(deps-dev): bump tw-animate-css from 1.2.9 to 1.3.0 in /vrc-get-gui
Bumps [tw-animate-css](https://github.com/Wombosvideo/tw-animate-css) from 1.2.9 to 1.3.0.
- [Release notes](https://github.com/Wombosvideo/tw-animate-css/releases)
- [Commits](https://github.com/Wombosvideo/tw-animate-css/compare/v1.2.9...v1.3.0)

---
updated-dependencies:
- dependency-name: tw-animate-css
  dependency-version: 1.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:25:20 +00:00
dependabot[bot]
3b62014c02
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.76.0 to 5.76.1.
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.76.1/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.76.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:25:13 +00:00
dependabot[bot]
195eb88507
chore(deps): bump lucide-react from 0.510.0 to 0.511.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.510.0 to 0.511.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.511.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 0.511.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:25:06 +00:00
dependabot[bot]
78fb37e997
chore(deps): bump i18next from 25.1.2 to 25.1.3 in /vrc-get-gui
Bumps [i18next](https://github.com/i18next/i18next) from 25.1.2 to 25.1.3.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v25.1.2...v25.1.3)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 25.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:24:55 +00:00
dependabot[bot]
669fd05bf2
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.1.6 to 4.1.7
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.7/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:24:48 +00:00
dependabot[bot]
65e1227eba
chore(deps-dev): bump @types/react-dom
Bumps the react group in /vrc-get-gui with 1 update: [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).


Updates `@types/react-dom` from 19.1.4 to 19.1.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:24:16 +00:00
dependabot[bot]
5be49d3d7e
chore(deps): bump dispatch2 from 0.2.0 to 0.3.0
Bumps [dispatch2](https://github.com/madsmtm/objc2) from 0.2.0 to 0.3.0.
- [Commits](https://github.com/madsmtm/objc2/compare/dispatch2-0.2.0...dispatch2-0.3.0)

---
updated-dependencies:
- dependency-name: dispatch2
  dependency-version: 0.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 07:18:59 +00:00
anatawa12
582efe9b57
Merge pull request #2169 from vrc-get/load-projects-packages-asynchronously
Load projects packages asynchronously
2025-05-17 04:49:07 +09:00
anatawa12
206ca4d9c8
docs: Loading projects / repositories is now asynchronously 2025-05-17 04:40:42 +09:00
anatawa12
ad767a10d7
fix: error spam workaround not working 2025-05-17 04:40:18 +09:00
anatawa12
d51a348240
feat: quick loading of packages 2025-05-17 04:09:22 +09:00
anatawa12
1576290574
Merge pull request #2172 from vrc-get/rust-1.87
Rust 1.87
2025-05-17 03:55:39 +09:00
anatawa12
1fb67a994d
feat(vpm): add function to load local cache only 2025-05-17 03:38:42 +09:00
anatawa12
d6a4c933e5
feat(vpm): add function to load local cache only 2025-05-17 03:38:42 +09:00
anatawa12
9e52ed7c28
chore: store information about unloaded repositories 2025-05-17 03:38:42 +09:00
anatawa12
32e5239662
refactor: use RepoHolder in PackageCollection 2025-05-17 03:38:42 +09:00
anatawa12
77a5abf63b
chore: use extract_if stabilized in 1.87 2025-05-16 23:08:57 +09:00
anatawa12
1acbe99f7c
lint: fix new lints in clippy 1.87 2025-05-16 22:53:01 +09:00
anatawa12
185c676317
chore: use the pair of package name and version as the identifier of package instead of index 2025-05-16 21:08:58 +09:00
anatawa12
99e3aa6c11
feat: add wrapper struct for comparing two versions strictly 2025-05-16 21:06:07 +09:00
anatawa12
655f8a6df2
refactor: add and use common logic for event synced variable 2025-05-15 22:05:49 +09:00
anatawa12
e9c8b6f62f
refactor: use the project path as the identifier of project and remove index/version pairs 2025-05-15 21:28:06 +09:00
anatawa12
78e690a246
fix: reload button does not rotate 2025-05-15 11:59:36 +09:00
anatawa12
06a2d8b795
feat: asynchronously update project information on the DB for quick response 2025-05-15 02:02:28 +09:00
anatawa12
242f4034b9
feat: API to split loading project and updating database 2025-05-15 01:26:47 +09:00
anatawa12
3e1076a833
feat: global lock for litedb lock 2025-05-15 00:08:28 +09:00
anatawa12
91a61fcf48
Merge pull request #2103 from lonelyicer/fix/log-page-auto-scroll
fix: log page auto scroll is broken
2025-05-14 10:46:31 +09:00
anatawa12
5239dd93e1
Merge pull request #2166 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-05-14 10:43:00 +09:00
JustBuddy
11f956cfa4
chore(l10n): [de_DE] update locale for duplication feature 2025-05-13 20:55:41 +02:00
JustBuddy
5c8b3c4ab9
Merge branch 'german-translation' of https://github.com/JustBuddy/vrc-get into german-translation 2025-05-13 20:39:39 +02:00
JustBuddy
a979b96586 chore(l10n): [de_DE] update locale 2025-05-13 20:38:53 +02:00
anatawa12
46693caaba
Merge pull request #2168 from vrc-get/duplicate-project
Duplicate project
2025-05-14 01:21:52 +09:00
anatawa12
2a6990faac
docs(changelog): Menu option to copy a project 2025-05-14 00:09:31 +09:00
anatawa12
01bc1d6614
Merge branch 'master' into duplicate-project 2025-05-14 00:06:24 +09:00
anatawa12
9a08258123
feat: copy a project 2025-05-13 23:14:56 +09:00
JustBuddy
7814ba7566
chore(l10n): [de_DE] update locale 2025-05-13 15:48:28 +02:00
anatawa12
b20ac31a0a
Merge pull request #2162 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-05-13 19:52:54 +09:00
RingLo_
707b778643 Merge branch 'fix/log-page-auto-scroll' of https://github.com/lonelyicer/vrc-get into fix/log-page-auto-scroll 2025-05-13 15:57:21 +08:00
RingLo_
1d4197d6dd lint(biome): fix 2025-05-13 15:57:04 +08:00
RingLo_
a32106c1b8
Merge branch 'master' into fix/log-page-auto-scroll 2025-05-13 15:55:34 +08:00
RingLo_
bfc030d5aa chore: remove requestAnimationFrame() 2025-05-13 15:52:54 +08:00
RingLo_
05e5e8fefd chore(l10n): [zh_Hans] update locale 2025-05-13 15:43:18 +08:00
anatawa12
7604c4b559
refactor: split function for actually do copy and select new name 2025-05-13 14:20:38 +09:00
anatawa12
9c1cd87a33
Merge pull request #2159 from vrc-get/install-dialog-improvements
Install dialog improvements
2025-05-13 13:56:56 +09:00
anatawa12
5ac6c827b1
chore(en): improve message 2025-05-13 13:49:15 +09:00
anatawa12
760938216a
docs(changelog): Warning on upgrading major version or installing incompatible versions 2025-05-13 13:45:47 +09:00
dependabot[bot]
e346444058
Merge pull request #2150 from vrc-get/dependabot/cargo/wmi-0.17.2 2025-05-13 03:39:40 +00:00
dependabot[bot]
38a7eede39
Merge pull request #2139 from vrc-get/dependabot/cargo/nix-0.30.1 2025-05-13 03:37:23 +00:00
anatawa12
793d058167
lint: remove unused use 2025-05-13 12:11:42 +09:00
dependabot[bot]
b624ea119d
Merge pull request #2064 from vrc-get/dependabot/github_actions/actions/create-github-app-token-2 2025-05-13 03:10:48 +00:00
anatawa12
b8bac1bd96
chore: update code for breaking changes 2025-05-13 12:06:20 +09:00
dependabot[bot]
e074030490
Merge pull request #2154 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-25.1.2 2025-05-13 03:06:15 +00:00
dependabot[bot]
c86df50c49
Merge pull request #2069 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-84c24e89c8 2025-05-13 03:02:44 +00:00
dependabot[bot]
841cf2027e
chore(deps): bump actions/create-github-app-token from 1 to 2
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1 to 2.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](https://github.com/actions/create-github-app-token/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 03:01:22 +00:00
dependabot[bot]
0c65e1b156
chore(deps): bump wmi from 0.15.2 to 0.17.2
Bumps [wmi](https://github.com/ohadravid/wmi-rs) from 0.15.2 to 0.17.2.
- [Release notes](https://github.com/ohadravid/wmi-rs/releases)
- [Commits](https://github.com/ohadravid/wmi-rs/compare/v0.15.2...v0.17.2)

---
updated-dependencies:
- dependency-name: wmi
  dependency-version: 0.17.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 02:59:07 +00:00
dependabot[bot]
10b979d8e6
chore(deps): bump nix from 0.29.0 to 0.30.1
Bumps [nix](https://github.com/nix-rust/nix) from 0.29.0 to 0.30.1.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.29.0...v0.30.1)

---
updated-dependencies:
- dependency-name: nix
  dependency-version: 0.30.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 02:58:53 +00:00
dependabot[bot]
2a6a43d8f9
chore(deps): bump i18next from 24.2.3 to 25.1.2 in /vrc-get-gui
Bumps [i18next](https://github.com/i18next/i18next) from 24.2.3 to 25.1.2.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v24.2.3...v25.1.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 25.1.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 02:55:34 +00:00
dependabot[bot]
cee0633cd3
Merge pull request #2095 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/cli-2.5.0 2025-05-13 02:53:43 +00:00
dependabot[bot]
75e52e9f6f
chore(deps-dev): bump the react group in /vrc-get-gui with 2 updates
Bumps the react group in /vrc-get-gui with 2 updates: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).


Updates `@types/react` from 19.0.12 to 19.1.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.0.4 to 19.1.1
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 02:53:18 +00:00
anatawa12
2e485ebca4
Merge pull request #2161 from vrc-get/update-deps
chore(deps): update deps
2025-05-13 02:19:23 +09:00
anatawa12
18091becee
ci: add more licenses 2025-05-13 01:57:33 +09:00
anatawa12
7076dff6ab
build: make error log 2025-05-13 01:57:24 +09:00
anatawa12
b298da3ef4
chore(deps): update deps 2025-05-13 01:27:16 +09:00
anatawa12
19d39ace4a
Merge pull request #2160 from vrc-get/use-oldest-possible-ubuntu
ci: use ubuntu-22.04 for building new ALCOM
2025-05-13 01:20:07 +09:00
anatawa12
bb5d5eb4bb
docs(changelog): Downgraded glibc requirements for linux images 2025-05-13 00:44:38 +09:00
anatawa12
2ae75af409
ci: use ubuntu-22.04 for building new images 2025-05-13 00:30:25 +09:00
anatawa12
26614e052d
fix: CircleAlert may shrink 2025-05-13 00:03:23 +09:00
anatawa12
c6da8808d0
chore: improve warning-foreground 2025-05-12 23:57:10 +09:00
anatawa12
b4a9367faf
chore: delay APPLY button if needs care 2025-05-12 23:53:37 +09:00
anatawa12
49399a8cdc
feat: add DelayedButton 2025-05-12 23:41:58 +09:00
anatawa12
1f89ae2e91
chore: add note if there is conflict or major bump 2025-05-12 22:56:31 +09:00
anatawa12
e21d87e045
chore: bold new version 2025-05-12 16:28:53 +09:00
anatawa12
1e9f756dfb
chore: show differently if there are breaking changes 2025-05-12 16:26:02 +09:00
anatawa12
f5e6160ba2
chore: show reason for installing a package 2025-05-11 21:23:07 +09:00
anatawa12
80c089e9f3
chore: extract component for installing packages 2025-05-11 18:36:59 +09:00
anatawa12
6acdd36e9a
Merge pull request #2148 from vrc-get/use-upstream-tauri
chore(deps): use upstream tauri instead of our fork
2025-05-10 23:28:06 +09:00
anatawa12
bb68caea18
chore(deps): use upstream tauri 2025-05-10 23:08:41 +09:00
anatawa12
096cf176a0
Merge pull request #2134 from JustBuddy/german-translation 2025-05-05 23:03:08 +09:00
JustBuddy
8e0bf595fc
chore(l10n): [de_DE] updated keys for templates 2025-05-04 22:06:19 +02:00
Sayamame-beans
3ae3e8e95f
Merge pull request #2133 from vrc-get/update_locale_ja
chore(l10n): [ja] update locale
2025-05-04 15:24:02 +09:00
Sayamame-beans
ac73e2461d chore(l10n): [ja] update locale 2025-05-03 18:17:59 +09:00
Sayamame-beans
e175eb46ae chore(l10n): [en] update comment 2025-05-03 18:17:32 +09:00
anatawa12
05948227ad
Merge pull request #2129 from vrc-get/remove-template-dialog
feat: show dialog to before removing template
2025-04-30 17:54:42 +09:00
anatawa12
2f8eddbaee
docs(changelog): add PR number to New Project Template System 2025-04-30 17:44:53 +09:00
anatawa12
743601011f
feat: show dialog to before removing template 2025-04-30 16:53:51 +09:00
anatawa12
bd22482e23
Merge pull request #2127 from vrc-get/open-unity-button
feat: prevent double-launching unity by double-clicking open unity button
2025-04-29 18:18:35 +09:00
anatawa12
f7c16d63a9
feat: prevent double-launching unity by double-clicking open unity button 2025-04-29 17:57:45 +09:00
anatawa12
e9f9200790
Merge pull request #2125 from vrc-get/fix-unknown-command-on-deep-link
fix: unexpected "Unknown command" error on deeplink on windows
2025-04-29 16:56:35 +09:00
anatawa12
df2491dd58
docs(changelog): add PR number to New Project Template System 2025-04-29 16:47:55 +09:00
anatawa12
e78d483081
fix: unexpected "Unknown command" error on deeplink on windows 2025-04-29 16:43:27 +09:00
anatawa12
7ba79f6355
Merge pull request #2124 from vrc-get/fix-defanct-and-activity
fix unity behavior on linux and macOS
2025-04-29 03:52:35 +09:00
anatawa12
87f626d276
docs(changelog): Improves launching unity behavior 2025-04-29 03:41:24 +09:00
anatawa12
88c783b00b
chore: return projectOpenUnity early to show launching toast quickly 2025-04-29 03:27:41 +09:00
anatawa12
e4f9f69921
fix: linux build error 2025-04-29 03:17:12 +09:00
anatawa12
1ac5ea7cf9
feat: use NSWorkspace openApplicationAtURL: for launching unity 2025-04-29 02:58:32 +09:00
anatawa12
ca5e8221ed
fix: unity exit code is not read so remain as defunct 2025-04-29 00:06:10 +09:00
anatawa12
21d80d36bf
Merge pull request #2120 from vrc-get/remove-io-traits
Remove io traits
2025-04-28 21:00:07 +09:00
anatawa12
3812f077ec
refactor: remove EnvironmentIo 2025-04-28 20:22:30 +09:00
anatawa12
62007e4e0b
refactor: remove ProjectIo trait 2025-04-28 20:01:12 +09:00
anatawa12
1bf81a3b6a
chore: use the real file system for testing 2025-04-28 18:30:27 +09:00
anatawa12
2d080204ac
chore: make tokio mandatory dependency 2025-04-28 18:06:39 +09:00
anatawa12
452732482b
Merge pull request #2114 from lonelyicer/fix/templates-path-not-exists
fix: template_dir doesn't exists
2025-04-28 17:38:42 +09:00
RingLo_
233447d8a8 docs(changelog): fix issue that directory doesn't exists 2025-04-28 16:30:25 +08:00
RingLo_
08a7aa9c05
chore: direct use create_dir_all
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-04-28 16:26:55 +08:00
RingLo_
35dbee86e0 fix: template_dir doesn't exists 2025-04-28 16:17:56 +08:00
anatawa12
6d50210516
Merge pull request #2105 from vrc-get/new-templates
New Template System
2025-04-28 15:18:50 +09:00
anatawa12
68be496db7
chore: rename packages => resources 2025-04-28 15:08:24 +09:00
anatawa12
af02ba0f24
docs(changelog): New Project Template System 2025-04-27 23:42:19 +09:00
anatawa12
abb83e3ec6
fix: semantic conflict 2025-04-27 23:24:22 +09:00
anatawa12
f769ab4aa5
Merge branch 'master' into new-templates 2025-04-27 23:14:27 +09:00
anatawa12
32fe1666ab
Merge pull request #2106 from vrc-get/unity-2018-support
Unity 2018, 2017 and older support
2025-04-27 23:13:27 +09:00
anatawa12
311c884379
docs(changelog): Support for Projects with Unity 2018 or older 2025-04-27 19:28:45 +09:00
anatawa12
d1d30875b9
feat: disable Manage button for unity 2017 or older 2025-04-27 19:19:47 +09:00
anatawa12
bf608cf145
feat: allow adding projects w/o unity revision 2025-04-27 18:51:06 +09:00
anatawa12
7c59429ded
chore: make ProjectSettings/ProjectVersion.txt required to load a unity project 2025-04-27 18:32:20 +09:00
anatawa12
eab622a628
lint: fix unused_variables on non-mac 2025-04-27 02:42:45 +09:00
anatawa12
b718283ae4
feat: remove template 2025-04-27 02:39:09 +09:00
anatawa12
6dd00eb732
feat: importing .alcomtemplate file 2025-04-27 02:39:09 +09:00
anatawa12
9cdb3c98fa
feat: define .alcomtemplate content type 2025-04-26 23:55:33 +09:00
anatawa12
db11dd504f
feat: create / edit templates 2025-04-26 05:42:24 +09:00
anatawa12
511c1bfcc0
chore: remove AlcomTemplate (de)serialize trait impl 2025-04-26 05:35:07 +09:00
anatawa12
c787fab56e
feat: open/export template 2025-04-26 00:40:18 +09:00
anatawa12
24e701a040
chore: rename directory for project templates 2025-04-25 22:58:40 +09:00
anatawa12
b91bdb92c1
feat: templates page 2025-04-25 03:18:03 +09:00
anatawa12
7148d8e193
Merge pull request #2086 from vrc-get/patch-1592
chore(l10n): [*] remove tail period of dialog header
2025-04-25 00:39:44 +09:00
anatawa12
5488f02f8c
fix: type of updateDate is not correct 2025-04-24 01:04:51 +09:00
anatawa12
dc9b996a66
fix: unavailable templates can be selected 2025-04-24 01:00:35 +09:00
anatawa12
be52775aa8
feat: reimplement project creation with new template system 2025-04-24 00:23:23 +09:00
RingLo_
4bd49c4fdf lint(biome): fix 2025-04-23 21:12:27 +08:00
RingLo_
cfc481c689 chore: don't nest requestAnimationFrame 2025-04-23 21:11:13 +08:00
anatawa12
1c171d2fb9
chore: remove resolving project from template generation 2025-04-23 21:25:46 +09:00
RingLo_
3d81b4b37f lint(biome): fix 2025-04-23 20:08:05 +08:00
RingLo_
ec7eddfe4b chore: try don't use useCallback 2025-04-23 20:06:30 +08:00
RingLo_
242beba95f lint(biome): fix again about logsShown 2025-04-23 19:46:08 +08:00
anatawa12
488d0512f0
fix: project name is not updated properly 2025-04-23 20:40:39 +09:00
RingLo_
e467f55ab0 lint(biome): try to fix 2025-04-23 19:38:51 +08:00
RingLo_
1fe929b411 fix: log page auto scroll is broken 2025-04-23 19:09:34 +08:00
anatawa12
74772f9794
feat: creating project based on template 2025-04-22 01:32:02 +09:00
dependabot[bot]
6e331f7d90
chore(deps-dev): bump @tauri-apps/cli in /vrc-get-gui
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 2.3.1 to 2.5.0.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.3.1...@tauri-apps/cli-v2.5.0)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-version: 2.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 08:27:47 +00:00
anatawa12
e08971ead7
chore: loading other repositories 2025-04-20 21:12:31 +09:00
anatawa12
2f1ce88328
chore: reserve id prefix 2025-04-20 17:19:19 +09:00
anatawa12
5f847201b8
feat: loading templates 2025-04-19 23:26:27 +09:00
anatawa12
f0478668b3
feat: alcomtemplate file format 2025-04-18 20:41:02 +09:00
Sayamame-beans
bbfd8b877a chore(l10n): [*] remove tail period of dialog header 2025-04-13 16:33:18 +09:00
dependabot[bot]
b772cff3ee
Merge pull request #2060 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-5c92e243a5 2025-04-01 07:48:44 +00:00
dependabot[bot]
403550714f
chore(deps): bump the react group across 1 directory with 3 updates
Bumps the react group with 3 updates in the /vrc-get-gui directory: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.0.0 to 19.1.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.0/packages/react)

Updates `@types/react` from 19.0.10 to 19.0.12
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.0.0 to 19.1.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.0/packages/react-dom)

Updates `@types/react` from 19.0.10 to 19.0.12
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.0.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.0.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 05:21:23 +00:00
anatawa12
bf2327a1d3
Merge pull request #2059 from vrc-get/rmeove-overrides
chore(deps): remove overrides
2025-04-01 14:20:02 +09:00
anatawa12
a586339c94
chore(deps): remove overrides 2025-04-01 14:08:48 +09:00
anatawa12
8d951537c9
Merge pull request #2047 from CirnoV/locale/ko-KR
chore(I10n): [ko_KR] update locale
2025-04-01 13:57:04 +09:00
dependabot[bot]
0436ac1df9
Merge pull request #2035 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vitejs/plugin-react-swc-3.8.1 2025-04-01 04:55:14 +00:00
dependabot[bot]
3278330e17
Merge pull request #2030 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tailwindcss-76dbe18d7c 2025-04-01 04:53:23 +00:00
dependabot[bot]
6016043a51
Merge pull request #2026 from vrc-get/dependabot/cargo/windows-0.61.1 2025-04-01 04:50:50 +00:00
dependabot[bot]
1073310bfa
chore(deps): bump windows from 0.60.0 to 0.61.1
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.60.0 to 0.61.1.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

---
updated-dependencies:
- dependency-name: windows
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 03:11:41 +00:00
anatawa12
3d33b85265
Merge pull request #2056 from vrc-get/update-deps
chore(deps): bump deps
2025-04-01 12:10:22 +09:00
anatawa12
44e66119bf
chore: downgrade tauri cli 2025-04-01 11:53:38 +09:00
anatawa12
3ab8b9cc88
chore(deps): bump deps 2025-04-01 01:02:31 +09:00
dependabot[bot]
2cc1bec734
chore(deps-dev): bump @tailwindcss/vite
Bumps the tailwindcss group in /vrc-get-gui with 1 update: [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite).


Updates `@tailwindcss/vite` from 4.0.14 to 4.0.15
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.15/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: tailwindcss
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 07:41:29 +00:00
anatawa12
d268d19a82
Merge pull request #2048 from vrc-get/fix-remove-repository
fix: unable to remove repository
2025-03-30 21:02:46 +09:00
anatawa12
ca90634b05
fix: unable to remove repository 2025-03-30 20:51:26 +09:00
CirnoV
8b2ef681bd chore(I10n): [ko_KR] update locale 2025-03-30 17:01:20 +09:00
anatawa12
3ee5f065ea
Merge pull request #2045 from vrc-get/fix-layout-shift-on-select-package
fix: layout shift on select package on manage packages card
2025-03-30 01:44:19 +09:00
anatawa12
4122def194
docs(changelog-gui): Layout shift on select package 2025-03-30 01:36:16 +09:00
anatawa12
12d2f5bffa
fix: layout shift on select package on manage packages card 2025-03-30 01:30:50 +09:00
anatawa12
bbf038341f
Merge pull request #2044 from vrc-get/remove-unnecessaery-version-compare-logic
chore: remove unnecessary special handling for unity 6 implemented before Unity 6000 release
2025-03-30 01:25:29 +09:00
anatawa12
56f66c6c02
chore: remove unnecessary special handling for unity 6 implemented before Unity 6000 release 2025-03-30 01:14:09 +09:00
anatawa12
b9bca121ba
Merge pull request #2043 from vrc-get/tw-animate-css
several frontend small migrations
2025-03-29 01:57:48 +09:00
anatawa12
0f89560aa5
Merge pull request #2042 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-03-29 01:50:59 +09:00
anatawa12
ff895a933f
fix: show dialog from center 2025-03-29 01:48:08 +09:00
anatawa12
6654f6c97b
chore: remove forwardRef 2025-03-29 01:23:30 +09:00
anatawa12
20107290f0
chore: leave config blank 2025-03-29 00:31:42 +09:00
anatawa12
1b25296cca
chore: migrate to tw-animate-css 2025-03-29 00:17:11 +09:00
夜嵐蝶Alma
dfb7d0aba8 chore(l10n): [zh_hant] update locale 2025-03-27 00:04:16 +08:00
anatawa12
2187a166bd
Merge pull request #2041 from vrc-get/error-with-missing-litedb-file
fix: error if there is no vcc.liteDb file
2025-03-26 22:15:29 +09:00
anatawa12
e2849f58b7
Merge pull request #2040 from vrc-get/query-refactor
Frontend refactors: useMutatuion, react-call-like dialog, dialog close animation
2025-03-26 22:09:29 +09:00
anatawa12
2e70f6c1e1
docs(changelog-gui): add PR number to Changed how we read VCC's project information 2025-03-26 22:08:36 +09:00
anatawa12
512b57f683
fix: error if there is no vcc.liteDb file 2025-03-26 22:03:56 +09:00
anatawa12
42750af9a2
Merge pull request #2036 from guraril/fix-wrong-filename
fix: wrong litedb filename
2025-03-26 18:45:14 +09:00
guraril
e084afbcd6
docs(changelog-gui): add pr number 2025-03-26 10:00:21 +09:00
anatawa12
a147aed952
Merge pull request #2021 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale
2025-03-26 03:24:38 +09:00
JustBuddy
be9293685c
chore(l10n): [de_DE] updated keys 2025-03-25 18:57:14 +01:00
JustBuddy
4a693272d8
chore(l10n): [de_DE] updated key 2025-03-25 18:55:28 +01:00
anatawa12
0a88fcf6f4
Merge pull request #2038 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2025-03-25 21:35:07 +09:00
anatawa12
d91825412c
Merge pull request #2025 from Spokeek/french-translation
Updated french translation 1.0.2-beta.0
2025-03-25 21:34:09 +09:00
RingLo_
2028cad2b5 chore(l10n): [zh_Hans] update locale 2025-03-25 15:41:20 +08:00
Spokeek
e9411cba36
updated fr translations 2025-03-24 18:16:45 +01:00
Spokeek
f7cfb0fa88
Updated french translation 1.0.2-beta.0 2025-03-24 18:08:26 +01:00
guraril
9731cba4f6
fix: wrong litedb filename 2025-03-25 00:33:00 +09:00
anatawa12
9522c032a7
refactor: use useQuery and useMutation in common setting parts 2025-03-25 00:18:31 +09:00
anatawa12
1d4db617d6
refactor: use useQuery and useMutation in logs page 2025-03-24 23:53:01 +09:00
anatawa12
859c3fb47c
chore: allow not using useCallback in useTauriListen 2025-03-24 23:33:35 +09:00
anatawa12
683ca61c65
refactor: use useQuery and useMutation in manage project page (2) 2025-03-24 23:29:09 +09:00
anatawa12
df9b3bf914
refactor: better? applyChanges 2025-03-24 22:29:18 +09:00
anatawa12
2779ec2cd9
refactor: add projectPath to parameter for applyChanges 2025-03-24 19:55:30 +09:00
Buddy
9592327230
Merge branch 'vrc-get:master' into german-translation 2025-03-24 08:23:39 +01:00
dependabot[bot]
019586d515
chore(deps-dev): bump @vitejs/plugin-react-swc in /vrc-get-gui
Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/vitejs/vite-plugin-react-swc/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react-swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react-swc/compare/v3.8.0...v3.8.1)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react-swc"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 07:18:19 +00:00
anatawa12
b46987fa3c
Merge pull request #2024 from vrc-get/rephrase_added_in_2020_and_update_l10n_ja
Rephrase button text added in #2020 and Update locale for ja
2025-03-24 09:42:37 +09:00
anatawa12
3461ed3003
refactor: change parameters for applyChanges 2025-03-24 03:09:50 +09:00
anatawa12
0ff000c01a
refactor: use useQuery and useMutation in manage project page (2) 2025-03-24 02:21:56 +09:00
anatawa12
5e69605d23
refactor: use useQuery and useMutation in user package list 2025-03-24 01:36:34 +09:00
anatawa12
62ceca6ee5
refactor: use the new dialog in repository list page 2025-03-24 01:26:14 +09:00
anatawa12
f91c92eeec
refactor: use useQuery and useMutation in repository list page 2025-03-24 00:06:37 +09:00
anatawa12
67f64e1401
refactor: use useQuery and useMutation in project list page 2025-03-23 23:35:06 +09:00
anatawa12
57dddf7a45
refactor: use the new dialog in project list window 2025-03-23 22:34:34 +09:00
Sayamame-beans
9d532e4d67
chore(l10n): Apply suggestions from code review
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-03-23 21:21:40 +09:00
Sayamame-beans
5db7938fc4 chore(l10n): rephrase with suggested in code review 2025-03-23 19:22:48 +09:00
anatawa12
16c52e717e
refactor: use the new dialog manage project (1) 2025-03-23 02:34:23 +09:00
anatawa12
784854ec47
refactor: use useSuspenseQuery in settings page 2025-03-23 01:28:10 +09:00
anatawa12
564195d4ca
fix(gui/ui): file name on ui should not be upper cased 2025-03-23 01:09:50 +09:00
anatawa12
2be89423b0
refactor: use useMutation in settings page 2025-03-23 00:49:50 +09:00
anatawa12
c3df71d8cb
chore: remove useFilePickerFunction 2025-03-22 23:06:04 +09:00
Sayamame-beans
082c7d1ba0 chore(l10n): [ja] update locale 2025-03-22 03:03:46 +09:00
Sayamame-beans
f6607ea187 chore(frontend): rephrase button text added in #2020 2025-03-22 03:03:08 +09:00
anatawa12
070dd00875
refactor: use the new dialog for unity args 2025-03-22 02:38:14 +09:00
anatawa12
44ea9c344a
refactor: use the new dialog to check for updates 2025-03-22 02:31:43 +09:00
anatawa12
c61b8ba08f
refactor: rename remove-project.tsx => RemoveProjectDialog.tsx 2025-03-22 02:19:44 +09:00
anatawa12
00331e8aa1
refactor: use new dialog for removing project 2025-03-22 02:17:29 +09:00
anatawa12
0304a76f27
refactor: rename backup-project.tsx => BackupProjectDialog.tsx 2025-03-22 01:44:36 +09:00
anatawa12
b38703a9c5
refactor: use the new dialog api with backing-up projects 2025-03-22 01:30:55 +09:00
anatawa12
6bd2c43a59
dev: register useEffectEvent result as stable 2025-03-22 01:21:18 +09:00
anatawa12
f54572dc2e
chore: reimplement unity migration with new dialog api 2025-03-22 01:21:05 +09:00
anatawa12
076ac96bf3
chore: create DialogContent element in dialog.tsx 2025-03-22 00:21:12 +09:00
anatawa12
dfcf9feb71
feat: errors and dispose for dialog context 2025-03-21 23:42:32 +09:00
anatawa12
63ec14a5dc
feat: add polyfills for Symbol.dispose 2025-03-21 23:41:23 +09:00
anatawa12
636bf97913
refactor: expose global queryClient 2025-03-21 23:41:13 +09:00
anatawa12
5cfcd093f4
chore: remove state from dialog 2025-03-21 22:04:33 +09:00
anatawa12
d46093ed8f
refactor: rename use-open-unity.tsx -> open-unity.tsx 2025-03-21 20:35:22 +09:00
anatawa12
48c049173d
refactor: use the new dialog API for opening unity 2025-03-21 20:33:55 +09:00
anatawa12
b451e70a89
refactor: use new dialog API for UnitySelectorDialog 2025-03-21 19:50:20 +09:00
anatawa12
e6f2349e35
refactor: move unity-selector-dialog.tsx 2025-03-21 19:49:25 +09:00
anatawa12
93f254b6da
Merge pull request #2023 from vrc-get/bump-litedb
chore(deps): bunp litedb crate
2025-03-21 13:56:56 +09:00
anatawa12
d7ce31eb97
feat(gui/internal): add helper for managing dialog 2025-03-21 13:51:17 +09:00
anatawa12
118ba7aa61
chore(deps): bunp litedb crate 2025-03-20 23:30:37 +09:00
anatawa12
84ce6022d9
refactor: unify return type of useUnitySelectorDialog 2025-03-19 23:33:20 +09:00
JustBuddy
490d69bdb8
chore(l10n): [de_DE] update locale 2025-03-18 18:42:50 +01:00
anatawa12
c7f9e023f9
refactor: use useMutation for removing projects 2025-03-19 00:26:35 +09:00
anatawa12
912e10828a
refactor: move up createProject related dialog and others 2025-03-19 00:00:50 +09:00
anatawa12
e49814635f
refactor: use useQuery and useMutation for project sorting 2025-03-18 23:57:14 +09:00
anatawa12
001ab7b2d3
Merge pull request #2020 from vrc-get/toggle-show-prerelease-project-page
Toggle show prerelease from project page
2025-03-18 23:07:56 +09:00
dependabot[bot]
67fc71db83
Merge pull request #2019 from vrc-get/dependabot/cargo/zip-2.4.1 2025-03-18 14:07:19 +00:00
anatawa12
aaf3cf1ecf
docs(changelog-gui): You now can toggle "Show Prerelease Packages" from Manage Project page 2025-03-18 23:00:30 +09:00
anatawa12
659ff4b6d4
chore: toggle show prerelease packages from manage project page 2025-03-18 19:39:15 +09:00
anatawa12
0f37b6e81e
chore: align style for dropdown checkbox with normal checkbox 2025-03-18 19:21:30 +09:00
dependabot[bot]
c436fdae5f
chore(deps): bump zip from 2.2.3 to 2.4.1
Bumps [zip](https://github.com/zip-rs/zip2) from 2.2.3 to 2.4.1.
- [Release notes](https://github.com/zip-rs/zip2/releases)
- [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zip-rs/zip2/compare/v2.2.3...v2.4.1)

---
updated-dependencies:
- dependency-name: zip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:12:10 +00:00
anatawa12
b36ab8d8ba
Merge pull request #2018 from vrc-get/update-deps
feat: select multiple folders for adding project / user packages
2025-03-18 01:15:21 +09:00
anatawa12
04d23466b9
docs(changelog): You now can select multiple folders at once to adding project 2025-03-18 01:05:16 +09:00
anatawa12
8f77aac200
dev: improve HMR behavior 2025-03-18 00:58:10 +09:00
anatawa12
aa124513bc
feat: select multiple folders for adding project / user packages 2025-03-18 00:58:08 +09:00
dependabot[bot]
e5bb241a16
Merge pull request #1978 from vrc-get/dependabot/cargo/serde-1.0.219 2025-03-17 15:56:47 +00:00
dependabot[bot]
b0695baf1e
chore(deps): bump serde from 1.0.218 to 1.0.219
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.218 to 1.0.219.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.218...v1.0.219)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 15:44:10 +00:00
dependabot[bot]
c44d2c1636
Merge pull request #2001 from vrc-get/dependabot/cargo/uuid-1.16.0 2025-03-17 15:39:48 +00:00
dependabot[bot]
036183b594
Merge pull request #2007 from vrc-get/dependabot/cargo/indexmap-2.8.0 2025-03-17 15:16:55 +00:00
dependabot[bot]
6064a6d915
Merge pull request #2014 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack/react-query-5.68.0 2025-03-17 15:14:51 +00:00
dependabot[bot]
a3437fbb59
chore(deps): bump indexmap from 2.7.1 to 2.8.0
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.7.1 to 2.8.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.7.1...2.8.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 15:02:13 +00:00
dependabot[bot]
e0c8294966
Merge pull request #2010 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/vite-6.2.2 2025-03-17 15:00:21 +00:00
dependabot[bot]
222bf352d4
chore(deps): bump @tanstack/react-query in /vrc-get-gui
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.66.11 to 5.68.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.68.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 15:00:00 +00:00
dependabot[bot]
b0e5e9fff6
Merge pull request #2008 from vrc-get/dependabot/cargo/clap-4.5.32 2025-03-17 14:45:04 +00:00
dependabot[bot]
12c299481a
Merge pull request #2006 from vrc-get/dependabot/cargo/env_logger-0.11.7 2025-03-17 14:44:30 +00:00
dependabot[bot]
88660120e6
Merge pull request #2009 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.482.0 2025-03-17 14:44:14 +00:00
dependabot[bot]
9ac624f2ce
Merge pull request #2013 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-24.2.3 2025-03-17 14:43:49 +00:00
dependabot[bot]
ae5870717e
chore(deps-dev): bump vite from 6.2.0 to 6.2.2 in /vrc-get-gui
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.0 to 6.2.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 14:43:06 +00:00
dependabot[bot]
c2d3d3cebc
Merge pull request #2005 from vrc-get/dependabot/cargo/tauri-plugin-updater-2.6.1 2025-03-17 14:42:10 +00:00
dependabot[bot]
b322218bb8
Merge pull request #2004 from vrc-get/dependabot/cargo/reqwest-0.12.14 2025-03-17 14:41:44 +00:00
dependabot[bot]
94276bce04
Merge pull request #2003 from vrc-get/dependabot/cargo/tokio-util-0.7.14 2025-03-17 14:39:52 +00:00
dependabot[bot]
9b4535778a
Merge pull request #2002 from vrc-get/dependabot/cargo/tokio-1.44.1 2025-03-17 14:39:39 +00:00
dependabot[bot]
4dad028eda
Merge pull request #1999 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/babel/runtime-7.26.10 2025-03-17 14:36:44 +00:00
dependabot[bot]
fa4321a773
Merge pull request #1980 from vrc-get/dependabot/cargo/serde_repr-0.1.20 2025-03-17 14:36:26 +00:00
dependabot[bot]
c5bff9339f
Merge pull request #1979 from vrc-get/dependabot/cargo/serde_json-1.0.140 2025-03-17 14:35:40 +00:00
dependabot[bot]
e1f1570314
Merge pull request #1976 from vrc-get/dependabot/cargo/either-1.15.0 2025-03-17 14:34:57 +00:00
dependabot[bot]
a8d2af33ef
Merge pull request #2017 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tanstack-router-7a45acca97 2025-03-17 14:33:57 +00:00
dependabot[bot]
4638a12f6d
chore(deps): bump the tanstack-router group
Bumps the tanstack-router group in /vrc-get-gui with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin).


Updates `@tanstack/react-router` from 1.112.13 to 1.114.23
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.114.23/packages/react-router)

Updates `@tanstack/router-devtools` from 1.112.13 to 1.114.23
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.114.23/packages/router-devtools)

Updates `@tanstack/router-plugin` from 1.112.13 to 1.114.23
- [Release notes](https://github.com/TanStack/router/releases)
- [Commits](https://github.com/TanStack/router/commits/v1.114.23/packages/router-plugin)

---
updated-dependencies:
- dependency-name: "@tanstack/react-router"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-devtools"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
- dependency-name: "@tanstack/router-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: tanstack-router
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 08:56:47 +00:00
anatawa12
5e04e688a0
Merge pull request #2016 from vrc-get/dependabot-grouping
chore: group dependabot updates for tanstack router and tailwindcss
2025-03-17 17:38:43 +09:00
anatawa12
77064e304a
chore: group dependabot updates for tanstack router and tailwindcss 2025-03-17 17:28:12 +09:00
dependabot[bot]
f36b2c9606
chore(deps): bump i18next from 24.2.2 to 24.2.3 in /vrc-get-gui
Bumps [i18next](https://github.com/i18next/i18next) from 24.2.2 to 24.2.3.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v24.2.2...v24.2.3)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:33:37 +00:00
dependabot[bot]
4e5b12b84a
chore(deps): bump lucide-react from 0.477.0 to 0.482.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.477.0 to 0.482.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.482.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:33:01 +00:00
dependabot[bot]
a00d581ace
chore(deps): bump clap from 4.5.31 to 4.5.32
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.31 to 4.5.32.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.31...clap_complete-v4.5.32)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:05:47 +00:00
dependabot[bot]
4140fe83f0
chore(deps): bump env_logger from 0.11.6 to 0.11.7
Bumps [env_logger](https://github.com/rust-cli/env_logger) from 0.11.6 to 0.11.7.
- [Release notes](https://github.com/rust-cli/env_logger/releases)
- [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-cli/env_logger/compare/v0.11.6...v0.11.7)

---
updated-dependencies:
- dependency-name: env_logger
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:05:19 +00:00
dependabot[bot]
f7a3b79dfe
chore(deps): bump tauri-plugin-updater from 2.5.1 to 2.6.1
Bumps [tauri-plugin-updater](https://github.com/tauri-apps/plugins-workspace) from 2.5.1 to 2.6.1.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/updater-v2.5.1...updater-v2.6.1)

---
updated-dependencies:
- dependency-name: tauri-plugin-updater
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:04:58 +00:00
dependabot[bot]
c7c608db81
chore(deps): bump reqwest from 0.12.12 to 0.12.14
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.12 to 0.12.14.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/v0.12.14/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.12...v0.12.14)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:04:36 +00:00
dependabot[bot]
8accf74b81
chore(deps): bump tokio-util from 0.7.13 to 0.7.14
Bumps [tokio-util](https://github.com/tokio-rs/tokio) from 0.7.13 to 0.7.14.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.13...tokio-util-0.7.14)

---
updated-dependencies:
- dependency-name: tokio-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:04:22 +00:00
dependabot[bot]
de02d36bbe
chore(deps): bump tokio from 1.43.0 to 1.44.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.43.0 to 1.44.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.43.0...tokio-1.44.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:04:09 +00:00
dependabot[bot]
cbed8fbbb0
chore(deps): bump uuid from 1.15.1 to 1.16.0
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.15.1 to 1.16.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.15.1...v1.16.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 07:03:55 +00:00
dependabot[bot]
c75ca2f36b
chore(deps): bump serde_repr from 0.1.19 to 0.1.20
Bumps [serde_repr](https://github.com/dtolnay/serde-repr) from 0.1.19 to 0.1.20.
- [Release notes](https://github.com/dtolnay/serde-repr/releases)
- [Commits](https://github.com/dtolnay/serde-repr/compare/0.1.19...0.1.20)

---
updated-dependencies:
- dependency-name: serde_repr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 05:09:31 +00:00
anatawa12
1a12d13ae2
Merge pull request #1997 from vrc-get/use-newer-litedb
feat: use newer litedb crate
2025-03-17 14:05:54 +09:00
anatawa12
edbc3fb007
Merge pull request #2000 from vrc-get/migrate-to-vite
chore(deps): rmeove tailwindcss from direct dev dependencies
2025-03-17 13:55:22 +09:00
anatawa12
9f68d06816
chore(deps): rmeove tailwindcss from direct dev dependencies 2025-03-17 13:39:52 +09:00
anatawa12
18b51e4cce
fix(windows): error for windos build 2025-03-17 13:37:53 +09:00
dependabot[bot]
1c1c7b3a9d
chore(deps): bump @babel/runtime from 7.26.9 to 7.26.10 in /vrc-get-gui
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.26.9 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-16 20:54:19 +00:00
anatawa12
beaa869300
Merge pull request #1998 from vrc-get/migrate-to-vite
chore: use @tailwindcss/vite
2025-03-17 05:53:19 +09:00
anatawa12
6eec60e228
fix(windows): error for windos build 2025-03-17 05:50:29 +09:00
anatawa12
e82a54000f
chore: use @tailwindcss/vite 2025-03-17 05:38:57 +09:00
anatawa12
02dff02526
docs(changelog): replace PR number for Changed how we read VCC's project information 2025-03-17 05:29:12 +09:00
anatawa12
35623e4d3a
fix: missing cfg 2025-03-17 05:27:21 +09:00
anatawa12
d5da94a36d
feat: use newer litedb crate 2025-03-17 05:21:58 +09:00
anatawa12
077db1fed7
Merge pull request #1991 from UNIASCEND/fix-text-style
fix(gui): text style for "remove project"
2025-03-12 17:40:47 +09:00
uniascend
f18d7f6194 fix: text style for "remove project" 2025-03-12 01:57:19 +09:00
anatawa12
b72cb74359
Merge pull request #1989 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-03-10 21:07:04 +09:00
夜嵐蝶Alma
a752b3dcd4 chore(l10n): [zh_hant] update locale 2025-03-10 16:30:12 +08:00
dependabot[bot]
2e700bf40e
chore(deps): bump serde_json from 1.0.139 to 1.0.140
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.139 to 1.0.140.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.139...v1.0.140)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 07:14:14 +00:00
dependabot[bot]
765892922a
chore(deps): bump either from 1.14.0 to 1.15.0
Bumps [either](https://github.com/rayon-rs/either) from 1.14.0 to 1.15.0.
- [Commits](https://github.com/rayon-rs/either/compare/1.14.0...1.15.0)

---
updated-dependencies:
- dependency-name: either
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 07:13:06 +00:00
anatawa12
0d8e4ccf48
Merge pull request #1971 from vrc-get/editors-v2
fix: loading editors from editors-v2.json is broken
2025-03-08 23:56:39 +09:00
anatawa12
6d72beeb45
Merge pull request #1974 from vrc-get/devstack-router-devtools
fix: tanstack router devtools location
2025-03-08 22:27:49 +09:00
dependabot[bot]
94d30b87b7
Merge pull request #1970 from vrc-get/dependabot/cargo/ring-0.17.13 2025-03-08 13:21:24 +00:00
anatawa12
a99f874db0
fix: tanstack router devtools location 2025-03-08 22:18:46 +09:00
anatawa12
59987e1176
Merge pull request #1973 from vrc-get/update_l10n_ja
chore(l10n): [ja] update locale
2025-03-08 21:35:41 +09:00
Sayamame-beans
fe7a6e15dd chore(l10n): [ja] update locale 2025-03-08 21:17:43 +09:00
anatawa12
51354da826
docs(changelog): add PR number to The method to retrieve the list of Unity from Unity Hub 2025-03-08 18:42:20 +09:00
anatawa12
e8e5811913
fix: loading editors from editors-v2.json is broken 2025-03-08 18:40:10 +09:00
anatawa12
8f841fc427
Merge pull request #1968 from lonelyicer/feat/enhance-os-info
feat: enhance os info for windows
2025-03-08 18:37:42 +09:00
dependabot[bot]
ebc3d61f8b
chore(deps): bump ring from 0.17.11 to 0.17.13
Bumps [ring](https://github.com/briansmith/ring) from 0.17.11 to 0.17.13.
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-07 17:00:57 +00:00
RingLo_
5dcefb95b0 docs(changelog): update for #1968 2025-03-07 18:01:15 +08:00
RingLo_
cfb9e92136
chore: Update vrc-get-gui/src/os_windows.rs
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-03-07 17:58:34 +08:00
anatawa12
99135d633a
Merge pull request #1969 from vrc-get/fix-system-dark
fix: system dark mode
2025-03-07 13:33:22 +09:00
anatawa12
2f3a44d1c6
Merge pull request #1967 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] fix line breaks
2025-03-07 13:21:36 +09:00
anatawa12
96884caf1e
fix: system dark mode 2025-03-07 13:13:46 +09:00
RingLo_
51b9ac8a6d lint: fix fmt 2025-03-07 05:00:13 +08:00
RingLo_
1052371074 lint: fix clippy 2025-03-07 04:58:32 +08:00
RingLo_
ab4ebd32df chore: using the old version of get_basic_version 2025-03-07 04:48:54 +08:00
RingLo_
ec6149d413 feat(windows): more accurate system information 2025-03-07 04:44:37 +08:00
RingLo_
e7410f3ef1 chore(l10n): [zh_Hans] fix line breaks 2025-03-07 02:42:04 +08:00
anatawa12
9cd94e4e53
Merge pull request #1964 from JustBuddy/german-translation
chore(l10n): [de_DE] update locale and line-break fix for en.
2025-03-07 02:56:56 +09:00
JustBuddy
7b1d062989
chore(l10n): [de_DE] update locale and line-break fix for en. 2025-03-06 18:44:07 +01:00
anatawa12
df3f5f8eee
Merge pull request #1963 from vrc-get/vite-and-tanstack-router
Use Vite + Tanskack Router instead of Next.js
2025-03-07 02:35:52 +09:00
anatawa12
70e9d632ae
Merge pull request #1962 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale for #1808
2025-03-07 02:34:29 +09:00
anatawa12
5278718807
chore: fix biome 2025-03-07 02:23:27 +09:00
anatawa12
dd0f0acf3a
chore: do not import tanstack router-devtools in production 2025-03-07 02:22:27 +09:00
RingLo_
9974c40cd8 chore(l10n): [zh_Hans] update locale 2025-03-07 01:17:30 +08:00
anatawa12
1183237ee3
Merge pull request #1808 from vrc-get/do-not-use-unity-hub
feat: find unity without calling unity hub
2025-03-07 02:09:06 +09:00
anatawa12
da9ec3fbc1
chore: build licenses.json with vite 2025-03-07 02:07:30 +09:00
anatawa12
d231155cff
chore: remove nextjs 2025-03-07 00:43:13 +09:00
anatawa12
69d9e8ea33
chore: configure to use vite / tanstack router with 2025-03-07 00:25:45 +09:00
anatawa12
4dcfd673eb
fix: some other errors 2025-03-07 00:19:25 +09:00
anatawa12
d2eda376df
fix: dark mode broken 2025-03-06 23:41:47 +09:00
anatawa12
d5bd6ead0d
fix: load global-info.js 2025-03-06 23:39:04 +09:00
anatawa12
010b0a4579
chore!: migrate to vite phase 3: migrate the main code to tanstack router 2025-03-06 23:38:23 +09:00
anatawa12
d031c5a0ae
chore!: migrate to vite phase 2: migrate route settings and initial settings 2025-03-06 23:32:59 +09:00
anatawa12
6e53318f40
chore!: migrate to vite phase 1.1: install JSON5 package 2025-03-06 19:56:42 +09:00
anatawa12
c33ec9a4b5
chore!: migrate to vite phase 1: install packages 2025-03-05 22:46:43 +09:00
anatawa12
f18a358608
docs(changelog): The method to retrieve the list of Unity from Unity Hub 2025-03-05 22:15:52 +09:00
anatawa12
195ac775d8
feat: configure if use legacy method or new reading config files 2025-03-05 21:59:01 +09:00
anatawa12
0da58d3f37
feat: use new logic to load unity from hub in vrc-get-gui 2025-03-05 20:59:08 +09:00
anatawa12
8e325a0634
feat: use new logic to load unity from hub 2025-03-05 18:42:15 +09:00
anatawa12
6445b32194
fix: something not working well 2025-03-05 18:40:07 +09:00
anatawa12
eb3eb4b3f7
chore: get_executable_path may return original path on macos 2025-03-05 18:21:05 +09:00
anatawa12
cc7845d2c6
chore: make get_app_path return option 2025-03-05 18:07:36 +09:00
anatawa12
739d2a3d98
chore: rename to load_unity_by_loading_unity_hub_files 2025-03-05 15:43:06 +09:00
anatawa12
63683f9e89
feat: add load_unity_by_calling_unity_hub 2025-03-05 15:41:33 +09:00
anatawa12
5701de2dbe
feat: add get_executable_path and get_app_path 2025-03-05 15:31:56 +09:00
anatawa12
323568283a
feat: expose load_unity_version 2025-03-05 15:13:05 +09:00
anatawa12
e413213769
refactor: move os dependent code to another code 2025-03-05 15:09:49 +09:00
anatawa12
c92e42c170
chore: asynchronously load unity version on windows 2025-03-05 14:38:10 +09:00
anatawa12
1671473497
fix: compile error due to windows-rs update 2025-03-04 23:44:52 +09:00
anatawa12
70c441c5a3
Merge remote-tracking branch 'origin/master' into do-not-use-unity-hub 2025-03-04 23:31:26 +09:00
anatawa12
643f435146
Merge pull request #1961 from vrc-get/cargo-about-dependency
remove cargo-about from build dependency
2025-03-04 11:21:01 +09:00
anatawa12
11174b9c73
docs(changelog): Removed cargo-about from build-time dependency 2025-03-03 23:00:02 +09:00
anatawa12
3411b13336
chore: change node.js version in README 2025-03-03 22:57:16 +09:00
anatawa12
d6422f2f24
refactor: refactor build-license-json 2025-03-03 22:14:32 +09:00
anatawa12
bab655b3d2
chore: remove depending on cargo-about 2025-03-03 21:23:12 +09:00
dependabot[bot]
523de95c37
Merge pull request #1959 from vrc-get/dependabot/cargo/serde_path_to_error-0.1.17 2025-03-03 12:07:23 +00:00
dependabot[bot]
b11a52c40e
Merge pull request #1960 from vrc-get/dependabot/cargo/yoke-0.8.0 2025-03-03 12:06:05 +00:00
dependabot[bot]
a324ff222b
chore(deps): bump yoke from 0.7.5 to 0.8.0
Bumps [yoke](https://github.com/unicode-org/icu4x) from 0.7.5 to 0.8.0.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: yoke
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-03 07:12:19 +00:00
dependabot[bot]
5e9e65bd1a
chore(deps): bump serde_path_to_error from 0.1.16 to 0.1.17
Bumps [serde_path_to_error](https://github.com/dtolnay/path-to-error) from 0.1.16 to 0.1.17.
- [Release notes](https://github.com/dtolnay/path-to-error/releases)
- [Commits](https://github.com/dtolnay/path-to-error/compare/0.1.16...0.1.17)

---
updated-dependencies:
- dependency-name: serde_path_to_error
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-03 07:11:56 +00:00
anatawa12
4059579b94
refactor: create addPackageToLicenses for better manipulation 2025-03-03 15:03:24 +09:00
anatawa12
6e87c09b4f
chore: getLicencesFromPackageLockJson return more general form 2025-03-03 14:46:17 +09:00
anatawa12
08d373daf1
Merge pull request #1958 from vrc-get/tailwind
chore: migrate tailwindcss to v4
2025-03-03 00:33:50 +09:00
anatawa12
25a5c8ac7e
chore: migrate tailwindcss to v4 2025-03-03 00:22:04 +09:00
anatawa12
f612e0e0d2
Merge pull request #1957 from vrc-get/next-and-react
Bump next and react
2025-03-02 22:50:42 +09:00
anatawa12
ad32047e13
fix: useRef without parameters 2025-03-02 22:40:46 +09:00
anatawa12
7dc08e93b1
chore: change way to generate license list 2025-03-02 22:29:17 +09:00
anatawa12
8a8e3d45bf
chore: use litedb-rs from git 2025-03-02 21:18:39 +09:00
anatawa12
505d406687
fix: some hydration warning 2025-03-02 21:16:45 +09:00
anatawa12
69a208a1ac
chore: upgrade next.js and react 2025-03-02 20:43:34 +09:00
dependabot[bot]
6a75de3d1e
Merge pull request #1934 from vrc-get/dependabot/cargo/windows-0.60.0 2025-03-02 10:22:32 +00:00
anatawa12
5dd3c374f3
fix: compile error 2025-03-02 19:12:16 +09:00
dependabot[bot]
d148ec4acd
chore(deps): bump windows from 0.58.0 to 0.60.0
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.58.0 to 0.60.0.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/compare/0.58.0...0.60.0)

---
updated-dependencies:
- dependency-name: windows
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 08:28:02 +00:00
dependabot[bot]
e0e1e5d353
Merge pull request #1847 from vrc-get/dependabot/cargo/dirs-sys-0.5.0 2025-03-02 08:26:46 +00:00
dependabot[bot]
39d06a12be
chore(deps): bump dirs-sys from 0.4.1 to 0.5.0
Bumps [dirs-sys](https://github.com/dirs-dev/dirs-sys-rs) from 0.4.1 to 0.5.0.
- [Commits](https://github.com/dirs-dev/dirs-sys-rs/commits)

---
updated-dependencies:
- dependency-name: dirs-sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 08:12:32 +00:00
dependabot[bot]
ec6317f759
Merge pull request #1834 from vrc-get/dependabot/cargo/itertools-0.14.0 2025-03-02 08:11:52 +00:00
dependabot[bot]
e5223462b1
Merge pull request #1855 from vrc-get/dependabot/cargo/winreg-0.55.0 2025-03-02 08:11:32 +00:00
anatawa12
1fc8ee6fd9
Merge pull request #1956 from vrc-get/rust-2024
Migrate to Rust 2024
2025-03-02 17:09:49 +09:00
dependabot[bot]
71073724fc
chore(deps): bump itertools from 0.13.0 to 0.14.0
Bumps [itertools](https://github.com/rust-itertools/itertools) from 0.13.0 to 0.14.0.
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-itertools/itertools/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: itertools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 07:59:37 +00:00
dependabot[bot]
3dc5cce710
chore(deps): bump winreg from 0.52.0 to 0.55.0
Bumps [winreg](https://github.com/gentoo90/winreg-rs) from 0.52.0 to 0.55.0.
- [Release notes](https://github.com/gentoo90/winreg-rs/releases)
- [Changelog](https://github.com/gentoo90/winreg-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gentoo90/winreg-rs/compare/v0.52.0...v0.55.0)

---
updated-dependencies:
- dependency-name: winreg
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 07:59:13 +00:00
anatawa12
bd2071cff2
docs(changelog): Migrated the project to Rust 2024 2025-03-02 16:56:28 +09:00
anatawa12
7a7e87ebd0
style: reformat with format edition 2024 2025-03-02 16:51:28 +09:00
anatawa12
690a9d1b72
chore: migrate to rust 2024 2025-03-02 16:51:28 +09:00
anatawa12
d3b4371f75
Merge pull request #1955 from vrc-get/litedb-migration-bug-fix
fix: a log file is incorrectly created
2025-03-02 16:26:04 +09:00
anatawa12
bc060bc12a
ci: install rust stable before building crate 2025-03-02 16:14:57 +09:00
anatawa12
65308c3840
fix: dispose database as possible 2025-03-02 16:07:14 +09:00
anatawa12
f4449a7779
docs(changelog): add pr number 2025-03-02 15:53:19 +09:00
anatawa12
45c5b9fe38
fix: a log file is incorrectly created 2025-03-02 15:51:15 +09:00
anatawa12
1785764ebd
Merge pull request #1952 from vrc-get/update-deps
chore(deps): upgrade deps
2025-03-02 04:38:20 +09:00
anatawa12
846a2dbaf0
chore(deps): upgrade deps 2025-03-02 03:54:40 +09:00
anatawa12
b92a01b2c4
Merge pull request #1949 from vrc-get/litedb-crate-updates
migrate to vrc-get-litedb 0.3.0-beta
2025-03-02 03:52:18 +09:00
anatawa12
3c31f3d6ac
fix: remove unused mutex guard 2025-03-02 03:36:22 +09:00
anatawa12
48a8ff8644
fix: build failure on windows (send) 2025-03-02 03:11:31 +09:00
anatawa12
920dc0a0a2
fix: build failure on windows (send) 2025-03-02 02:46:06 +09:00
anatawa12
11ca1bb0b0
fix: build failure on windows 2025-03-02 02:19:02 +09:00
anatawa12
d2774585a9
docs(changelog): Changed how we read VCC's project information 2025-03-02 02:18:03 +09:00
anatawa12
eb478f9938
docs: remove doc mentioning dotnet 2025-03-02 01:48:33 +09:00
anatawa12
8746713f15
ci: no longer installs dotnet 2025-03-02 01:46:04 +09:00
anatawa12
badcd8c40d
chore: remove unnecessary build script 2025-03-02 01:39:07 +09:00
anatawa12
766cf8727e
chore: migrate to vrc-get-litedb 0.3.0 2025-03-02 01:37:40 +09:00
anatawa12
de8f23c37a
chore: remove vrc-get-litedb crate from this repository 2025-03-01 21:17:54 +09:00
github-actions[bot]
878782a5a1 chore: prepare for next version: gui 1.0.2 2025-02-05 11:59:23 +00:00
github-actions[bot]
cedb8953f4 gui v1.0.1 2025-02-05 11:41:16 +00:00
github-actions[bot]
9e72635f2b gui v1.0.1-rc.0 2025-02-04 16:46:05 +00:00
anatawa12
0fd77b0b74
Merge pull request #1902 from vrc-get/input-axis-for-worlds-templetes
fix: world template lacks input manager settings
2025-02-05 01:40:24 +09:00
anatawa12
ec266c9d43
docs(changelog): Worlds templates doesn't have proper input axis settings 2025-02-05 01:22:06 +09:00
anatawa12
4f12d50586
fix: world template lacks input manager settings 2025-02-05 01:18:41 +09:00
anatawa12
3eecb01e3a
Merge pull request #1901 from vrc-get/update-deps
Update deps
2025-02-05 01:01:38 +09:00
anatawa12
28cbcc41f9
chore(deps): bump tauri to my fork for one bugfix 2025-02-05 00:42:33 +09:00
anatawa12
57a33085f1
chore(deps): bump many packages 2025-02-05 00:35:56 +09:00
anatawa12
9bbe5cac20
Merge pull request #1862 from vrc-get/backup-fixes
fix: Backup time now use local time instead of UTC
2025-01-17 20:02:14 +09:00
anatawa12
9de8d81d07
docs(changelog): Backup file used UTC time instead of Local time 2025-01-17 19:51:30 +09:00
anatawa12
f44cec1d47
fix: existing backup can be removed 2025-01-17 19:48:36 +09:00
anatawa12
e5d4c4dba3
chore: use Local time for backup timestamp 2025-01-17 19:48:36 +09:00
anatawa12
88384da901
Merge pull request #1860 from CirnoV/chore/update-ko
chore(I10n): [ko] update locale
2025-01-17 09:32:00 +09:00
CirnoV
6cce7d4576
chore(I10n): [ko] update locale 2025-01-17 00:37:25 +09:00
anatawa12
28f8711646
Merge pull request #1858 from vrc-get/unable-to-build-without-git
fix: failed to build without git
2025-01-13 23:53:38 +09:00
anatawa12
dbdd57c35b
Merge pull request #1838 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2025-01-11 23:31:35 +09:00
夜嵐蝶Alma
76bac0b7de chore(l10n): [zh_hant] update locale 2025-01-11 21:31:00 +08:00
夜嵐蝶Alma
1b04357d63
Merge branch 'master' into master 2025-01-11 21:27:28 +08:00
anatawa12
c3003846e7
Merge pull request #1839 from vrc-get/clippy
style: fix new clippy lints
2025-01-11 21:47:40 +09:00
anatawa12
a8049a6ee0
lint: fix new clippy lints for 1.85
I encountered literal_string_with_formatting_args, but I feel it's a false positive, so I ignored here.
2025-01-11 20:44:23 +09:00
anatawa12
d2804b491d
lint: fix new clippy lints for 1.84 2025-01-11 20:11:38 +09:00
夜嵐蝶Alma
d3768a8843 chore(l10n): [zh_hant] update locale 2025-01-10 19:19:30 +08:00
github-actions[bot]
efc2d13b9c gui v1.0.1-beta.1 2025-01-04 16:53:16 +00:00
anatawa12
e12871fe45
Merge pull request #1822 from CirnoV/gui-locale-ko
chore(I10n): [ko] add korean localization
2025-01-04 15:50:12 +09:00
anatawa12
2b3ee7eb48
ci: add Korean 2025-01-04 15:37:49 +09:00
anatawa12
fa8367872e
Merge pull request #1821 from vrc-get/deep-link-and-deb-package
Improve linux desktop support
2025-01-04 15:03:01 +09:00
anatawa12
8aa5a4819e
docs(changelog): Improved several linux desktop support 2025-01-04 14:53:30 +09:00
CirnoV
106bba42ae
Update CHANGELOG-gui 2025-01-04 04:17:54 +09:00
CirnoV
874293bdd8
chore(I10n): [ko] add localization 2025-01-03 23:44:39 +09:00
anatawa12
a22c208f5a
fix: alcom.desktop doesn't work well for deep link 2025-01-03 23:27:00 +09:00
anatawa12
276d1297ba
chore: add 64x64 image for linux 2025-01-03 15:52:51 +09:00
anatawa12
ed3a283db4
fix: desktop entry for .deb / .rpm should include x-scheme-handler/vcc 2025-01-03 15:29:47 +09:00
anatawa12
ace4006253
fix: ALCOM asks for installing deep link support even with .deb / .rpm 2025-01-03 14:52:45 +09:00
anatawa12
6e49499e2a
Merge pull request #1820 from vrc-get/add-badges-to-alcom-readme
Add badges to alcom readme
2025-01-03 03:49:59 +09:00
anatawa12
5b4404bd62
docs: show winget 2025-01-03 03:40:22 +09:00
anatawa12
be3af528e0
docs: show winget badge again 2025-01-03 03:38:48 +09:00
anatawa12
7ba8965033
docs: add note that you can install via package manager 2025-01-02 17:42:14 +09:00
anatawa12
ffc5637237
chore: hide winget badge 2025-01-02 17:41:20 +09:00
anatawa12
79542927a7
docs: update README 2025-01-02 01:06:12 +09:00
github-actions[bot]
b27c994651 chore: prepare for next version: 1.9.1 2025-01-01 13:53:24 +00:00
github-actions[bot]
c1bbc75824 v1.9.0 2025-01-01 13:45:28 +00:00
anatawa12
474387d06c
Merge pull request #1815 from 32ba/fix-repositories-import-toast
fix(gui): correct success toast message for adding a repositories
2025-01-01 20:41:17 +09:00
anatawa12
192b3baca2
Merge pull request #1816 from Spokeek/french-translation
review french translations and add missing keys
2025-01-01 20:38:45 +09:00
Spokeek
2457852fb5
review french translations and add missing keys 2025-01-01 11:24:37 +01:00
Yuki Maruyama
40b5a11035
docs(changelog): add changelog for https://github.com/vrc-get/vrc-get/pull/1815 2025-01-01 18:46:00 +09:00
Yuki Maruyama
0f9328f5d1
fix(gui): correct success toast message for adding a repositories 2025-01-01 16:15:47 +09:00
github-actions[bot]
ba5d01a0d5 chore: prepare for next version: gui 1.0.1 2025-01-01 04:32:17 +00:00
github-actions[bot]
2f6da75d20 gui v1.0.0 2025-01-01 04:16:19 +00:00
github-actions[bot]
895877e10e gui v1.0.0-rc.2 2024-12-31 19:32:22 +00:00
anatawa12
cda72b3a37
Merge pull request #1813 from vrc-get/support-unknown-unity-version
fix: support "UnknownUnityVersion"
2024-12-31 23:31:57 +09:00
anatawa12
215c6fe7d1
docs(changelog): Fixed failed to load project list with invalid unity version stored 2024-12-31 23:21:25 +09:00
anatawa12
0d1b59de40
fix: support "UnknownUnityVersion" 2024-12-31 23:16:44 +09:00
anatawa12
aaa2121cf5
Merge pull request #1811 from lonelyicer/fix-auto-scroll-not-enable-on-start
fix(gui): logs auto scroll not enable on start
2024-12-31 21:27:16 +09:00
RingLo_
2daf340399
docs(changelog): add pr number
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2024-12-31 20:18:42 +08:00
RingLo_
e746e9f48a docs(changelog): add changelog for #1811 2024-12-31 20:16:28 +08:00
RingLo_
f5e6620845 fix(gui): logs auto scroll not enable on start 2024-12-31 20:11:57 +08:00
dependabot[bot]
e82f715355
Merge pull request #1805 from vrc-get/dependabot/cargo/cc-1.2.6 2024-12-30 14:47:35 +00:00
dependabot[bot]
5d4ac7837c
chore(deps): bump cc from 1.2.5 to 1.2.6
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.5...cc-v1.2.6)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 14:34:33 +00:00
dependabot[bot]
978a11e1f3
Merge pull request #1806 from vrc-get/dependabot/cargo/reqwest-0.12.11 2024-12-30 14:29:30 +00:00
dependabot[bot]
fdb562c094
Merge pull request #1807 from vrc-get/dependabot/cargo/serde-1.0.217 2024-12-30 14:28:14 +00:00
anatawa12
fb77998499
Merge pull request #1810 from vrc-get/fix-link-to-unity-hub
fix: link to unity hub is hardcoded to the Japanese version
2024-12-30 22:58:47 +09:00
anatawa12
423b0eac33
fix: not fixed for french 2024-12-30 22:49:49 +09:00
anatawa12
25b87d092b
docs(changelog): Link to unity hub is hardcoded to Japanese 2024-12-30 22:38:42 +09:00
anatawa12
0c9eba7014
fix: link to unity hub is hardcoded to the Japanese version 2024-12-30 22:35:28 +09:00
dependabot[bot]
645981be64
chore(deps): bump serde from 1.0.216 to 1.0.217
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.216 to 1.0.217.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.216...v1.0.217)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 07:40:27 +00:00
dependabot[bot]
3417e6057b
chore(deps): bump reqwest from 0.12.9 to 0.12.11
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.9 to 0.12.11.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.9...v0.12.11)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 07:40:12 +00:00
anatawa12
3f56f8c712
fix: failed to build without git 2024-12-29 00:19:33 +09:00
anatawa12
ca3ed3b213
feat: find unity without calling unity hub 2024-12-28 01:10:18 +09:00
github-actions[bot]
5e48808ad2 gui v1.0.0-rc.1 2024-12-26 09:17:15 +00:00
github-actions[bot]
f4edd681f8 v1.9.0-rc.0 2024-12-25 12:11:35 +00:00
anatawa12
6723886bbf
Merge pull request #1802 from vrc-get/fix-multi-element-toast
fix: toast with markup shown oddly
2024-12-25 15:51:30 +09:00
anatawa12
b04f6954fe
fix: toast with markup shown oddly 2024-12-25 15:41:12 +09:00
github-actions[bot]
77b19dff54 gui v1.0.0-rc.0 2024-12-24 15:11:18 +00:00
anatawa12
7090ecce26
Merge pull request #1800 from vrc-get/allow-miner-update-of-lucide
chore: allow any version of lucide
2024-12-24 23:39:35 +09:00
anatawa12
d6b2bddde2
chore: allow any version of lucide 2024-12-24 23:24:50 +09:00
anatawa12
5d29575411
Merge pull request #1789 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/react-toastify-11.0.2
chore(deps): bump react-toastify from 10.0.6 to 11.0.2 in /vrc-get-gui
2024-12-24 23:18:03 +09:00
dependabot[bot]
78cf1587e7
Merge pull request #1783 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/i18next-24.2.0 2024-12-24 14:17:31 +00:00
anatawa12
6ba1fa0082
chore: move css variables for toastify to base layer 2024-12-24 23:07:40 +09:00
anatawa12
de16c25ac3
chore: remove unnecessary importing css 2024-12-24 22:48:39 +09:00
anatawa12
f6570bed80
Merge pull request #1799 from vrc-get/update-deps
chore(deps): upgrade deps
2024-12-24 21:47:53 +09:00
anatawa12
d2879dd74a
Merge branch 'master' into update-deps 2024-12-24 21:36:37 +09:00
anatawa12
3229dac6f5
chore(deps): upgrade deps 2024-12-24 21:35:15 +09:00
anatawa12
58ecdec067
Merge pull request #1798 from vrc-get/updater-error
chore: show less message for check for update failure
2024-12-24 20:39:43 +09:00
anatawa12
24d4342ce5
chore: show less message for check for update failure 2024-12-24 20:22:33 +09:00
anatawa12
3b5cf9e917
Merge pull request #1797 from vrc-get/v1
Prepare for v1 release
2024-12-24 20:21:05 +09:00
anatawa12
74807568a7
chore(booth): add booth assets 2024-12-24 20:08:37 +09:00
anatawa12
6344527f5a
chore(booth): add booth description text 2024-12-24 19:35:51 +09:00
anatawa12
5995424d7f
feat: add script to build booth thumbnail 2024-12-24 14:23:00 +09:00
anatawa12
7332b637e9
chore: embed lucide icon 2024-12-24 13:51:45 +09:00
anatawa12
b946f54da8
chore: bump version to v1.0.0 2024-12-24 13:44:49 +09:00
anatawa12
5bc7def2d9
chore: add initial booth assets 2024-12-24 13:16:21 +09:00
dependabot[bot]
9146f920be
chore(deps): bump react-toastify from 10.0.6 to 11.0.2 in /vrc-get-gui
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 10.0.6 to 11.0.2.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v10.0.6...v11.0.2)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 07:16:41 +00:00
github-actions[bot]
2862dd1e90 chore: prepare for next version: gui 0.1.18 2024-12-22 16:36:43 +00:00
github-actions[bot]
0c48143c17 gui v0.1.17 2024-12-22 15:19:43 +00:00
dependabot[bot]
a5a148dbb1
chore(deps): bump i18next from 23.16.8 to 24.2.0 in /vrc-get-gui
Bumps [i18next](https://github.com/i18next/i18next) from 23.16.8 to 24.2.0.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.16.8...v24.2.0)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-22 09:56:02 +00:00
anatawa12
5013caecb3
Merge pull request #1782 from vrc-get/remove-parseargs
fix: tailwind-animate is added as runtime dependency
2024-12-22 18:54:46 +09:00
anatawa12
c6947828c7
fix: tailwind-animate is added as runtime dependency 2024-12-22 18:38:22 +09:00
anatawa12
52daee159e
Merge pull request #1779 from vrc-get/header-improvement
chore: improve header behavior with thiner window
2024-12-21 23:47:11 +09:00
anatawa12
ea87061e7e
docs(changelog): add pr to Several GUI improvements 2024-12-21 23:40:36 +09:00
anatawa12
da5f6e564b
chore: improve button at edge of header 2024-12-21 12:22:24 +09:00
anatawa12
194cb953ed
chore: improve api 2024-12-21 12:17:54 +09:00
anatawa12
7bac1ab782
chore: improve header behavior with thiner window 2024-12-20 20:11:10 +09:00
anatawa12
eb00c45437
Merge pull request #1776 from vrc-get/gui-animation-toggle
chore: add space between missing package list and message
2024-12-20 15:42:20 +09:00
anatawa12
a4b09cb0c7
docs(changelog): Dialog is shown when some installing packages are not found 2024-12-19 13:37:44 +09:00
anatawa12
d56fe84d94
chore: add space between missing package list and message 2024-12-19 11:45:32 +09:00
github-actions[bot]
81938cec03 gui v0.1.17-beta.1 2024-12-19 00:10:38 +00:00
anatawa12
f476a0a32e
Merge pull request #1772 from lonelyicer/move-ui-palette
chore: move ui palette to dev
2024-12-18 23:02:15 +09:00
RingLo_
67df2df608
Merge branch 'master' into move-ui-palette 2024-12-18 21:51:33 +08:00
RingLo_
45ec284c17 docs(changelog): update for #1771 2024-12-18 20:00:47 +08:00
RingLo_
93bc3853a6 chore: move ui palette to dev-palette 2024-12-18 19:59:19 +08:00
anatawa12
918638195b
Merge pull request #1775 from vrc-get/gui-animation-toggle
chore: improve page change animation with repositories pages
2024-12-18 14:12:05 +09:00
anatawa12
92090c12e3
docs(changelog): add PR number to Several GUI improvements 2024-12-18 13:56:08 +09:00
anatawa12
d8e8b290b5
Merge branch 'master' into gui-animation-toggle 2024-12-18 13:54:41 +09:00
anatawa12
ba19fa6e77
chore: improve page change animation with repositories pages 2024-12-18 12:08:00 +09:00
anatawa12
59ec9ac744
Merge pull request #1773 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale
2024-12-18 11:36:29 +09:00
RingLo_
1558e20fbb chore(l10n): [zh_Hans] update locale
Update locale for #1749 & Fixing a small problem
2024-12-18 04:26:20 +08:00
RingLo_
b8c3be2edb chore: move ui palette to dev 2024-12-18 04:11:10 +08:00
anatawa12
6309bb307b
Merge pull request #1771 from vrc-get/gui-animation-toggle
fix: first page change after changing GUI Toggle is incorrect
2024-12-18 01:43:06 +09:00
anatawa12
534eaa90ce
docs(changelog): add PR number to Several GUI improvements 2024-12-18 01:33:02 +09:00
anatawa12
8e3a275a0e
Merge pull request #1769 from vrc-get/update_l10n_ja
update locale ja / chore english message
2024-12-18 01:30:09 +09:00
anatawa12
b795eb1781
fix: first page change after changing GUI Toggle is incorrect 2024-12-18 01:25:29 +09:00
anatawa12
34ec688631
feat: add useEffectEvent 2024-12-18 01:06:30 +09:00
Sayamame-beans
d7e2505ecf chore(l10n): chore line breaking 2024-12-18 00:14:45 +09:00
Sayamame-beans
fa78a31f34 chore(l10n): [ja] update locale 2024-12-18 00:13:42 +09:00
dependabot[bot]
1eba404634
Merge pull request #1730 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.468.0 2024-12-17 13:12:07 +00:00
anatawa12
ad192014b6
Merge pull request #1763 from vrc-get/update-alcom-readme
docs: update README for ALCOM, adds Platform Version Policy and remove experimental
2024-12-17 21:49:06 +09:00
dependabot[bot]
edd6b9f53c
chore(deps): bump lucide-react from 0.456.0 to 0.468.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.456.0 to 0.468.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.468.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-17 12:47:57 +00:00
anatawa12
6655ed3eab
Merge pull request #1764 from JustBuddy/german-translation
chore(l10n): [de] update locale
2024-12-17 21:44:49 +09:00
JustBuddy
3d39d8f314
chore(l10n): [de] update locale 2024-12-17 09:50:05 +01:00
anatawa12
83eb72f0bb
docs: note that pull requests for backport is welcome 2024-12-17 15:26:56 +09:00
anatawa12
6b2725ceb2
docs: update README for ALCOM 2024-12-17 14:51:25 +09:00
anatawa12
71cdcc5264
Merge pull request #1749 from vrc-get/better-not-found-error
Better not found error
2024-12-17 13:27:52 +09:00
anatawa12
175f12de6b
Merge pull request #1672 from lonelyicer/gui-improved
chore: some gui minor Improvements
2024-12-17 13:18:47 +09:00
anatawa12
f3bde7c8a3
feat: add link to VPM Catalog 2024-12-17 13:16:29 +09:00
anatawa12
b661ee1226
feat(internal): allow ExternalLink in localization 2024-12-17 13:14:03 +09:00
anatawa12
440f49ab81
feat(internal): add ExternalLink component 2024-12-17 13:09:05 +09:00
RingLo_
fdfd351a5a chore: make autoScroll default by true 2024-12-17 03:23:11 +08:00
RingLo_
a576b6dc93 lint: fix cargo fmt 2024-12-17 03:09:18 +08:00
RingLo_
6d1e474023 chore: make gui_animation default by true 2024-12-17 03:07:41 +08:00
anatawa12
31bb1deaab
fix: english localization
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2024-12-16 23:35:56 +09:00
RingLo_
d1360ba5fc chore: update changelog for #1672 2024-12-16 20:13:40 +08:00
RingLo_
2708e69290
Merge branch 'master' into gui-improved 2024-12-16 20:05:47 +08:00
RingLo_
7d9eb6df3b lint: fix biome 2024-12-16 20:01:26 +08:00
RingLo_
76f78a34b2 chore: apply suggestions
& make logsAutoScroll stored in the sessionStorage
2024-12-16 19:53:29 +08:00
anatawa12
85624f2dfa
Merge pull request #1752 from vrc-get/bump-deps
Bump deps
2024-12-16 18:14:22 +09:00
anatawa12
c9787f8227
lint: fix lint errors 2024-12-16 18:12:10 +09:00
anatawa12
9467f79bbc
chore(deps): bump deps 2024-12-16 17:06:25 +09:00
anatawa12
8fa51c18b3
docs(changelog): Dialog is shown when some installing packages are not found 2024-12-16 16:27:27 +09:00
anatawa12
83fad70a4c
Merge branch 'master' into better-not-found-error 2024-12-16 16:24:12 +09:00
anatawa12
004b6a2eab
feat(gui): dialog to show missing dependencies and suggest adding repository 2024-12-16 16:21:48 +09:00
anatawa12
8343455db4
feat(gui-internal): add Handleable errors 2024-12-16 15:43:22 +09:00
anatawa12
335808b8c0
chore: collect missing packages as many as we can 2024-12-16 12:15:47 +09:00
anatawa12
9508568b8d
Merge pull request #1748 from vrc-get/create-project-resolve
Add new project to list before resolving packages
2024-12-16 11:24:24 +09:00
anatawa12
85b66436cd
docs(changelog): Projects that failes to resolve will also be added to Project List now 2024-12-16 11:15:51 +09:00
anatawa12
9cdcc1b590
chore: refetch project list even with error 2024-12-16 11:05:02 +09:00
anatawa12
f8d1c5f559
fix: add to the project list before resolving 2024-12-16 11:01:56 +09:00
anatawa12
a68b6eca4c
Merge pull request #1745 from vrc-get/try-non-prerelease-first
chore: prefer a stable version over prerelease
2024-12-12 11:28:58 +09:00
anatawa12
97b323ca7d
docs(changelog): Prerelease version is choosen even if good stable version exists 2024-12-12 11:19:40 +09:00
anatawa12
94058c6f00
fix: default PrereleaseAcceptance 2024-12-12 11:15:15 +09:00
anatawa12
cf38f83b5b
chore: prefer a stable version over prerelease 2024-12-12 09:53:25 +09:00
anatawa12
f295878bc1
Merge pull request #1742 from vrc-get/try-non-prerelease-first
chore: remove -debugCodeOptimization from default arguments
2024-12-12 08:38:36 +09:00
anatawa12
b0b0c3f47a
Merge branch 'master' into try-non-prerelease-first 2024-12-12 08:26:55 +09:00
RingLo_
d62f6ea697
chore(l10n): [EN] remove unused string 2024-12-12 04:50:39 +08:00
RingLo_
85b12e9125
lint: fix cargo fmt 2024-12-12 04:42:29 +08:00
RingLo_
5f6a4aab69
lint: fix clippy error 2024-12-12 04:31:47 +08:00
RingLo_
a3f41a6060
chore: remove switch component 2024-12-12 04:18:52 +08:00
RingLo_
611b69e7d6
Revert "chore(deps): add switch"
This reverts commit 09b73c5a24.
2024-12-12 04:12:26 +08:00
RingLo_
676fb40338
Merge branch 'master' into gui-improved 2024-12-12 04:08:04 +08:00
RingLo_
88b5bff529
feat: gui animation switch 2024-12-12 04:06:07 +08:00
RingLo_
59535943d6
chore: licenses page improved 2024-12-12 02:15:32 +08:00
RingLo_
a04fe9e23a
fix: may play wrong animation 2024-12-12 02:03:34 +08:00
anatawa12
32b8731413
Merge pull request #1743 from vrc-get/clippy-fixes
lint: fix clippy error
2024-12-12 01:43:07 +09:00
anatawa12
962d899f02
lint: fix clippy error 2024-12-11 21:54:18 +09:00
anatawa12
fad663c19e
docs(changelog): Removed -debugCodeOptimization from default unity arguments 2024-12-10 20:00:19 +09:00
anatawa12
82ae1e8041
chore: remove -debugCodeOptimization from default arguments 2024-12-10 19:58:06 +09:00
RingLo_
b7a89f4e1f chore: add simple loading page 2024-12-10 00:21:06 +08:00
RingLo_
396d6137cc feat: page trans animation 2024-12-09 23:57:07 +08:00
RingLo_
16c1ad59cf Revert "chore(deps): add framer-motion"
This reverts commit 2c043f4448.
2024-12-09 23:28:24 +08:00
RingLo_
b6e1e0795b chore: add switch components 2024-12-04 04:12:56 +08:00
RingLo_
09b73c5a24 chore(deps): add switch 2024-12-04 04:11:32 +08:00
RingLo_
2c043f4448 chore(deps): add framer-motion 2024-12-04 04:06:55 +08:00
RingLo_
6a264599dd chore: fix biome 2024-12-04 04:03:39 +08:00
RingLo_
0485542f16 fix: no highlight when located in subpages of packages 2024-12-04 04:00:51 +08:00
RingLo_
18e0f8ee2f chore: highlight when in child page 2024-12-04 03:45:15 +08:00
RingLo_
afae02579c chore: fix cargo fmt 2024-12-04 03:35:45 +08:00
RingLo_
5dc727e4a2 feat: scroll smooth 2024-12-04 03:34:54 +08:00
RingLo_
1f77aeb717 feat: log settings persistence 2024-12-04 03:28:19 +08:00
RingLo_
00aa101ef0 chore: fix biome 2024-12-04 00:37:51 +08:00
RingLo_
d152d955a5 chore: logs page tweak 2024-12-04 00:25:35 +08:00
RingLo_
9cccf6f0c9 chore: revert packages page 2024-12-04 00:14:36 +08:00
RingLo_
ac8b273357 chore: revert projects page 2024-12-03 23:57:36 +08:00
RingLo_
23d91815aa chore: fix biome 2024-12-02 20:40:43 +08:00
RingLo_
3675dee8c4 chore: scrollpagecontainer improvement 2024-12-02 20:39:12 +08:00
RingLo_
cbad2b76b5 chore: button style improvement 2024-12-02 20:20:18 +08:00
RingLo_
996414f5cd chore: sidebar improvement 2024-12-02 20:10:17 +08:00
RingLo_
8e26224509 feat: logs page auto scroll 2024-12-02 19:52:07 +08:00
RingLo_
96e8de775d chore: add manage project title 2024-11-17 20:49:25 +08:00
RingLo_
34b45a1136 Merge branch 'gui-improved' of https://github.com/lonelyicer/vrc-get into gui-improved 2024-11-17 20:46:13 +08:00
RingLo_
e82b01bfa4 chore(gui): fix typo 2024-11-17 20:44:40 +08:00
RingLo_
7ad8cab866 chore(gui): settings page minor improved 2024-11-17 20:44:40 +08:00
RingLo_
e58ca1c32c chore(gui):fix biome 2024-11-17 20:44:40 +08:00
RingLo_
40b46b0f40 chore(gui): settings page minor improved 2024-11-17 20:44:40 +08:00
RingLo_
bbf81cc91d chore(gui): table & packages page improved 2024-11-17 20:44:40 +08:00
RingLo_
0a69b845db chore(gui): projects page minor improved 2024-11-17 20:44:40 +08:00
github-actions[bot]
af1eee8c46 chore: prepare for next version: gui 0.1.17 2024-11-12 03:46:06 +00:00
github-actions[bot]
57003d4bca gui v0.1.16 2024-11-12 01:28:17 +00:00
dependabot[bot]
202ccb3449
Merge pull request #1679 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.456.0 2024-11-12 01:04:43 +00:00
anatawa12
be54fc9734
Merge pull request #1692 from vrc-get/update-deps
chore: bump deps again
2024-11-12 08:51:23 +09:00
anatawa12
b91b567813
Merge branch 'master' into update-deps 2024-11-12 08:34:22 +09:00
anatawa12
9420df27ea
chore: bump deps again 2024-11-12 08:09:50 +09:00
dependabot[bot]
5e21cb6d51
chore(deps): bump lucide-react from 0.454.0 to 0.456.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.454.0 to 0.456.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.456.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 15:31:39 +00:00
anatawa12
036f215f57
Merge pull request #1689 from vrc-get/update-deps
chore: bump deps
2024-11-12 00:29:51 +09:00
anatawa12
1f7d28bdb0
chore: bump deps 2024-11-11 22:41:53 +09:00
RingLo_
7e54cfd69b chore(gui): fix typo 2024-11-07 15:31:42 +08:00
RingLo_
d9de31b1d1 chore(gui): settings page minor improved 2024-11-06 22:41:04 +08:00
RingLo_
b13d3887b7 chore(gui):fix biome 2024-11-06 21:52:45 +08:00
RingLo_
33f69b90cc chore(gui): settings page minor improved 2024-11-06 21:48:42 +08:00
RingLo_
94a7953213 chore(gui): table & packages page improved 2024-11-06 21:41:17 +08:00
RingLo_
2a573365de chore(gui): projects page minor improved 2024-11-06 21:17:03 +08:00
anatawa12
88f2ab35ca
Merge pull request #1670 from vrc-get/winget-badge
docs: add winget badge
2024-11-05 09:28:17 +09:00
anatawa12
dfd47ca17d
docs: add winget badge 2024-11-05 09:14:15 +09:00
anatawa12
6d1f341856
Merge pull request #1660 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update locale for #1653
2024-10-30 20:35:51 +09:00
RingLo_
48d1d1a91f chore(l10n): [zh_Hans] update locale for #1653 2024-10-30 18:37:47 +08:00
anatawa12
d98dec9d43
Merge pull request #1659 from JustBuddy/german-translation
chore(l10n): [de] update locale
2024-10-30 10:54:03 +09:00
JustBuddy
82f6500316
chore(l10n): [de] update locale 2024-10-29 17:34:15 +01:00
anatawa12
ebc2feb1ea
Merge pull request #1658 from vrc-get/update_l10n_ja
Update l10n ja
2024-10-29 23:55:38 +09:00
Sayamame-beans
8e2b4ecc14 chore(l10n): fix separator 2024-10-29 23:06:05 +09:00
Sayamame-beans
0ad63c847b chore(l10n): [ja] update locale 2024-10-29 23:05:37 +09:00
github-actions[bot]
21472faa36 gui v0.1.16-beta.2 2024-10-28 23:59:51 +00:00
dependabot[bot]
ee8d5ae062
Merge pull request #1656 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.454.0 2024-10-28 23:12:14 +00:00
dependabot[bot]
2eb40f75fe
chore(deps): bump lucide-react from 0.446.0 to 0.454.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.446.0 to 0.454.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.454.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-28 16:10:11 +00:00
anatawa12
b4e5e8d480
Merge pull request #1655 from vrc-get/bump-deps
chore: bump deps
2024-10-29 00:56:51 +09:00
anatawa12
0f22f02fd6
Merge pull request #1654 from vrc-get/fix-some-missing-field-version
fix: "missing field Verison" error if some unity version is missing
2024-10-29 00:48:16 +09:00
anatawa12
d63df74492
chore: bump deps 2024-10-29 00:41:39 +09:00
anatawa12
35466ab8e6
docs(changelog-gui): "missing field Verison" error if some unity version is missing 2024-10-29 00:36:02 +09:00
anatawa12
03f563c07b
fix: "missing field Verison" error if some unity version is missing 2024-10-29 00:34:51 +09:00
anatawa12
d15617cb60
Merge pull request #1653 from vrc-get/better-error-for-missing-drive
feat: better error message for missing drive
2024-10-29 00:33:30 +09:00
anatawa12
53781f3d92
docs(changelog): Improved error message when specified drive not found 2024-10-29 00:22:34 +09:00
anatawa12
005143ec0d
chore: improve error messages 2024-10-29 00:21:18 +09:00
anatawa12
987a11fbe9
feat: better error message for missing drive 2024-10-28 23:59:02 +09:00
anatawa12
a2a74fa02f
Merge pull request #1652 from vrc-get/more-reqwest-error
chore: more error information for http request errors
2024-10-28 23:49:08 +09:00
anatawa12
9af4402307
docs(changelog): Added more error log 2024-10-28 23:38:47 +09:00
anatawa12
823b42f697
chore: more error information for http request errors 2024-10-28 23:33:00 +09:00
anatawa12
273ca40577
Merge pull request #1651 from vrc-get/fix-prefix-only-path
fix: error if the project path is "C:"
2024-10-28 23:29:20 +09:00
anatawa12
8d538de136
docs(changelog-gui): Error creating project if the project path is "C:" 2024-10-28 23:19:19 +09:00
anatawa12
cfdc0638ba
fix: error if the project path is "C:" 2024-10-28 23:02:56 +09:00
anatawa12
e24e1e135d
Merge pull request #1648 from vrc-get/fix-backup-dot
fix: backup name for projects containing dot is not correct
2024-10-28 22:49:54 +09:00
anatawa12
24ed56aba8
docs(changelog-gui): Backup file name is incorrect if project name contains '.' 2024-10-28 22:37:11 +09:00
anatawa12
8611fd3ca2
Merge branch 'master' into fix-backup-dot 2024-10-28 22:36:13 +09:00
anatawa12
204d4aaa0d
Merge pull request #1641 from vrc-get/fix-templetes-folder
fix: opening Templates folder fails if not exists
2024-10-28 22:35:43 +09:00
anatawa12
8d7ab9ff2c
Merge branch 'master' into fix-templetes-folder 2024-10-28 22:20:40 +09:00
anatawa12
4d027491cd
Merge pull request #1650 from vrc-get/exclude-litedb-from-test
ci: exclude litedb from testing
2024-10-28 22:20:11 +09:00
anatawa12
41eb1a2cce
ci: do not run test for vrc-get-gui 2024-10-28 22:07:49 +09:00
anatawa12
4d36a402df
lint: fix lint errors 2024-10-28 21:52:11 +09:00
anatawa12
a95e940253
ci: exclude litedb from testing 2024-10-28 21:41:12 +09:00
anatawa12
815e46d3a7
fix: backup name for projects containing dot is not correct 2024-10-28 17:03:02 +09:00
anatawa12
41e11055d7
docs(changelog): Opnening Templetes directory might fails 2024-10-28 16:44:04 +09:00
anatawa12
1620a5136f
fix: opening Templates folder fails if not exists 2024-10-28 16:40:31 +09:00
anatawa12
b87b40c82a
Merge pull request #1615 from vrc-get/hotfix-user-agent
Hotfix: add contact information to the user agent
2024-10-16 13:53:42 +09:00
anatawa12
5cf8f9c12b
Merge branch 'master' into hotfix-user-agent 2024-10-16 10:55:31 +09:00
github-actions[bot]
9c7e4e25bf chore: prepare for next version: 1.8.3 2024-10-16 00:42:33 +00:00
github-actions[bot]
7dc10234da v1.8.2 2024-10-16 00:34:05 +00:00
anatawa12
019008417a
ci: release branch is not correct 2024-10-16 09:32:51 +09:00
anatawa12
9cc58f459d
ci: allow hotfix stable release 2024-10-16 09:28:14 +09:00
anatawa12
1b66f8f056
docs(changelog): Added contact information about author of the project to the User-Agent 2024-10-16 09:24:02 +09:00
anatawa12
d17dc589d8
fix: add author information to user agent 2024-10-16 09:22:52 +09:00
anatawa12
09b261ac4e
Merge pull request #1599 from Spokeek/french-translation
Update French Translations
2024-10-13 14:24:25 +09:00
Spokeek
f21d892c98
Update translations with China Unity 2024-10-12 22:46:08 +02:00
anatawa12
9606934421
Merge pull request #1593 from vrc-get/update_l10n_ja
chore(l10n): [ja] update locale
2024-10-10 09:35:38 +09:00
Sayamame-beans
3d427682b5 chore(l10n): [ja] update locale 2024-10-09 20:38:24 +09:00
anatawa12
523232daf5
Merge pull request #1587 from vrc-get/bump-deps
chore(deps): bump deps (including tauri v2 stable)
2024-10-06 22:35:42 +09:00
anatawa12
b87bcecbbd
chore(deps): bump deps 2024-10-06 22:20:15 +09:00
anatawa12
d71a2e7d3e
feat: add flatpak installation of unity hub to default search path 2024-10-05 21:08:00 +09:00
github-actions[bot]
ab6615d741 gui v0.1.16-beta.1 2024-10-04 15:37:03 +00:00
anatawa12
eb21d820b2
Merge pull request #1573 from vrc-get/favorite-checkbox-improvement
chore: show gray star for non-favorite projects
2024-10-05 00:01:34 +09:00
anatawa12
189e882725
docs(changelog): add PR number to Several UX improvements 2024-10-04 23:54:46 +09:00
anatawa12
ece4487d0b
Merge branch 'master' into favorite-checkbox-improvement 2024-10-04 23:35:01 +09:00
anatawa12
f9068ed537
Merge pull request #1577 from lolosiax/gui-locales-zh_Hans
chore(l10n): [zh_Hans] update locale
2024-10-04 22:46:15 +09:00
anatawa12
9c47f9ff2e
Merge pull request #1585 from JustBuddy/german-translation
chore(l10n): [de] update locale
2024-10-04 22:39:41 +09:00
lolosiax
6b8887a171 chore(l10n): [zh_Hans] applied requirements. 2024-10-04 17:19:00 +08:00
JustBuddy
a90c42f699
chore(l10n): [de] update locale 2024-10-04 09:43:52 +02:00
lolosiax
4223c59e06 chore(l10n): [zh_Hans] update locale 2024-10-03 22:30:26 +08:00
anatawa12
1985a3934f
Merge pull request #1584 from vrc-get/write-notes
docs: write notes.txt
2024-10-03 15:27:11 +09:00
anatawa12
75b48bb44f
Merge pull request #1583 from vrc-get/gui-prerelease-changelog
ci: do not update CHANGELOG.md with beta releases
2024-10-03 15:20:42 +09:00
anatawa12
2822d61e18
docs: write notes.txt 2024-10-03 15:15:35 +09:00
anatawa12
3ae1e52da9
ci: do not update CHANGELOG.md with beta releases 2024-10-03 15:09:10 +09:00
anatawa12
38e101c0ec
Merge pull request #1582 from vrc-get/en-improvements
general localization improvements
2024-10-03 14:11:53 +09:00
anatawa12
a151055e5c
chore: apply placeholder name change to another locale 2024-10-03 14:01:52 +09:00
anatawa12
0db37bc144
chore: use Directory instead of Folders 2024-10-03 13:51:21 +09:00
anatawa12
1d5e54b248
chore: improve placeholder names 2024-10-03 13:41:55 +09:00
anatawa12
ed49f6277a
Merge pull request #1581 from vrc-get/skip-legacy-search-with-upgrade-or-reinstall
Skip legacy search with upgrade or reinstall
2024-10-03 13:39:42 +09:00
anatawa12
0bdd5f4ffa
docs(changelog): Skipping finding legacy assets when downgrading / upgrading / reinstalling package 2024-10-03 13:32:01 +09:00
anatawa12
0d219a8b90
feat: skip collecting legacy assets if same legacy assets are defined in installed package 2024-10-03 09:44:20 +09:00
anatawa12
731ba58171
Merge pull request #1578 from Misaka-L/patch-1
fix: correct typo
2024-10-03 09:17:26 +09:00
anatawa12
aa89247cb2
Merge pull request #1564 from vrc-get/update_l10n_ja
chore(l10n): [ja] update locale
2024-10-03 09:16:17 +09:00
anatawa12
92d15bc170
Merge pull request #1568 from vrc-community-assets-tc-translators/master
chore(l10n): [zh_hant] update locale
2024-10-03 09:15:55 +09:00
anatawa12
185e967ad9
docs(changelog-gui): remove changelog entry 2024-10-03 09:07:10 +09:00
anatawa12
42024717fc
Merge pull request #1567 from lonelyicer/gui-locales-zh_Hans
chore(l10n): [zh_Hans] update locale
2024-10-03 08:57:41 +09:00
夜嵐蝶Alma
03b6979d8f chore(l10n): [zh_hant] update locale 2024-10-03 02:09:30 +08:00
Misaka_L
97c2d3f083
docs(changelog-gui): correct typo for key projects:dialog:vpm migrate description 2024-10-03 01:48:01 +08:00
Misaka_L
a3adf45f24
fix: correct typo 2024-10-03 01:36:18 +08:00
夜嵐蝶Alma
434dc3aba5
Merge branch 'vrc-get:master' into master 2024-10-03 00:35:26 +08:00
anatawa12
bfa988e2a3
Merge pull request #1575 from vrc-get/enable-rpm-deb-build
feat: enable rpm / deb build
2024-10-02 23:56:05 +09:00
anatawa12
02921cbf17
ci: fix deb/rpm asset path 2024-10-02 23:40:28 +09:00
anatawa12
5327658ed3
docs(changelog): rpm deb packaging for Linux 2024-10-02 23:21:14 +09:00
anatawa12
ae41c3412c
Merge branch 'master' into enable-rpm-deb-build 2024-10-02 23:17:48 +09:00
anatawa12
ad41ab1914
Merge pull request #1566 from JustBuddy/german-translation
chore(l10n): [de] update locale
2024-10-02 23:17:23 +09:00
anatawa12
c5b374b500
Merge pull request #1558 from vrc-get/china-unity-support
feat: support for china releases of Unity
2024-10-02 23:08:49 +09:00
anatawa12
a21a066a94
docs(changelog-gui): Support for China version of Unity releases like 2022.3.22f1c1 2024-10-02 22:58:29 +09:00
anatawa12
385c1467b0
Merge branch 'master' into china-unity-support 2024-10-02 22:56:52 +09:00
anatawa12
f5e681ac7b
chore: remove update button from rpm/deb releases 2024-10-02 22:11:26 +09:00
anatawa12
2cf51294be
feat: upload rpm/deb as releases 2024-10-02 21:51:53 +09:00
anatawa12
1c2a2736fe
feat: enable rpm / deb build 2024-10-02 21:39:41 +09:00
Sayamame-beans
c3a2cb7808 chore(l10n): [ja] re: update locale 2024-10-02 21:36:11 +09:00
anatawa12
00230fbcfd
fix: between China and international change dialog will not be closed on clicking use the other version 2024-10-02 21:29:24 +09:00
anatawa12
375df83880
chore: show gray star for non-favorite projects 2024-10-02 21:15:53 +09:00
anatawa12
e4ae8fa148
Merge pull request #1571 from vrc-get/add-repository-url-queue
fix: allow installing locked package with unlocked directory
2024-10-02 21:04:50 +09:00
JustBuddy
a38e1a3450
chore(l10n): [de] update locale 2024-10-02 14:01:22 +02:00
Buddy
bc24eca437
Merge branch 'master' into german-translation 2024-10-02 13:57:03 +02:00
anatawa12
c6014b9841
Merge branch 'master' into add-repository-url-queue 2024-10-02 20:56:00 +09:00
anatawa12
7dc0233ff2
docs(changelog-gui): add PR number to Several UX improvements 2024-10-02 20:55:37 +09:00
anatawa12
b5faf3bd60
fix: allow installing locked package with unlocked directory 2024-10-02 20:51:38 +09:00
Sayamame-beans
2f729b10f3
Merge branch 'master' into update_l10n_ja 2024-10-02 20:32:06 +09:00
anatawa12
49469fd31e
Merge pull request #1570 from vrc-get/add-repository-url-queue
fix: clicking add repository link will close existing adding repository dialog
2024-10-02 19:33:30 +09:00
anatawa12
a28389ca39
docs(changelog-gui): Clicking VCC link while adding vpm repository would close previously opened add repository dialog 2024-10-02 19:22:27 +09:00
夜嵐蝶Alma
c7b7b040c7
Merge branch 'vrc-get:master' into master 2024-10-02 17:49:40 +08:00
anatawa12
95b6f4f9ae
Merge pull request #1569 from vrc-get/migration-improvements
Backup and Migration improvements
2024-10-02 18:33:19 +09:00
anatawa12
a99a6f995e
fix: clicking add repository link will close existing adding repository dialog 2024-10-02 18:24:29 +09:00
anatawa12
d1832de6d8
docs(changelog): Add PR number to UX improvements 2024-10-02 16:56:31 +09:00
anatawa12
62dd753f53
feat: backup and migrate 2024-10-02 16:52:03 +09:00
anatawa12
07537a97f6
feat: migrate copy project progress 2024-10-02 16:52:03 +09:00
anatawa12
47e4a63a3b
chore: collect files to tree instead of a list 2024-10-02 16:52:03 +09:00
anatawa12
98f36c9990
feat: backup progress 2024-10-02 16:51:41 +09:00
夜嵐蝶Alma
ffb47a6ce9 chore(l10n): [zh_hant] update locale 2024-10-02 11:49:45 +08:00
RingLo_
6fa5806915 chore(l10n): [zh_Hans] update locale 2024-10-02 11:44:36 +08:00
anatawa12
c5817ecbc5
chore: ask for switching between international and china on opening projects 2024-10-02 11:29:45 +09:00
anatawa12
62f7b27df2
chore: add a suggestion to use the international version instead of a china version 2024-10-02 11:20:03 +09:00
anatawa12
ac16198fc9
chore: allow using china version of unity for migration 2024-10-02 10:57:14 +09:00
anatawa12
2654acd134
refactor: separate migration cards to another component 2024-10-02 10:32:04 +09:00
anatawa12
c17abab9fc
refactor: code paths for unity migration and version change 2024-10-02 09:44:42 +09:00
anatawa12
ced2b9af10
fix: unity patch migration is shown for china unity projects 2024-10-02 09:21:23 +09:00
anatawa12
8756b20d32
fix: detecting unity hub fails because of incorrect the registry key 2024-10-02 09:15:34 +09:00
anatawa12
6967dcc015
Merge branch 'master' into china-unity-support 2024-10-02 09:12:39 +09:00
JustBuddy
bd8f4928d9
chore(l10n): [de] update locale 2024-10-01 18:01:14 +02:00
Sayamame-beans
ddf3d202bb
Apply suggestions from code review 2024-10-01 22:37:36 +09:00
anatawa12
c4ce0d6e9d
Merge pull request #1565 from vrc-get/fix-sayamame-suggestions
fix: sayamame's suggestion
2024-10-01 22:24:31 +09:00
anatawa12
38d3337e01
docs(changelog-gui): add pr number 2024-10-01 22:03:08 +09:00
anatawa12
7b97c83b63
fix: sayamame's suggestion
Co-authored-by: Sayamame-beans <61457993+sayamame-beans@users.noreply.github.com>
2024-10-01 22:01:42 +09:00
Sayamame-beans
1cf5603475 chore(l10n): [ja] update locale 2024-10-01 21:44:09 +09:00
anatawa12
14ec9ecffa
Merge pull request #1562 from vrc-get/repository-list-format-documentation
docs: add documentation about repository file
2024-10-01 18:06:58 +09:00
anatawa12
3841444bc5
docs: add documentation about repository file 2024-10-01 17:58:08 +09:00
anatawa12
5e0280cb75
Merge pull request #1561 from vrc-get/gui-ux-improvements
Gui UX improvements
2024-10-01 17:42:41 +09:00
anatawa12
45b2d9e5c7
docs(changelog-gui): Several UX improvements 2024-10-01 17:35:50 +09:00
anatawa12
fe52791aa1
fix: shadcn separateor is not formatted with biomejs 2024-10-01 17:32:39 +09:00
anatawa12
d351eacbf1
feat: show VRC supported and unsupported unity version separately
Fix #1363
2024-10-01 17:25:05 +09:00
anatawa12
e2b8464123
fix: wait for unity hub update if unity does not be found, and it's in progress
Fix #1482
2024-10-01 16:58:21 +09:00
anatawa12
14ce9fcd13
feat: manually reload unity from unity hub
Fix #1408
2024-10-01 15:50:57 +09:00
anatawa12
04f4d71d39
Merge pull request #1560 from lonelyicer/gui-locale-zh_Hans
chore(l10n): [zh_Hans] update for #1559
2024-10-01 13:13:18 +09:00
anatawa12
1e8cb5df91
feat: more detailed add repository error
Fix #1493
2024-10-01 13:11:33 +09:00
RingLo_
14dc4bd864
chore(l10n): [zh_Hans] update for #1559 2024-10-01 11:19:25 +08:00
anatawa12
822570724d
feat: show VRChat Curated / Official repository in repository page
Fix #1492
2024-10-01 11:52:29 +09:00
anatawa12
a7eaf464fe
feat: show number of packages selected
Fix #1490
2024-10-01 11:50:59 +09:00
anatawa12
83115ae207
Merge pull request #1559 from vrc-get/migration-no-longer-experimental
migration features are no longer experimental
2024-10-01 11:02:36 +09:00
anatawa12
50204c7a0f
docs(changelog): Migration feature is no longer marked as experimental 2024-10-01 10:53:02 +09:00
anatawa12
ab283bb791
chore: remove experimental warning 2024-10-01 10:52:31 +09:00
anatawa12
f94859d464
chore: change vrc-get migrate unity 2022 to vrc-get migrate unity2022 2024-10-01 10:46:29 +09:00
anatawa12
9863797719
chore: remove beta / experimental from unity migration note 2024-10-01 10:45:40 +09:00
anatawa12
421e1f0000
feat: minimum support for china releases of Unity 2024-10-01 09:42:19 +09:00
anatawa12
cd78c86a19
Merge pull request #1557 from vrc-get/install-improvements
Installing package improvements
2024-09-30 22:06:36 +09:00
anatawa12
cc5078b835
test: remove rollback_error_in_error test 2024-09-30 21:55:11 +09:00
anatawa12
535fd42803
docs(changelog): Installing package improvements 2024-09-30 21:51:21 +09:00
anatawa12
31189b98f9
fix: conflicting unlocked packages will not be removed 2024-09-30 21:34:11 +09:00
anatawa12
9364d47ce3
chore: remove InstalledAsUnlocked error 2024-09-30 21:09:02 +09:00
anatawa12
cd61e20dc3
chore: allow installing unlocked package with conflict warnings
Fix #1393
2024-09-30 21:05:27 +09:00
anatawa12
d80baf8a96
chore: add more networking logs and enable gzip / brotli, and timeouts 2024-09-30 18:44:55 +09:00
anatawa12
6a360d7763
chore: improve downloading error behavior
Fixes #1491
2024-09-30 16:35:48 +09:00
anatawa12
badc392a89
chore: improve apply_pending_changes processing order
Improve #1491
2024-09-30 15:39:00 +09:00
anatawa12
3fdb609a18
chore: add more logs for installing packages 2024-09-30 15:36:18 +09:00
anatawa12
03dead111e
chore: add more logs for installing packages 2024-09-30 13:53:21 +09:00
dependabot[bot]
8c68c8f5d4
Merge pull request #1556 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/cli-2.0.0-rc.17 2024-09-30 03:55:25 +00:00
dependabot[bot]
b9f7ee1a6e
Merge pull request #1555 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/api-2.0.0-rc.6 2024-09-30 03:51:46 +00:00
dependabot[bot]
76bf9d9d60
Merge pull request #1554 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.446.0 2024-09-30 03:50:33 +00:00
dependabot[bot]
b2cbe35bce
chore(deps-dev): bump @tauri-apps/cli in /vrc-get-gui
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 2.0.0-rc.10 to 2.0.0-rc.17.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.0.0-rc.10...@tauri-apps/cli-v2.0.0-rc.17)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 03:34:36 +00:00
dependabot[bot]
bf4dde5c6c
chore(deps): bump @tauri-apps/api in /vrc-get-gui
Bumps [@tauri-apps/api](https://github.com/tauri-apps/tauri) from 2.0.0-rc.4 to 2.0.0-rc.6.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.0.0-rc.4...@tauri-apps/api-v2.0.0-rc.6)

---
updated-dependencies:
- dependency-name: "@tauri-apps/api"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 03:34:34 +00:00
dependabot[bot]
4cf82fc081
chore(deps): bump lucide-react from 0.438.0 to 0.446.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.438.0 to 0.446.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.446.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 03:34:28 +00:00
anatawa12
176ded4343
Merge pull request #1553 from vrc-get/bump-deps
chore(deps): bump dependencies
2024-09-30 12:31:54 +09:00
anatawa12
c942fdaa46
chore: add git-blame-ignore-revs 2024-09-30 11:59:01 +09:00
anatawa12
d7d9ba4e84
style: fix new style checks 2024-09-30 11:58:11 +09:00
anatawa12
7f24ebef0c
lint: fix noLabelWithoutControl 2024-09-30 11:56:35 +09:00
anatawa12
9cf95337bb
chore(deps): bump dependencies 2024-09-30 11:20:15 +09:00
anatawa12
590e9740b4
Merge pull request #1513 from lonelyicer/gui-locales-zh_Hans
chore(l10n): [zh_Hans] update locale
2024-09-16 22:19:22 +09:00
anatawa12
a867277c42
Merge pull request #1514 from vrc-get/update_l10n
chore(l10n): [ja] update locale ja
2024-09-15 03:05:48 +09:00
Sayamame-beans
13d449ad9c chore(l10n): [ja] improve "warn multibyte char in project name" message 2024-09-12 23:46:39 +09:00
Sayamame-beans
ec09fb8286 chore(l10n): [ja] update locale ja 2024-09-12 23:26:39 +09:00
RingLo_
4c99634fe6 chore(l10n): [zh_Hans] update locale 2024-09-12 13:05:25 +08:00
anatawa12
9a1d5e9cdd
Merge pull request #1494 from Spokeek/french-translation
French translation
2024-09-12 14:00:57 +09:00
Spokeek
349129fcfa
Added missing key 2024-09-11 20:25:49 +02:00
Spokeek
95a2b53dec
Removed unused localization migration script 2024-09-11 20:11:33 +02:00
Spokeek
ebd0566c0f
Added node shebang for easier use 2024-09-11 20:11:33 +02:00
Spokeek
cd80c99b30
Revert "Added changelog entry"
This reverts commit 46f32b09bde48f0b81308ccac4e57f3d6017b113.
2024-09-11 20:11:28 +02:00
Spokeek
7abb213f08
Updated script to remove excessing keys 2024-09-11 20:11:06 +02:00
Spokeek
68f1328587
Added changelog entry 2024-09-11 20:10:58 +02:00
Spokeek
58b279033b
Run Script to add keys + Translate 2024-09-11 20:10:31 +02:00
Spokeek
d5866d04fb
Added a helper script to add missing keys + format fr to match new format 2024-09-11 20:10:31 +02:00
anatawa12
585a904acc
Merge pull request #1496 from JustBuddy/quicklinks
chore(gui): Separate quick open actions
2024-09-11 20:05:43 +09:00
JustBuddy
5bd331170f
chore(lang): Adjusted wording for new key. 2024-09-09 20:58:52 +02:00
JustBuddy
2b92cdbf87
chore(lang): Related hotfix for german locale. 2024-09-08 17:13:04 +02:00
JustBuddy
e29be7c19c
chore(lang): adjusted wording to directories 2024-09-08 17:11:45 +02:00
JustBuddy
d79795ff08
chore: added changelog entry. 2024-09-08 17:05:01 +02:00
JustBuddy
f2a10e0c83
chore(lang): adjusted key position in other locales where applicable. 2024-09-08 17:00:08 +02:00
JustBuddy
e1c7106802
fix lint issues. 2024-09-08 16:45:35 +02:00
JustBuddy
95e38baf61
chore(gui): Seperate quick open actions 2024-09-08 16:40:40 +02:00
github-actions[bot]
bb0d53c9bd v1.9.0-beta.1 2024-09-05 11:51:06 +00:00
github-actions[bot]
4c8d686f8f chore: prepare for next version: gui 0.1.16 2024-09-05 11:49:37 +00:00
github-actions[bot]
eb5c2ca120 gui v0.1.15 2024-09-05 11:29:54 +00:00
anatawa12
d45feb9e8e
Merge pull request #1489 from vrc-get/update-notes
docs(notes): write notes for 0.1.15
2024-09-05 20:29:16 +09:00
anatawa12
f638f42383
docs(notes): write notes for 0.1.15 2024-09-05 20:25:34 +09:00
dependabot[bot]
e7b5618c89
Merge pull request #1471 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/lucide-react-0.438.0 2024-09-03 19:43:14 +00:00
dependabot[bot]
c191e6359d
Merge pull request #1469 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/api-2.0.0-rc.4 2024-09-03 19:42:54 +00:00
dependabot[bot]
395d836129
Merge pull request #1472 from vrc-get/dependabot/npm_and_yarn/vrc-get-gui/tauri-apps/cli-2.0.0-rc.10 2024-09-03 19:42:32 +00:00
anatawa12
3bd35f3eca
Merge pull request #1488 from vrc-get/bump-next-cli-version
chore: bump next cli version to 1.9.0
2024-09-04 04:39:37 +09:00
anatawa12
2cc245dd5e
Merge pull request #1487 from vrc-get/update-deps
chore(deps): upgrade deps
2024-09-04 04:39:14 +09:00
anatawa12
d3a2637eb8 chore: bump next cli version to 1.9.0 2024-09-04 04:30:04 +09:00
anatawa12
30916a2df3 fix: compile errors 2024-09-04 04:18:27 +09:00
anatawa12
4cfaf4188a chore(deps): upgrade deps 2024-09-04 03:28:20 +09:00
anatawa12
6f0b5ecde1
Merge pull request #1484 from vrc-get/fix-project-name-on-windows
fix: the project path is shown instead of name
2024-09-04 03:06:31 +09:00
anatawa12
5806e7b60e
Merge branch 'master' into fix-project-name-on-windows 2024-09-04 02:56:20 +09:00
anatawa12
c40762e962
docs(changelog-gui): Project Path is shown instead of Project Name 2024-09-02 23:23:27 +09:00
anatawa12
5ee85b11c1
fix: the project path is shown instead of name 2024-09-02 23:21:51 +09:00
dependabot[bot]
435ee2ed64
chore(deps-dev): bump @tauri-apps/cli in /vrc-get-gui
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 2.0.0-rc.4 to 2.0.0-rc.10.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.0.0-rc.4...@tauri-apps/cli-v2.0.0-rc.10)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-02 07:44:50 +00:00
dependabot[bot]
369445a20a
chore(deps): bump lucide-react from 0.436.0 to 0.438.0 in /vrc-get-gui
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.436.0 to 0.438.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.438.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-02 07:44:44 +00:00
dependabot[bot]
fa784af2fd
chore(deps): bump @tauri-apps/api in /vrc-get-gui
Bumps [@tauri-apps/api](https://github.com/tauri-apps/tauri) from 2.0.0-rc.3 to 2.0.0-rc.4.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/api-v2.0.0-rc.3...@tauri-apps/api-v2.0.0-rc.4)

---
updated-dependencies:
- dependency-name: "@tauri-apps/api"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-02 07:44:29 +00:00
538 changed files with 43920 additions and 22655 deletions

2
.cargo/config.toml Normal file
View file

@ -0,0 +1,2 @@
[alias]
xtask = "run --profile xtask --target host-tuple -p xtask --"

View file

@ -1,2 +1,4 @@
# reformat with biomejs
798da7111ab611c07ff7171574cd2ab9e8254515
# reformat with biomejs 1.9.2
d7d9ba4e84925794e60e4ba194f96c6932418d29

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

2
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,2 @@
github: [anatawa12]
custom: [https://booth.pm/ja/items/6448396]

50
.github/actions/sign-windows/action.yml vendored Normal file
View file

@ -0,0 +1,50 @@
name: 'Sign in place'
description: 'Signs exe in-place'
inputs:
signpath-api-token:
description: SignPath REST API access token.
required: true
signing-policy-slug:
description: SignPath signing policy slug
version:
required: true
description: Version number of artifact we're signing
path:
description: The path of artifact we'll sign
required: true
artifact-name:
description: The name of artifact on github
required: true
runs:
using: "composite"
steps:
- name: upload unsigned artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
with:
path: ${{ inputs.path }}
name: ${{ inputs.artifact-name }}
- name: Sign on signpath
id: sign
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: ${{ inputs.signpath-api-token }}
organization-id: 'c2d4dbf9-920f-4318-9017-7306e0fc7590'
project-slug: 'vrc-get'
signing-policy-slug: ${{ inputs.signing-policy-slug }}
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: .github/actions/sign-windows/signed/${{ inputs.artifact-name }}
parameters: |
version: ${{ toJSON(inputs.version) }}
- name: Copy artifact
env:
DOWNLOADED_PATH: .github/actions/sign-windows/signed/${{ inputs.artifact-name }}
REPLACE_TO: ${{ inputs.path }}
shell: bash
run:
cp -f "$DOWNLOADED_PATH/$(basename "$REPLACE_TO")" "$REPLACE_TO"

8
.github/copilot-instructions.md vendored Normal file
View file

@ -0,0 +1,8 @@
If you're writing code:
- Please don't make localization for locales other than en / ja. I cannot review those locales.
- Run cargo clippy for lints and cargo fmt for format before commit.
- After completing the code and commit, please add a changelog entry. Please note that the numbers in the changelog file are pull request numbers, not issue numbers.
- Please add it to the bottom of the change list.
- Please use the proper section for each change. "Fix" should be used only for bug fixes. UX improvements typically belong under "Change", and new features typically under "Add". These are not strict rules, so use them flexibly.
- You should use Conventional Commits (chore:, fix:, dev:, build:, docs:, style:, lint:, and others).
- Please split commits for implementation and changelog updates.

View file

@ -8,6 +8,8 @@ updates:
groups:
tauri:
patterns: [ 'tauri', 'tauri-build' ]
clap:
patterns: [ 'clap', 'clap_complete' ]
- package-ecosystem: github-actions
directory: "/"
open-pull-requests-limit: 20
@ -23,3 +25,9 @@ updates:
patterns: [ "@radix-ui/*" ]
react:
patterns: [ "react", "react-dom", "@types/react", "@types/react-dom" ]
tanstack-router:
patterns: [ "@tanstack/*router*" ]
tailwindcss:
patterns: [ "tailwindcss", "@tailwindcss/*" ]
i18next:
patterns: [ "i18next", "react-i18next" ]

View file

@ -48,11 +48,28 @@ module.exports = async ({github, context}) => {
discussionNumber: 1443,
replyId: 'DC_kwDOIza9ks4An6A8'
},
{
id: 'ko',
discussionNumber: 1823,
replyId: 'DC_kwDOIza9ks4AswKE'
},
];
/** @type {{missingCount: number, extraCount: number, id: string, discussionNumber: number}[]} */
const localeData = [];
for (const locale of locales) {
await processOneLocale(github, owner, repo, locale.discussionNumber, locale.replyId, locale.id);
const proceed = await processOneLocale(github, owner, repo, locale.discussionNumber, locale.replyId, locale.id);
localeData.push({
id: locale.id,
discussionNumber: locale.discussionNumber,
missingCount: proceed.missingCount,
extraCount: proceed.extraCount,
})
}
// 894 is English Localization and Text Representation
await updateRootLocale(github, owner, repo, 894, localeData);
}
/**
@ -63,9 +80,113 @@ module.exports = async ({github, context}) => {
* @param number {number}
* @param replyToId {string}
* @param localeId {string}
* @return {Promise<void>}
* @return {Promise<{missingCount: number, extraCount: number}>}
*/
async function processOneLocale(github, owner, repo, number, replyToId, localeId) {
const enJson = json5.parse(await fs.readFile(`vrc-get-gui/locales/en.json5`, "utf8"));
const enKeys = normalizeKeys(Object.keys(enJson.translation));
const transJson = json5.parse(await fs.readFile(`vrc-get-gui/locales/${localeId}.json5`, "utf8"));
const transKeys = normalizeKeys(Object.keys(transJson.translation));
const {missingList: missingKeys, extraList: extraKeys} = missingAndExtras(enKeys, transKeys);
const newData = {
missingKeys,
extraKeys,
};
const newAutoPart = `**Missing Keys:**\n${listToMarkdown(missingKeys)}\n\n**Excess Keys:**\n${listToMarkdown(extraKeys)}\n`;
const {discussionId, previousJson: dataJson} = await updateComment(github, owner, repo, number, newAutoPart, newData);
dataJson.missingKeys ??= [];
dataJson.extraKeys ??= [];
// create comment if there are new missing / extra keys
const {extraList: newlyAddedMissingKeys} = missingAndExtras(normalizeKeys(dataJson.missingKeys), missingKeys);
const {extraList: newlyAddedExtraKeys} = missingAndExtras(normalizeKeys(dataJson.extraKeys), extraKeys);
if (newlyAddedMissingKeys.length > 0 || newlyAddedExtraKeys.length > 0) {
const text = `
There are new missing / excess keys in the translation. Please update the translation!
**New Missing Keys:**
${listToMarkdown(newlyAddedMissingKeys)}
**New Excess Keys:**
${listToMarkdown(newlyAddedExtraKeys)}
`
await github.graphql(`
mutation($discussionId: ID!, $replyToId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, replyToId: $replyToId, body: $body}) {
comment {
body
}
}
}
`, {discussionId, replyToId, body: text});
}
return {
missingCount: missingKeys.length,
extraCount: extraKeys.length,
}
}
/**
* Updates the root locale configuration for a specified repository.
*
* @param {import('@octokit/rest').Octokit} github - The GitHub API client instance used to interact with the GitHub API.
* @param {string} owner - The owner of the repository where the root locale is to be updated.
* @param {string} repo - The name of the repository where the root locale is to be updated.
* @param {number} number
* @param {{missingCount: number, extraCount: number, id: string, discussionNumber: number}[]} localeData - The locale data object containing the updated root locale configuration.
* @return {Promise<void>} A promise that resolves to the API response for the update operation.
*/
async function updateRootLocale(github, owner, repo, number, localeData) {
let table = "| locale | missing count | exceeding count | link |\n" +
"| -- | -- | -- | -- |\n"
for (let {missingCount, extraCount, id, discussionNumber} of localeData) {
table += `| ${id} | ${missingCount} | ${extraCount} | [link](https://github.com/${owner}/${repo}/discussions/${discussionNumber}) |\n`;
}
await updateComment(github, owner, repo, number, table, {});
}
/**
* @template T
* @param beforeList {T[]}
* @param afterList {T[]}
* @return {{missingList: T[], extraList: T[]}}
*/
function missingAndExtras(beforeList, afterList) {
const missingList = beforeList.filter(key => !afterList.includes(key)).filter(key => !optionalKeys.includes(key));
const extraList = afterList.filter(key => !beforeList.includes(key)).filter(key => !optionalKeys.includes(key));
return {missingList, extraList};
}
function listToMarkdown(values) {
return values.length === 0 ? 'nothing' : values.map(key => `- \`${key}\``).join('\n')
}
/**
*
* @param github {import('@octokit/rest').Octokit}
* @param owner {string}
* @param repo {string}
* @param number {number}
* @param content {string} the updated content
* @param newData {object} data stored in the comment
* @return {Promise<{previousJson: object, discussionId:string}>}
*/
async function updateComment(
github,
owner, repo, number,
content,
newData,
) {
/** @type {{data: {repository: {discussion: {body: string}}}}} */
const result = await github.graphql(`
query($owner: String!, $repo: String!, $number: Int!) {
@ -93,42 +214,14 @@ async function processOneLocale(github, owner, repo, number, replyToId, localeId
const postAutoPart = split1[1] ?? '';
const dataJsonLine = autoPart.split(/\r?\n/).find(l => l.startsWith(dataJsonLinePrefix));
// the dataJson is for computing the difference and create new comment if there are changes
const dataJson = dataJsonLine ? JSON.parse(dataJsonLine.slice(dataJsonLinePrefix.length)) : {};
dataJson.missingKeys ??= [];
dataJson.extraKeys ??= [];
const enJson = json5.parse(await fs.readFile(`vrc-get-gui/locales/en.json5`, "utf8"));
const enKeys = normalizeKeys(Object.keys(enJson.translation));
const transJson = json5.parse(await fs.readFile(`vrc-get-gui/locales/${localeId}.json5`, "utf8"));
const transKeys = normalizeKeys(Object.keys(transJson.translation));
const missingKeys = enKeys.filter(key => !transKeys.includes(key)).filter(key => !optionalKeys.includes(key));
const extraKeys = transKeys.filter(key => !enKeys.includes(key)).filter(key => !optionalKeys.includes(key));
const missingKeysStr = missingKeys.length === 0 ? 'nothing' : missingKeys.map(key => `- \`${key}\``).join('\n');
const excessKeysStr = extraKeys.length === 0 ? 'nothing' : extraKeys.map(key => `- \`${key}\``).join('\n');
const newData = {
missingKeys,
extraKeys,
};
const newAutoPart = `
**Missing Keys:**
${missingKeysStr}
**Excess Keys:**
${excessKeysStr}
const previousJson = dataJsonLine ? JSON.parse(dataJsonLine.slice(dataJsonLinePrefix.length)) : {};
const newBody = `${manualPart}${autoPartStart}
${content}
<!-- data part
${dataJsonLinePrefix}${JSON.stringify(newData)}
-->
`;
const newBody = `${manualPart}${autoPartStart}${newAutoPart}${autoPartEnd}${postAutoPart}`;
${autoPartEnd}${postAutoPart}`;
await github.graphql(`
mutation($discussionId: ID!, $body: String!) {
@ -140,36 +233,9 @@ ${dataJsonLinePrefix}${JSON.stringify(newData)}
}
`, {discussionId, body: newBody});
// create comment if there are new missing / extra keys
const oldMissingKeys = new Set(normalizeKeys(dataJson.missingKeys));
const oldExtraKeys = new Set(normalizeKeys(dataJson.extraKeys));
const newlyAddedMissingKeys = missingKeys.filter(key => !oldMissingKeys.has(key));
const newlyAddedExtraKeys = extraKeys.filter(key => !oldExtraKeys.has(key));
if (newlyAddedMissingKeys.length > 0 || newlyAddedExtraKeys.length > 0) {
const newMissingKeysStr = newlyAddedMissingKeys.length === 0 ? 'nothing' : newlyAddedMissingKeys.map(key => `- \`${key}\``).join('\n');
const newExcessKeysStr = newlyAddedExtraKeys.length === 0 ? 'nothing' : newlyAddedExtraKeys.map(key => `- \`${key}\``).join('\n');
const text = `
There are new missing / excess keys in the translation. Please update the translation!
**New Missing Keys:**
${newMissingKeysStr}
**New Excess Keys:**
${newExcessKeysStr}
`
await github.graphql(`
mutation($discussionId: ID!, $replyToId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, replyToId: $replyToId, body: $body}) {
comment {
body
}
}
}
`, {discussionId, replyToId, body: text});
return {
previousJson,
discussionId,
}
}

View file

@ -4,7 +4,6 @@ on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
CARGO_TERM_COLOR: always
@ -16,7 +15,8 @@ jobs:
matrix:
include:
- triple: x86_64-unknown-linux-gnu
on: ubuntu-latest
on: ubuntu-22.04
bundles: appimage,appimage-updater
setup: |
sudo apt update && sudo apt install -y lld
ld.lld --version
@ -26,12 +26,14 @@ jobs:
- triple: x86_64-pc-windows-msvc
on: windows-latest
bundles: setup-exe,setup-exe-zip,exe-updater
- triple: universal-apple-darwin
on: macos-14
setup: |
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
bundles: app,dmg,app-updater
triple:
- x86_64-unknown-linux-gnu
#- aarch64-unknown-linux-gnu
@ -44,9 +46,25 @@ jobs:
RUSTFLAGS: ${{ matrix.rustflags }}
steps:
- uses: actions/checkout@v4
- uses: samypr100/setup-dev-drive@v4
with:
drive-size: 12GB # github actions grantees 14 GB of disk space. we have few GB for action environment
drive-path: "/dev_drive.vhdx"
mount-path: ${{ github.workspace }}
trusted-dev-drive: true
- name: Preinitialize git repository
shell: bash
run: |
# hopefully for non-cleaning environments, actions/checkout will tries to clean existing repository
# if existing dir is not git repository nor for specified repository.
# this step creates git directory to workaround the behavior
git init
git remote add origin "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
- uses: actions/checkout@v6
with:
submodules: recursive
- run: rustup update stable
- name: Install cross-compilation tools
uses: taiki-e/setup-cross-toolchain-action@v1
if: ${{ matrix.triple != 'universal-apple-darwin' }}
@ -55,11 +73,8 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
key: ci-build-gui-${{ matrix.triple }}
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.2xx
- name: Cache javascript essentials
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.npm
@ -68,11 +83,6 @@ jobs:
key: ${{ runner.os }}-nextjs-${{ hashFiles('vrc-get-gui/package-lock.json') }}-${{ hashFiles('vrc-get-gui/**/*.js', 'vrc-get-gui/**/*.jsx', 'vrc-get-gui/**/*.ts', 'vrc-get-gui/**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('vrc-get-gui/package-lock.json') }}-
- uses: taiki-e/install-action@v2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tool: cargo-about
- name: Setup
run: ${{ matrix.setup }}
@ -92,20 +102,16 @@ jobs:
cp vrc-get-gui/Tauri.toml vrc-get-gui/Tauri.toml.bak
grep -v "remove if ci" < vrc-get-gui/Tauri.toml.bak > vrc-get-gui/Tauri.toml
- name: Enable Devtools Feature
shell: bash
run: |
cargo add --package vrc-get-gui tauri --features devtools
- name: Build ALCOM binary
run:
cargo xtask build-alcom --release --target ${{ matrix.triple }} --devtools ${{ (secrets.ACTIONS_STEP_DEBUG || vars.ACTIONS_STEP_DEBUG) == 'true' && '--verbose' || '' }}
- uses: tauri-apps/tauri-action@v0
with:
projectPath: vrc-get-gui
tauriScript: npm run tauri
args: |
--target ${{ matrix.triple }} -c '{"version":"${{ steps.version.outputs.version }}", "bundle":{"windows":{"certificateThumbprint": null}}}'
- name: Build installer
shell: bash
run: cargo xtask bundle-alcom --release --target ${{ matrix.triple }} --bundles ${{ matrix.bundles }}
- name: Upload built binary
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.triple }}
path: |
@ -116,6 +122,195 @@ jobs:
target/${{ matrix.triple }}/release/bundle/*/ALCOM*
target/${{ matrix.triple }}/release/bundle/*/alcom*
build-rpm:
strategy:
fail-fast: false
matrix:
include:
- install_rust: false
- no_dist: false
- mock-env: fedora-40-x86_64
install_rust: true
no_dist: true
mock-env:
- fedora-40-x86_64
- fedora-rawhide-x86_64
runs-on: ubuntu-latest
container:
image: 'fedora:latest'
options: --privileged
env:
MOCK_ENV: ${{ matrix.mock-env }}
RPMBUILD_OPTS: ${{ case(matrix.no_dist, '-D "dist %{nil}"', '') }} ${{ case(matrix.install_rust, '-D "install_rust 1"', '') }}
steps:
- name: Install CI dependencies
run: dnf install -y git tar curl
- uses: actions/checkout@v6
with:
submodules: recursive
# https://github.com/actions/checkout/issues/1169
- run: git config --system --add safe.directory $GITHUB_WORKSPACE
- name: install dependencies
run: dnf install -y mock rpmbuild
- name: prepare rpm build environment
run: mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
- name: update version name in spec file
run: |
COMMIT_HASH="$(git rev-parse HEAD)"
SHORT_HASH="$(git rev-parse --short HEAD)"
PKG_VERSION="$(<vrc-get-gui/Cargo.toml sed -En -e '/^version/{s/.*"(.*)".*/\1/p;}')+${SHORT_HASH}"
echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV
cp vrc-get-gui/Cargo.toml vrc-get-gui/Cargo.toml.bak
sed -E "/^version/s/\"$/+$(git rev-parse --short HEAD)\"/" < vrc-get-gui/Cargo.toml.bak > vrc-get-gui/Cargo.toml
rm vrc-get-gui/Cargo.toml.bak
git add vrc-get-gui/Cargo.toml
sed -i vrc-get-gui/bundle/alcom.spec -e "/^Version:/c\Version: ${PKG_VERSION//-/\~}"
- name: build source rpm package
run: |
git archive --format=tar --prefix=vrc-get-gui-v$PKG_VERSION/ $(git write-tree) | gzip > ~/rpmbuild/SOURCES/gui-v$PKG_VERSION.tar.gz
eval "rpmbuild -bs vrc-get-gui/bundle/alcom.spec $RPMBUILD_OPTS"
- name: build rpm package
run: eval "mock -v -r '$(ls -1 /etc/mock{/eol,}/$MOCK_ENV.cfg 2>/dev/null)' --enable-network $RPMBUILD_OPTS rebuild ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm"
- name: copy built binaries
run: |
mkdir -p artifacts
cp ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm artifacts/
cp /var/lib/mock/$MOCK_ENV/result/alcom-${PKG_VERSION//-/\~}-1*.${MOCK_ENV##*-}.rpm artifacts/
- name: Upload built binary
uses: actions/upload-artifact@v7
with:
name: rpm-${{ matrix.mock-env }}
path: artifacts/*
build-deb:
strategy:
fail-fast: false
matrix:
include:
- install_rust: false
- install_nodejs: false
- apt-components: main
- apt-with-updates: false
# Old distributions have older tools than we need. Download tools in build process
- pbuilder-distribution: bookworm
install_rust: true
install_nodejs: true
- pbuilder-distribution: jammy
install_rust: true
install_nodejs: true
# Debian uses mirror from debian-archive.trafficmanager.net which is managed by microsoft on azure
- pbuilder-distribution: bookworm
mirror: http://debian-archive.trafficmanager.net/debian/
keyring: /usr/share/keyrings/debian-archive-keyring.gpg
- pbuilder-distribution: sid
mirror: http://debian-archive.trafficmanager.net/debian/
keyring: /usr/share/keyrings/debian-archive-keyring.gpg
# Ubuntu legacy release
- pbuilder-distribution: jammy
mirror: http://archive.ubuntu.com/ubuntu/
apt-components: main universe
apt-with-updates: true
keyring: /usr/share/keyrings/ubuntu-archive-keyring.gpg
# For note,
# bookworm: libc6@2.36
# sid: libc6@2.39 as of 2026/06/14
# jammy: libc6@2.35
pbuilder-distribution:
# debian distribution
- bookworm
- sid
# ubuntu distribution
- jammy # jammy is the oldest ubuntu release with libwebkit2gtk-4.1 >= 2.41 (but requires -updates and universe)
target-arch:
- amd64
runs-on: ubuntu-latest
env:
TARGET_ARCH: ${{ matrix.target-arch }}
PBUILDER_DISTRIBUTION: ${{ matrix.pbuilder-distribution }}
PBUILDER_MIRROR: ${{ matrix.mirror }}
PBUILDER_KEYRING: ${{ matrix.keyring }}
PBUILDER_COMPONENTS: ${{ matrix.apt-components }}
PBUILDER_OTHERMIRROR: ${{ case(matrix.apt-with-updates, format('deb {0} {1}-updates {2}', matrix.mirror, matrix.pbuilder-distribution, matrix.apt-components), '') }}
INSTALL_RUST: ${{ case(matrix.install_rust, '1', '0') }}
INSTALL_NODEJS: ${{ case(matrix.install_nodejs, '1', '0') }}
steps:
- uses: actions/checkout@v6
with:
path: vrc-get
submodules: recursive
- name: install dependencies
run: sudo apt update && sudo apt install -y pbuilder debian-archive-keyring debhelper-compat=13
- name: prepare deb build environment
working-directory: vrc-get
run: |
cp -r vrc-get-gui/bundle/debian debian
sudo pbuilder create \
--architecture "$TARGET_ARCH" \
--keyring "$PBUILDER_KEYRING" \
--mirror "$PBUILDER_MIRROR" \
--distribution "$PBUILDER_DISTRIBUTION" \
--components "$PBUILDER_COMPONENTS" \
--othermirror "$PBUILDER_OTHERMIRROR"
- name: update changelog
working-directory: vrc-get
run: |
COMMIT_HASH="$(git rev-parse HEAD)"
SHORT_HASH="$(git rev-parse --short HEAD)"
PKG_VERSION="$(<vrc-get-gui/Cargo.toml sed -En -e '/^version/{s/.*"(.*)".*/\1/p;}')+${SHORT_HASH}"
echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV
cp debian/changelog debian/changelog.bak
cat - debian/changelog.bak <<CHANGELOG > debian/changelog
alcom (${PKG_VERSION//-/\~}-1) experimental;
* Upgraded version to ${PKG_VERSION}
-- anatawa12 <i@anatawa12.com> $(date -u +"%a, %d %b %Y %H:%M:%S +0000")
CHANGELOG
rm debian/changelog.bak
cp vrc-get-gui/Cargo.toml vrc-get-gui/Cargo.toml.bak
sed -E "/^version/s/\"$/+$(git rev-parse --short HEAD)\"/" < vrc-get-gui/Cargo.toml.bak > vrc-get-gui/Cargo.toml
rm vrc-get-gui/Cargo.toml.bak
git add vrc-get-gui/Cargo.toml
echo cat debian/changelog
cat debian/changelog
dpkg-parsechangelog
- name: build source deb package
working-directory: vrc-get
run: |
git archive --format=tar $(git write-tree) | xz > ../alcom_${PKG_VERSION//-/\~}.orig.tar.xz
dpkg-buildpackage -d -S
- name: build deb package
working-directory: vrc-get
run: |
sudo --preserve-env=INSTALL_RUST,INSTALL_NODEJS pbuilder build --use-network yes ../alcom_${PKG_VERSION//-/\~}-1.dsc
- name: copy built binaries
run: |
mkdir -p artifacts
cp vrc-get/debian/changelog artifacts/
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}* artifacts/
ls artifacts
- name: Print information about built package
run: dpkg-deb -I artifacts/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb
- name: Upload built binary
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
with:
name: deb-${{ matrix.pbuilder-distribution }}-${{ matrix.target-arch }}
path: artifacts/*
conclude-gui:
runs-on: ubuntu-latest
if: ${{ always() }}

View file

@ -4,7 +4,6 @@ on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
CARGO_TERM_COLOR: always
@ -74,7 +73,7 @@ jobs:
RUSTFLAGS: ${{ matrix.rustflags }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: dtolnay/rust-toolchain@stable
@ -87,9 +86,6 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
key: ci-build-${{ matrix.triple }}
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.2xx
- name: Setup
run: ${{ matrix.setup }}
@ -103,24 +99,24 @@ jobs:
- name: Build
run: cargo build --verbose --target ${{ matrix.triple }}
- name: Upload built binary
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.triple }}
path: |
target/${{ matrix.triple }}/debug/vrc-get*
target/${{ matrix.triple }}/debug/libvrc-get*
- name: Build tests
run: cargo build --tests --target ${{ matrix.triple }}
run: cargo build --tests --target ${{ matrix.triple }} -p vrc-get -p vrc-get-vpm
- name: Run tests
if: ${{ matrix.run-test }}
run: cargo test --verbose --target ${{ matrix.triple }}
run: cargo test --verbose --target ${{ matrix.triple }} -p vrc-get -p vrc-get-vpm
- name: Check binary is statically linked
shell: bash
if: ${{ matrix.static-linked }}
env:
RUSTFLAGS: ''
run: |
# https://github.com/taiki-e/setup-cross-toolchain-action/issues/18
unset CARGO_BUILD_TARGET
cargo run -p build-check-static-link target/${{ matrix.triple }}/debug/vrc-get*
cargo xtask check-static-link target/${{ matrix.triple }}/debug/vrc-get${WINDIR:+.exe}
conclude:
runs-on: ubuntu-latest

View file

@ -9,11 +9,11 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/labeler@v5
- uses: actions/labeler@v6
with:
repo-token: ${{ steps.app-token.outputs.token }}

View file

@ -17,7 +17,7 @@ jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- run: cargo fmt --all -- --check
@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive
@ -40,10 +40,7 @@ jobs:
run:
sudo apt update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.2xx
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.cargo/bin/
@ -53,13 +50,12 @@ jobs:
target/
key: lints-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: auguwu/clippy-action@1.4.0
- uses: auguwu/clippy-action@1.5.0
with:
token: ${{secrets.GITHUB_TOKEN}}
check-args: --all --all-targets --all-features
check-args: --all --all-targets --all-features --exclude windows-installer-wrapper
args: -Dclippy::todo -Dwarnings
biome:
permissions:
contents: read
@ -67,7 +63,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: run Biome
working-directory: vrc-get-gui
run: npm run biome -- ci
typecheck:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: run Type Check
working-directory: vrc-get-gui
run: npm ci && npx tsc

View file

@ -12,13 +12,13 @@ jobs:
contents: read
discussions: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '20.x'
- run: npm i --omit=dev
working-directory: .github/scripts
- uses: actions/github-script@v7
- uses: actions/github-script@v9
with:
script: |
const script = require('./.github/scripts/localization-updates.js')

View file

@ -18,6 +18,9 @@ on:
default: true
required: false
concurrency:
group: releasing
jobs:
pre-build:
name: Update version name
@ -28,11 +31,12 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: anatawa12/something-releaser@v3
- uses: snow-actions/git-config-user@v1.0.0
- run: rustup update stable
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
@ -63,6 +67,21 @@ jobs:
;;
esac
GUI_VERSION="$(get-version -t gui)"
# update debian package
cp vrc-get-gui/bundle/debian/changelog vrc-get-gui/bundle/debian/changelog.bak
cat - vrc-get-gui/bundle/debian/changelog.bak <<CHANGELOG > vrc-get-gui/bundle/debian/changelog
alcom (${GUI_VERSION//-/\~}-1) stable;
* Upgraded version to ${GUI_VERSION}
-- anatawa12 <i@anatawa12.com> $(date -u +"%a, %d %b %Y %H:%M:%S +0000")
CHANGELOG
rm vrc-get-gui/bundle/debian/changelog.bak
# update rpm package
sed -i vrc-get-gui/bundle/alcom.spec -e "/^Version:/c\Version: ${GUI_VERSION//-/\~}"
case "$GITHUB_REF_NAME" in
master | master-* )
echo "head is master or master-*"
@ -77,7 +96,7 @@ jobs:
;;
esac
gh-export-variable GUI_VERSION "$(get-version -t gui)"
gh-export-variable GUI_VERSION "${GUI_VERSION}"
env:
RELEASE_KIND_IN: ${{ inputs.release_kind }}
DRY_RUN: ${{ inputs.dry-run }}
@ -85,14 +104,11 @@ jobs:
# region changelog
- name: Create Changelog
id: changelog
# if: ${{ !steps.update-version.outputs.prerelease }}
uses: anatawa12/sh-actions/changelog/prepare-release@master
with:
path: CHANGELOG-gui.md
version: ${{ env.GUI_VERSION }}
# use CHANGELOG-gui.md for all releases including beta for now
# there are several logics uses generated changelog, so remember to update them if you change this
prerelease: false # ${{ env.PRERELEASE }}
prerelease: ${{ env.PRERELEASE }}
tag-prefix: gui-v
prerelease-note-heading: |
Version ${{ env.GUI_VERSION }}
@ -101,41 +117,21 @@ jobs:
Version ${{ env.GUI_VERSION }}
---
- name: Upload CHANGELOG.md
# if: ${{ !steps.update-version.outputs.prerelease }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: CHANGELOG
path: CHANGELOG.md
- name: copy release note
# if: ${{ !steps.update-version.outputs.prerelease }}
run: cp "${{ steps.changelog.outputs.release-note }}" release-note.md
- name: Upload release note
# if: ${{ !steps.update-version.outputs.prerelease }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: release-note-for-release
path: release-note.md
- name: remove temp release note file
# if: ${{ !steps.update-version.outputs.prerelease }}
run: rm release-note.md
# endregion changelog
# region notes
- name: Reset notes.txt
if: ${{ !steps.update-version.outputs.prerelease }}
run: |
cat <<SHELL > vrc-get-gui/notes.txt
# This is notes text for the updater json, which will be shown in the updater dialog.
# Lines starting with '#' will be ignored (as comments).
SHELL
- name: Reset notes-beta.txt
run: |
cat <<SHELL > vrc-get-gui/notes-beta.txt
# This is notes text for the updater json, which will be shown in the updater dialog.
# Lines starting with '#' will be ignored (as comments).
SHELL
# endregion
- name: Commit
id: update
run: |-
@ -144,29 +140,6 @@ jobs:
git branch releasing
git push -f -u origin releasing
build-web:
name: Build gui web
runs-on: ubuntu-latest
needs: [ pre-build ]
steps:
- uses: actions/checkout@v4
with:
ref: 'releasing'
submodules: recursive
- uses: taiki-e/install-action@v2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tool: cargo-about
- run: npm run build
working-directory: vrc-get-gui
- uses: actions/upload-artifact@v4
with:
name: vrc-get-gui-web
path: vrc-get-gui/out
build-rust:
name: Build rust
environment:
@ -177,57 +150,67 @@ jobs:
include:
# note: when you changed paths for tauri updater (which are files with .sig),
# remember keep in sync with build-updater-json
- triple: x86_64-unknown-linux-gnu
on: ubuntu-latest
- name: x86_64-linux-appimage
triple: x86_64-unknown-linux-gnu
on: ubuntu-22.04
setup: |
sudo apt update && sudo apt install -y lld
ld.lld --version
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
rustflags: "-C link-arg=-fuse-ld=lld"
last-bundles: appimage,appimage-updater
updater-bundle: bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage.tar.gz
dist-path: |
bundle/appimage/ALCOM_${GUI_VERSION}_amd64.AppImage:alcom-${GUI_VERSION}-x86_64.AppImage
bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage:alcom-${GUI_VERSION}-x86_64.AppImage
bundle/appimage/ALCOM_${GUI_VERSION}_amd64.AppImage.tar.gz:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz
bundle/appimage/ALCOM_${GUI_VERSION}_amd64.AppImage.tar.gz.sig:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz.sig
bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage.tar.gz:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz
bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage.tar.gz.sig:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz.sig
- triple: x86_64-pc-windows-msvc
on: windows-latest
esigner: true
- name: x86_64-windows-all
triple: x86_64-pc-windows-msvc
on: windows-2022
last-bundles: setup-exe-zip,exe-updater
updater-bundle: bundle/setup/alcom-updater.exe
dist-path: |
ALCOM.exe:ALCOM-${GUI_VERSION}-x86_64.exe
bundle/nsis/ALCOM_${GUI_VERSION}_x64-setup.exe:ALCOM-${GUI_VERSION}-x86_64-setup.exe
bundle/nsis/ALCOM_${GUI_VERSION}_x64-setup.nsis.zip:ALCOM-${GUI_VERSION}-x86_64-setup.nsis.zip
bundle/nsis/ALCOM_${GUI_VERSION}_x64-setup.nsis.zip.sig:ALCOM-${GUI_VERSION}-x86_64-setup.nsis.zip.sig
bundle/setup/alcom-setup.exe:ALCOM-${GUI_VERSION}-x86_64-setup.exe
bundle/setup/alcom-setup.exe.zip:ALCOM-${GUI_VERSION}-x86_64-setup.exe.zip
bundle/setup/alcom-updater.exe:ALCOM-${GUI_VERSION}-x86_64-updater.exe
bundle/setup/alcom-updater.exe.sig:ALCOM-${GUI_VERSION}-x86_64-updater.exe.sig
- triple: universal-apple-darwin
- name: universal-macos-all
triple: universal-apple-darwin
on: macos-14
setup: |
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
last-bundles: dmg,app-updater
updater-bundle: bundle/macos/ALCOM.app.tar.gz
dist-path: |
bundle/dmg/ALCOM_${GUI_VERSION}_universal.dmg:ALCOM-${GUI_VERSION}-universal.dmg
bundle/macos/ALCOM.app.tar.gz:ALCOM-${GUI_VERSION}-universal.app.tar.gz
bundle/macos/ALCOM.app.tar.gz.sig:ALCOM-${GUI_VERSION}-universal.app.tar.gz.sig
triple:
- x86_64-unknown-linux-gnu
name:
- x86_64-linux-appimage
#- aarch64-unknown-linux-musl
- x86_64-pc-windows-msvc
#- aarch64-pc-windows-msvc
- universal-apple-darwin
- x86_64-windows-all
#- aarch64-windows-all
- universal-macos-all
runs-on: ${{ matrix.on }}
env:
RUSTFLAGS: ${{ matrix.rustflags }}
needs: [ pre-build, build-web ]
needs: [ pre-build ]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
submodules: recursive
- run: rustup update stable
- name: Install cross-compilation tools
uses: taiki-e/setup-cross-toolchain-action@v1
if: ${{ matrix.triple != 'universal-apple-darwin' }}
@ -237,54 +220,72 @@ jobs:
with:
cache-targets: false # for release build, do not cache build artifacts
key: release-gui # there are no elements about build result, so it's ok to share between all builds
- uses: taiki-e/install-action@v2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tool: cargo-about
- name: Setup
run: ${{ matrix.setup }}
- uses: anatawa12/setup-eSigner-CKA@v1
if: ${{ matrix.esigner }}
with:
mode: ${{ vars.WIN_ESIGNER_MODE }}
username: ${{ secrets.WIN_ESIGNER_USERNAME }}
password: ${{ secrets.WIN_ESIGNER_PASSWORD }}
totp-secret: ${{ secrets.WIN_ESIGNER_TOTP_SECRET }}
- name: Build ALCOM binary
run: |
cargo xtask build-alcom --target ${{ matrix.triple }} --release ${{ matrix.alcom-build-options }}
- name: Download Web Artifact
uses: actions/download-artifact@v4
with:
name: vrc-get-gui-web
path: vrc-get-gui/out
- name: pre-sign Bundle ALCOM app (macOS)
if: ${{ contains(matrix.name, 'macos') }}
run: cargo xtask bundle-alcom --target ${{ matrix.triple }} --release --bundles app
- uses: tauri-apps/tauri-action@v0
- name: Sign ALCOM app (macOS)
if: ${{ contains(matrix.name, 'macos') }}
env:
# apple code signing
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: cargo xtask sign-alcom-app --target ${{ matrix.triple }}
# tauri updater signing
- name: Sign ALCOM exe (Windows)
if: ${{ contains(matrix.name, 'windows') }}
uses: ./.github/actions/sign-windows
with:
artifact-name: alcom-exe-unsigned
path: target/${{ matrix.triple }}/release/ALCOM.exe
signpath-api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
signing-policy-slug: ${{ case(inputs.dry-run, 'test-signing', 'release-signing') }}
version: ${{ needs.pre-build.outputs.gui-version }}
- name: Bundle Setup exe (Windows)
if: ${{ contains(matrix.name, 'windows') }}
run: cargo xtask bundle-alcom --target ${{ matrix.triple }} --release --bundles setup-exe
- name: Sign Setup exe (Windows)
if: ${{ contains(matrix.name, 'windows') }}
uses: ./.github/actions/sign-windows
with:
artifact-name: alcom-setup-exe-unsigned
path: target/${{ matrix.triple }}/release/bundle/setup/alcom-setup.exe
signpath-api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
signing-policy-slug: ${{ case(inputs.dry-run, 'test-signing', 'release-signing') }}
version: ${{ needs.pre-build.outputs.gui-version }}
- name: Bundle ALCOM (${{ matrix.last-bundles }})
run: cargo xtask bundle-alcom --target ${{ matrix.triple }} --release --bundles ${{ matrix.last-bundles }}
- name: Sign updater artifacts (All Platforms)
shell: bash
if: ${{ matrix.updater-bundle }}
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
UPDATER_BUNDLE: ${{ matrix.updater-bundle }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
# we have to use x86 version of signtool since eSignerCKA does not work with x64 version
TAURI_WINDOWS_SIGNTOOL_PATH: C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe
with:
projectPath: vrc-get-gui
tauriScript: npm run tauri
# disable beforeBuildCommand since we already build web
args: |
--target ${{ matrix.triple }} -c '{"build":{"beforeBuildCommand":null}}'
run: |
UPDATER_BUNDLE="${UPDATER_BUNDLE//\$\{GUI_VERSION\}/$GUI_VERSION}"
cargo xtask sign-alcom-updater "target/${{ matrix.triple }}/release/${UPDATER_BUNDLE}"
- name: Move artifacts
if: ${{ !cancelled() }}
shell: bash
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
@ -302,9 +303,153 @@ jobs:
mv "target/${{ matrix.triple }}/release/$src" "artifacts/$dst"
done
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: artifacts-${{ matrix.triple }}
name: artifacts-${{ matrix.name }}
path: artifacts/*
build-rpm:
needs: [ pre-build ]
strategy:
fail-fast: false
matrix:
include:
- install_rust: false
- no_dist: false
- mock-env: fedora-40-x86_64
install_rust: true
no_dist: true
mock-env:
- fedora-40-x86_64
runs-on: ubuntu-latest
container:
image: 'fedora:latest'
options: --privileged
env:
MOCK_ENV: ${{ matrix.mock-env }}
RPMBUILD_OPTS: ${{ case(matrix.no_dist, '-D "dist %{nil}"', '') }} ${{ case(matrix.install_rust, '-D "install_rust 1"', '') }}
PKG_VERSION: ${{ needs.pre-build.outputs.gui-version }}
steps:
- name: Install CI dependencies
run: dnf install -y git tar curl
- uses: actions/checkout@v6
with:
ref: 'releasing'
submodules: recursive
# https://github.com/actions/checkout/issues/1169
- run: git config --system --add safe.directory $GITHUB_WORKSPACE
- name: install dependencies
run: dnf install -y mock rpmbuild
- name: prepare rpm build environment
run: mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
- name: build source rpm package
run: |
git archive --format=tar --prefix=vrc-get-gui-v$PKG_VERSION/ $(git write-tree) | gzip > ~/rpmbuild/SOURCES/gui-v$PKG_VERSION.tar.gz
eval "rpmbuild -bs vrc-get-gui/bundle/alcom.spec $RPMBUILD_OPTS"
- name: build rpm package
run: eval "mock -v -r '$(ls -1 /etc/mock{/eol,}/$MOCK_ENV.cfg 2>/dev/null)' --enable-network $RPMBUILD_OPTS rebuild ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm"
- name: copy built binaries
run: |
mkdir -p artifacts
cp ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm artifacts/
cp /var/lib/mock/$MOCK_ENV/result/alcom-${PKG_VERSION//-/\~}-1*.${MOCK_ENV##*-}.rpm artifacts/
- name: Upload built binary
uses: actions/upload-artifact@v7
with:
name: artifacts-rpm-${{ matrix.mock-env }}
path: artifacts/*
build-deb:
needs: [ pre-build ]
strategy:
fail-fast: false
matrix:
include:
- install_rust: false
- install_nodejs: false
- apt-components: main
- apt-with-updates: false
# Old distributions have older tools than we need. Download tools in build process
- pbuilder-distribution: jammy
install_rust: true
install_nodejs: true
# Debian uses mirror from debian-archive.trafficmanager.net which is managed by microsoft on azure
- pbuilder-distribution: jammy
mirror: http://archive.ubuntu.com/ubuntu/
apt-components: main universe
apt-with-updates: true
keyring: /usr/share/keyrings/ubuntu-archive-keyring.gpg
# We build on jammy since it's the distribution with a) libwebkit2gtk-4.1 >= 2.41 and 2) oldest libc version required.
# bookworm: libc6@2.36
# sid: libc6@2.39 as of 2026/06/14
# jammy: libc6@2.35
pbuilder-distribution:
- jammy # jammy is the oldest ubuntu release with libwebkit2gtk-4.1 >= 2.41 (but requires -updates and universe)
target-arch:
- amd64
runs-on: ubuntu-latest
env:
TARGET_ARCH: ${{ matrix.target-arch }}
PBUILDER_DISTRIBUTION: ${{ matrix.pbuilder-distribution }}
PBUILDER_MIRROR: ${{ matrix.mirror }}
PBUILDER_KEYRING: ${{ matrix.keyring }}
PBUILDER_COMPONENTS: ${{ matrix.apt-components }}
PBUILDER_OTHERMIRROR: ${{ case(matrix.apt-with-updates, format('deb {0} {1}-updates {2}', matrix.mirror, matrix.pbuilder-distribution, matrix.apt-components), '') }}
INSTALL_RUST: ${{ case(matrix.install_rust, '1', '0') }}
INSTALL_NODEJS: ${{ case(matrix.install_nodejs, '1', '0') }}
PKG_VERSION: ${{ needs.pre-build.outputs.gui-version }}
steps:
- uses: actions/checkout@v6
with:
ref: 'releasing'
path: vrc-get
submodules: recursive
- name: install dependencies
run: sudo apt update && sudo apt install -y pbuilder debian-archive-keyring debhelper-compat=13
- name: prepare deb build environment
working-directory: vrc-get
run: |
( mkdir debian && cd debian && ln -s ../vrc-get-gui/bundle/debian/* . )
sudo pbuilder create \
--architecture "$TARGET_ARCH" \
--keyring "$PBUILDER_KEYRING" \
--mirror "$PBUILDER_MIRROR" \
--distribution "$PBUILDER_DISTRIBUTION" \
--components "$PBUILDER_COMPONENTS" \
--othermirror "$PBUILDER_OTHERMIRROR"
- name: build source deb package
working-directory: vrc-get
run: |
git archive --format=tar HEAD | xz > ../alcom_${PKG_VERSION//-/\~}.orig.tar.xz
dpkg-buildpackage -d -S
- name: build deb package
working-directory: vrc-get
run: |
sudo --preserve-env=INSTALL_RUST,INSTALL_NODEJS pbuilder build --use-network yes ../alcom_${PKG_VERSION//-/\~}-1.dsc
- name: copy built binaries
run: |
mkdir -p artifacts
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb artifacts/
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.buildinfo artifacts/
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.changes artifacts/
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1.debian.tar.xz artifacts/
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1.dsc artifacts/
ls artifacts
- name: Print information about built package
run: dpkg-deb -I artifacts/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb
- name: Upload built binary
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
with:
name: artifacts-deb-${{ matrix.pbuilder-distribution }}-${{ matrix.target-arch }}
path: artifacts/*
build-updater-json:
@ -312,11 +457,11 @@ jobs:
needs: [ pre-build, build-rust ]
steps:
# use release
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: Download All Artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
path: assets
pattern: artifacts-*
@ -325,15 +470,14 @@ jobs:
- name: Run updater-json
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
run: cargo run -p build-updater-json
run: cargo xtask alcom-updater-json --version "$GUI_VERSION" --assets assets updater.json
- name: Upload updater-json
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: updater.json
path: |
updater.json
updater-beta.json
publish-to-github:
name: Publish to GitHub
@ -344,16 +488,16 @@ jobs:
permissions:
contents: write
runs-on: ubuntu-latest
needs: [ pre-build, build-rust, build-updater-json ]
needs: [ pre-build, build-rust, build-rpm, build-deb, build-updater-json ]
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
fetch-depth: 2
@ -366,7 +510,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- name: Download All Artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
path: assets
pattern: artifacts-*
@ -374,7 +518,7 @@ jobs:
- name: Download changelog
# if: ${{ !needs.pre-build.outputs.prerelease }}
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: release-note-for-release
path: changelog
@ -427,7 +571,7 @@ jobs:
- build-rust
- publish-to-github
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
fetch-depth: 2
@ -444,14 +588,14 @@ jobs:
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: vrc-get
repositories: vrc-get.anatawa12.com
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
repository: 'vrc-get/vrc-get.anatawa12.com'
ref: 'master'
@ -460,7 +604,7 @@ jobs:
- uses: snow-actions/git-config-user@v1.0.0
- name: Download updater.json
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: updater.json
path: .
@ -474,7 +618,7 @@ jobs:
mv updater.json public/api/gui/tauri-updater.json
fi
rm public/api/gui/tauri-updater-beta.json || true
mv updater-beta.json public/api/gui/tauri-updater-beta.json
mv updater.json public/api/gui/tauri-updater-beta.json
- name: Commit
run: |-

View file

@ -1,173 +0,0 @@
name: Publish (litedb)
on:
workflow_dispatch:
inputs:
release_kind:
type: choice
description: The type of release.
default: prerelease
required: true
options:
- prerelease
- start-rc
- stable
jobs:
pre-build:
name: Update version name
runs-on: ubuntu-latest
outputs:
litedb-version: ${{ env.LITEDB_VERSION }}
prerelease: ${{ steps.update-version.outputs.prerelease }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: anatawa12/something-releaser@v3
- uses: snow-actions/git-config-user@v1.0.0
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Update Version Name
id: update-version
run: |
# set version name in properties file
case "$RELEASE_KIND_IN" in
"prerelease" )
get-version -t litedb | version-next | set-version -t litedb
gh-export-variable PRERELEASE true
gh-set-output prerelease true
;;
"start-rc" )
get-version -t litedb | version-set-channel - rc 0 | set-version -t litedb
gh-export-variable PRERELEASE true
gh-set-output prerelease true
;;
"stable" )
get-version -t litedb | version-set-channel - stable | set-version -t litedb
gh-export-variable PRERELEASE false
gh-set-output prerelease '' # empty string for false
;;
* )
echo "invalid release kind: $RELEASE_KIND_IN"
exit 255
;;
esac
case "$GITHUB_REF_NAME" in
master | master-* )
echo "head is master or master-*"
;;
* )
echo "invalid release kind: $RELEASE_KIND_IN is not allowd for $GITHUB_REF_NAME"
exit 255
;;
esac
gh-export-variable LITEDB_VERSION "$(get-version -t litedb)"
env:
RELEASE_KIND_IN: ${{ github.event.inputs.release_kind }}
# check for unexpected breaking ABI changes
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
package: vrc-get-litedb
- name: Commit
id: update
run: |-
# commit & tag
git commit -am "litedb v$LITEDB_VERSION"
git branch releasing
git push -f -u origin releasing
publish-crates-io:
name: Publish to crates.io
environment:
name: crates.io
url: https://crates.io/crates/vrc-get
runs-on: ubuntu-latest
needs: [ pre-build ]
steps:
- uses: actions/checkout@v4
with:
ref: 'releasing'
fetch-depth: 1
submodules: recursive
- name: Publish CARGO
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: cargo publish --package vrc-get-litedb
publish-to-github:
name: Publish to GitHub
environment:
name: actions-github-app
url: https://github.com/anatawa12/vrc-get/releases/litedb-v${{ needs.pre-build.outputs.litedb-version }}
permissions:
contents: write
runs-on: ubuntu-latest
needs: [ pre-build, publish-crates-io ]
env:
LITEDB_VERSION: ${{ needs.pre-build.outputs.litedb-version }}
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
ref: 'releasing'
fetch-depth: 2
submodules: recursive
token: ${{ steps.app-token.outputs.token }}
# tools
- uses: anatawa12/something-releaser@v3
- uses: snow-actions/git-config-user@v1.0.0
- uses: dtolnay/rust-toolchain@stable
- name: Push tag
run: |-
# set tag and publish current version
git tag "litedb-v$LITEDB_VERSION"
git push --tags
# create master and push
git switch -c master
git fetch origin master --depth=1
git log --all --graph
git push -u origin master
sleep 1
- name: prepare next release & push
if: ${{ !needs.pre-build.outputs.prerelease }}
run: |
get-version -t litedb | version-next | version-set-channel - beta 0 | set-version -t litedb
LITEDB_NEXT="$(get-version -t litedb | version-stable)"
git commit -am "chore: prepare for next version: litedb $LITEDB_NEXT"
git push
cleanup:
name: Cleanup
if: ${{ !failure() && !cancelled() }}
permissions:
contents: write
runs-on: ubuntu-latest
needs:
- pre-build
- publish-crates-io
- publish-to-github
steps:
- uses: actions/checkout@v4
with:
ref: 'releasing'
fetch-depth: 2
- name: remove releasing branch
run: git push --delete origin releasing

View file

@ -12,6 +12,14 @@ on:
- prerelease
- start-rc
- stable
dry-run:
type: boolean
description: Dry Run, If true, do not publish release to GitHub.
default: true
required: false
concurrency:
group: releasing
jobs:
pre-build:
@ -24,7 +32,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: anatawa12/something-releaser@v3
@ -63,12 +71,16 @@ jobs:
esac
case "$GITHUB_REF_NAME" in
master | master-* )
echo "head is master or master-*"
master | master-* | hotfix-* )
echo "head is master, master-*, or hotfix-*"
;;
* )
echo "invalid release kind: $RELEASE_KIND_IN is not allowd for $GITHUB_REF_NAME"
exit 255
if [ "$DRY_RUN" = "true" ]; then
echo "head is not master, but DRY_RUN is true"
else
echo "head is not master, but DRY_RUN is false"
exit 255
fi
;;
esac
@ -76,6 +88,7 @@ jobs:
gh-export-variable VPM_VERSION "$(get-version -t vpm)"
env:
RELEASE_KIND_IN: ${{ github.event.inputs.release_kind }}
DRY_RUN: ${{ inputs.dry-run }}
# region changelog
- name: Create Changelog
@ -94,7 +107,7 @@ jobs:
---
- name: Upload CHANGELOG.md
if: ${{ !steps.update-version.outputs.prerelease }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: CHANGELOG
path: CHANGELOG.md
@ -103,7 +116,7 @@ jobs:
run: cp "${{ steps.changelog.outputs.release-note }}" release-note.md
- name: Upload release note
if: ${{ !steps.update-version.outputs.prerelease }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: release-note-for-release
path: release-note.md
@ -164,7 +177,7 @@ jobs:
needs: [ pre-build ]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
submodules: recursive
@ -186,12 +199,13 @@ jobs:
run: cargo build --target ${{ matrix.triple }} --release --verbose
- name: Check binary is statically linked
shell: bash
env:
RUSTFLAGS: ''
run: |
# https://github.com/taiki-e/setup-cross-toolchain-action/issues/18
unset CARGO_BUILD_TARGET
cargo run -p build-check-static-link target/${{ matrix.triple }}/release/vrc-get*
cargo xtask check-static-link target/${{ matrix.triple }}/release/vrc-get${WINDIR:+.exe}
- name: Move artifacts
if: ${{ !cancelled() }}
shell: bash
run: |-
mkdir artifacts
@ -201,20 +215,22 @@ jobs:
done
popd
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: artifacts-${{ matrix.triple }}
path: artifacts/*
publish-crates-io:
name: Publish to crates.io
if: ${{ !inputs.dry-run }}
environment:
name: crates.io
url: https://crates.io/crates/vrc-get
runs-on: ubuntu-latest
needs: [ pre-build, build-rust ]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
fetch-depth: 1
@ -232,6 +248,7 @@ jobs:
publish-to-github:
name: Publish to GitHub
if: ${{ !inputs.dry-run }}
environment:
name: actions-github-app
url: https://github.com/anatawa12/vrc-get/releases/v${{ needs.pre-build.outputs.cli-version }}
@ -243,12 +260,12 @@ jobs:
CLI_VERSION: ${{ needs.pre-build.outputs.cli-version }}
VPM_VERSION: ${{ needs.pre-build.outputs.vpm-version }}
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
fetch-depth: 2
@ -261,7 +278,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- name: Download All Artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
path: assets
pattern: artifacts-*
@ -269,22 +286,24 @@ jobs:
- name: Download changelog
if: ${{ !needs.pre-build.outputs.prerelease }}
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: release-note-for-release
path: changelog
- name: Push tag
env:
BRANCH: ${{ github.ref_name }}
run: |-
# set tag and publish current version
git tag "v$CLI_VERSION"
git tag "vpm-v$VPM_VERSION"
git push --tags
# create master and push
git switch -c master
git fetch origin master --depth=1
git switch -c "$BRANCH"
git fetch origin "$BRANCH" --depth=1
git log --all --graph
git push -u origin master
git push -u origin "$BRANCH"
sleep 1
- name: create release
@ -324,7 +343,7 @@ jobs:
CLI_VERSION: ${{ needs.pre-build.outputs.cli-version }}
VPM_VERSION: ${{ needs.pre-build.outputs.vpm-version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: 'releasing'
fetch-depth: 2
@ -334,7 +353,7 @@ jobs:
publish-to-homebrew:
name: Publish to homebrew
# vrc-get is on autobump list https://github.com/Homebrew/homebrew-core/blame/master/.github/autobump.txt
if: false # ${{ !needs.pre-build.outputs.prerelease }}
if: false # ${{ !inputs.dry-run && !needs.pre-build.outputs.prerelease }}
environment:
name: homebrew-core
url: https://github.com/homebrew/homebrew-core
@ -348,7 +367,7 @@ jobs:
publish-to-winget:
name: Publish to winget
if: ${{ !needs.pre-build.outputs.prerelease }}
if: ${{ !inputs.dry-run && !needs.pre-build.outputs.prerelease }}
needs: [ pre-build, publish-to-github ]
uses: vrc-get/vrc-get/.github/workflows/publish-cli-winget.yml@master

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "vrc-get-litedb/dotnet/LiteDB"]
path = vrc-get-litedb/dotnet/LiteDB
url = https://github.com/anatawa12/LiteDB.git

View file

@ -8,34 +8,291 @@ The format is based on [Keep a Changelog].
## [Unreleased]
### Added
- System Information card to Settings Page `#1406`
- Traditional Chinese translation `#1442`
- Reinstall some selected packages `#1450`
- Install and Upgrade packages at once `#1450`
- Upgrade to the stable latest version even if some package has newer prerelease version `#1450`
- Buttons to open settings, logs, and templates location `#1451`
- Error page `#1457`
- Ctrl + F on Log, Projects List, and Project page will focus search box on the page `#1485`
- Implement project sorting by creation date `#2941`
### Changed
- GitHub Releases for ALCOM is no longer prereleases
- Moved log files to `<vpm-home>/vrc-get/gui-logs` `#1446`
- Logs pages overhaul `#1456`
### Deprecated
### Removed
### Fixed
- Fails to uninstall packages on macOS with filesystem that doesn't support resource fork `#1402`
### Security
## [1.1.6] - 2026-06-02
### Added
- The package list can show hidden packages. [`#2731`](https://github.com/vrc-get/vrc-get/pull/2731)
- Build-time option to disable auto updater [`#2759`](https://github.com/vrc-get/vrc-get/pull/2759)
- Please read README for new build instruction.
- User repositories can now be reordered by drag and drop [`#2935`](https://github.com/vrc-get/vrc-get/pull/2935)
### Changed
- The "Clear Selection" button in the package management screen is now red (destructive style) to distinguish it from the "Install Selected" button [`#2803`](https://github.com/vrc-get/vrc-get/pull/2803)
- File filled with '\0' or whitespace will be treated as empty file [`#2710`](https://github.com/vrc-get/vrc-get/pull/2710)
- This should prevent `syntax error loading settings.json: expected value at line 1 column 1` if settings.json is broken
- We also added a backup file to recover from settings.json corruption [`#2933`](https://github.com/vrc-get/vrc-get/pull/2933)
- Completely changed how do we build ALCOM and how do we self-update ALCOM [`#2759`](https://github.com/vrc-get/vrc-get/pull/2759) [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828) [`#2881`](https://github.com/vrc-get/vrc-get/pull/2881) [`#2882`](https://github.com/vrc-get/vrc-get/pull/2882) [`#2885`](https://github.com/vrc-get/vrc-get/pull/2885)
- This fixes few problems relates to auto update
- Please read README for new build instruction.
- Improved backup speed by parallelizing the process [`#2746`](https://github.com/vrc-get/vrc-get/pull/2746)
- Along with this change, the default compression level has been changed to `zip-fast`
- We added dialog on enabling "Show Prerelease Packages" [`#2795`](https://github.com/vrc-get/vrc-get/pull/2795)
- I hope this prevents users unexpectedly adding prerelease packages
- Path for unitypackage on Template Editor now can be reselected [`#2635`](https://github.com/vrc-get/vrc-get/pull/2635)
- ALCOM now refuses launching project if project is on noexec mount points [`#2814`](https://github.com/vrc-get/vrc-get/pull/2814)
- This would cause problems with several native plugins
- Already-added packages are now excluded from the package name suggestions in the Template Editor [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828)
- Extended some timeouts to 1 minute [`#2826`](https://github.com/vrc-get/vrc-get/pull/2826)
- Prevents timeouts in slow DNS environments
- Improved robustness for package installation errors [`#2844`](https://github.com/vrc-get/vrc-get/pull/2844)
- It is now unlikely that vrc-get will leave the project directory corrupted if an I/O error occurs while installing a package
- Backslashes in path in zip file are now treated as path separator on unix [`#2845`](https://github.com/vrc-get/vrc-get/pull/2845)
- This fixes problem with Gesture Manager 3.9.7
- Empty string for `documentationUrl` and `changelogUrl` are now allowed and ignored [`#2930`](https://github.com/vrc-get/vrc-get/pull/2930)
- They are formerly rejected as invalid url
### Fixed
- Fixed an issue where the progress bar flickered and did not display correct progress in environments using WebKit as the renderer. [`#2641`](https://github.com/vrc-get/vrc-get/pull/2641)
- Fails to import UnityPackages with files in `Packages` directory [`#2679`](https://github.com/vrc-get/vrc-get/pull/2679)
- null as vpmDependencies value is not allowed [`#2709`](https://github.com/vrc-get/vrc-get/pull/2709)
- It's not recommended, but we allow null for `vpmDependencies` as a alias of `{}`
- ALCOM cannot detect per-user flatpak installation of unity hub [`#2812`](https://github.com/vrc-get/vrc-get/pull/2812)
- Unabled to import some untypackages [`#2821`](https://github.com/vrc-get/vrc-get/pull/2821)
- It's hard to say but some older unitypackages ware unsupported.
- Panic when resolving projects where dependency packages depend on newer versions of locked packages [`#2822`](https://github.com/vrc-get/vrc-get/pull/2822)
- Missing glibc and libgcc_s dependency notation in .deb / .rpm distributon [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828)
- Unclear error message for invalid version name or version range [`#2842`](https://github.com/vrc-get/vrc-get/pull/2842)
- Default file names in save dialogs now include the appropriate file extension [`#2846`](https://github.com/vrc-get/vrc-get/pull/2846)
- Template export now defaults to `{template name}.alcomtemplate`
- Repository list export now defaults to `repositories.txt`
- Uninformative `[object Object]` appearing as an error message [`#2848`](https://github.com/vrc-get/vrc-get/pull/2848)
- New Unity Hub loading method may not load manually added Unity Editors [`#2850`](https://github.com/vrc-get/vrc-get/pull/2850)
- New Unity Hub loading method does load unity hub configuration on Linux [`#2850`](https://github.com/vrc-get/vrc-get/pull/2850)
- Too many open files when copying project `#2867
- Added workaround for VRCDefaultWorldScene generation issue in SDK 3.10.2 or later [`#2916`](https://github.com/vrc-get/vrc-get/pull/2916)
- See [this][default-scene-canny] canny for bug in VRCSDK and issue [#2913][issue-2913] for our decision.
### Security
- Package hash checks are now enforced when installing packages [`#2849`](https://github.com/vrc-get/vrc-get/pull/2849)
- It has been about two years since the error message for package hash mismatches was introduced.
- It is now enforced for security.
[default-scene-canny]: https://feedback.vrchat.com/sdk-bug-reports/p/3102-3103-vrcscenetemplateinitializer-does-not-create-sample-scene-if-udon-prepr
[issue-2913]: https://github.com/vrc-get/vrc-get/issues/2913
## [1.1.5] - 2025-11-16
- Fix package version selector dropdown exceeding window height [`#2589`](https://github.com/vrc-get/vrc-get/pull/2589)
- The dropdown list now has a maximum height of 50% of the viewport or 24rem, whichever is smaller
- This prevents the version selector from overflowing the window on small screens
- Fix muted-foreground color [`#2516`](https://github.com/vrc-get/vrc-get/pull/2516) [`#2517`](https://github.com/vrc-get/vrc-get/pull/2517)
- Remove `DialogDescription` not in `DialogHeader` to fix text color
- Fix 'Detected Loop' panic with valid database file [`#2607`](https://github.com/vrc-get/vrc-get/pull/2607)
## [1.1.4] - 2025-09-02
### Added
- Add compact gui option [`#2436`](https://github.com/vrc-get/vrc-get/pull/2436) [`#2450`](https://github.com/vrc-get/vrc-get/pull/2450) [`#2470`](https://github.com/vrc-get/vrc-get/pull/2470)
### Changed
- Improved saving interacting with setting files [`#2485`](https://github.com/vrc-get/vrc-get/pull/2485)
- This should reduce "EOF while parsing a value at line 1 column 0" error on launch.
- This should reduce losing settings after crashing ALCOM or PC.
### Fixed
- Specifying a single unityversion doesn't work properly in alcomtemplate [`#2452`](https://github.com/vrc-get/vrc-get/pull/2452)
- For example, if you'd like to specify `2022.3.22f1`, you need to set `2022.3.22`, not `2022.3.22f1`
- You can now see correct validation and suggestions for this.
- Home/End and Up/Down keys now consistently control cursor position in autocomplete fields [`#2466`](https://github.com/vrc-get/vrc-get/pull/2466)
- Home/End keys now always move the text cursor regardless of autocomplete state
- Up/Down keys move the text cursor when suggestions are not visible, and navigate suggestions when they are visible
- Previously, these keys would sometimes be captured for suggestion navigation when autocomplete was open
## [1.1.3] - 2025-07-28
### Added
- Add support for `keywords` UPM manifest field [`#2375`](https://github.com/vrc-get/vrc-get/pull/2375)
- You now can specifiy search keywords for package with `keywords` UPM manifest field
- Favorites for templates [`#2376`](https://github.com/vrc-get/vrc-get/pull/2376)
- It's much easier to select project templates you likely to use.
### Changed
- Improved the Template Editor with AutoComplete [`#2371`](https://github.com/vrc-get/vrc-get/pull/2371)
- You no longer need to remember the package name (id) and version associated with the package.
- You now can search package by display name, name (id), aliases to enter package name, and ALCOM shows common version range for you.
- Updated project settings of templates to include Item layer [`#2373`](https://github.com/vrc-get/vrc-get/pull/2373)
- You should no longer need to update layers and collision matrix before uploading world
- Improved behavior about `settings.json` to `vcc.litedb` migration [`#2327`](https://github.com/vrc-get/vrc-get/pull/2327)
- See [`vrchat-community/creator-companion#492`](https://github.com/vrchat-community/creator-companion/issues/492) and the PR for details
- Last used template is now preserved [`#2376`](https://github.com/vrc-get/vrc-get/pull/2376)
- When you generally create project with custom template, you no longer need to change template every time.
### Fixed
- Packages are not deselected after installing packages [`#2372`](https://github.com/vrc-get/vrc-get/pull/2372)
## [1.1.2] - 2025-06-30
### Fixed
- Fixed `a - b` version range is not correctly serialized on the `vpm-manifest.json`
- Frontend error on package list update [`#2341`](https://github.com/vrc-get/vrc-get/pull/2341)
## [1.1.1] - 2025-06-21
### Fixed
- Unity can be duplicated [`#2321`](https://github.com/vrc-get/vrc-get/pull/2321)
- Crash on creating a new project on Windows [`#2326`](https://github.com/vrc-get/vrc-get/pull/2326)
## [1.1.0] - 2025-06-19
### Added
- Support for Projects with Unity 2018 or older [`#2106`](https://github.com/vrc-get/vrc-get/pull/2106)
- Projects with Unity 2018 cannot be added before, but since this version you can add to your project list.
- Unity 2017 or older doesn't have Unity Package Manager, the base system for VPM,
so you cannot manage packages for projects with older unity.
You can only launch Unity to open the project.
- Projects with Unity 4 or older are still not supported, but I hope no one want to use such a vintage Unity with ALCOM.
- New Project Template System [`#2105`](https://github.com/vrc-get/vrc-get/pull/2105) [`#2114`](https://github.com/vrc-get/vrc-get/pull/2114) [`#2125`](https://github.com/vrc-get/vrc-get/pull/2125) [`#2129`](https://github.com/vrc-get/vrc-get/pull/2129) [`#2204`](https://github.com/vrc-get/vrc-get/pull/2204) [`#2259`](https://github.com/vrc-get/vrc-get/pull/2259) [`#2260`](https://github.com/vrc-get/vrc-get/pull/2260) [`#2261`](https://github.com/vrc-get/vrc-get/pull/2261) [`#2275`](https://github.com/vrc-get/vrc-get/pull/2275) [`#2276`](https://github.com/vrc-get/vrc-get/pull/2276)
- You now can create Project Templates in ALCOM.
- The new form of template can install multiple VPM packages at once, and you also can import unitypackages.
- You now can create blank project along with this system change.
- Warning on upgrading major version or installing incompatible versions [`#2159`](https://github.com/vrc-get/vrc-get/pull/2159) [`#2313`](https://github.com/vrc-get/vrc-get/pull/2313)
- When you're upgrading package versions majorly, you'll see the warning message about breaking changes.
- I hope this should reduce problems with unexpectedly upgrading packages majorly.
- In addition, we added more messages when you're installing packages with some compatibility concerns.
- The previous version only has those messages at the bottom of the window, so you may not notice the message.
- Not only that, you now can see the package is upgraded, reinstalled, downgraded, or newly installed.
- Menu option to copy a project [`#2168`](https://github.com/vrc-get/vrc-get/pull/2168) [`#2219`](https://github.com/vrc-get/vrc-get/pull/2219) [`#2225`](https://github.com/vrc-get/vrc-get/pull/2225)
- Simple enough, you can copy a project.
- Remember recent project locations [`#2182`](https://github.com/vrc-get/vrc-get/pull/2182)
- ALCOM now remembers a few multiple recent locations for project creation, and you can select from recent locations
- Support for flatpak installation of unity hub [`#1586`](https://github.com/vrc-get/vrc-get/pull/1586)
- ALCOM now detects flatpak installation of unity hub automatically
- Projects page Grid View [`#2245`](https://github.com/vrc-get/vrc-get/pull/2245) [`#2257`](https://github.com/vrc-get/vrc-get/pull/2257)
### Changed
- Changed how we read VCC's project information [`#1997`](https://github.com/vrc-get/vrc-get/pull/1997) [`#2036`](https://github.com/vrc-get/vrc-get/pull/2036) [`#2041`](https://github.com/vrc-get/vrc-get/pull/2041)
- Along with this, building this project no longer needs dotnet SDK to build.
- Migrated the project to Rust 2024 [`#1956`](https://github.com/vrc-get/vrc-get/pull/1956)
- This is internal changes should not cause behavior changes
- This would require Rust 1.85 for building this project
- Removed `cargo-about` from build-time dependency [`#1961`](https://github.com/vrc-get/vrc-get/pull/1961)
- This is internal changes should not cause behavior changes
- I listed here since this may need update on package metadata of some package managers
- The method to retrieve the list of Unity from Unity Hub [`#1808`](https://github.com/vrc-get/vrc-get/pull/1808) [`#1971`](https://github.com/vrc-get/vrc-get/pull/1971)
- Since this version, ALCOM reads UnityHub's configuration files to get list of Unity installed to the machine.
- Before this version, ALCOM called headless Unity Hub in the background.
- New method might have some compatibility problem, especially with some sandbox system.
- Please report us if you find some problem with the new system.
- Enhance os info for windows [`#1968`](https://github.com/vrc-get/vrc-get/pull/1968)
- You now can select multiple folders at once to adding project [`#2018`](https://github.com/vrc-get/vrc-get/pull/2018)
- I didn't know official VCC had such a feature. Sorry for lack of feature!
- You now can toggle "Show Prerelease Packages" from Manage Project page [`#2020`](https://github.com/vrc-get/vrc-get/pull/2020)
- You can toggle "Show Prerelease Packages" from Select Packages dropdown
- The requirements for unity project [`#2106`](https://github.com/vrc-get/vrc-get/pull/2106)
- Since this version, `Projectsettings/ProjectVersion.txt` is required.
- Improves launching unity behavior [`#2124`](https://github.com/vrc-get/vrc-get/pull/2124)
- On linux, ALCOM will now read exit code, therefore, Unity no longer remains as a defunct process.
- On macOS, we now launch Unity as a distinct / individual process, therefore several macOS subsystems should treat Unity as Unity instead of Unity as a part of ALCOM.
- Downgraded glibc requirements for linux images [`#2160`](https://github.com/vrc-get/vrc-get/pull/2160)
- This release will be built on ubuntu 22.04 so glibc 2.35 is new requirements
- If you want to use on platforms with older glibc, build yourself or pull request to build on older environments.
- Loading projects / repositories is now asynchronously [`#2169`](https://github.com/vrc-get/vrc-get/pull/2169)
- You should be able to open a project / install packages much quickly than before!
- The reload button will keep rotating while loading asynchronously
- Open changelog, documentation, and reinstall single package from package list [`#2184`](https://github.com/vrc-get/vrc-get/pull/2184) [`#2208`](https://github.com/vrc-get/vrc-get/pull/2208) [`#2298`](https://github.com/vrc-get/vrc-get/pull/2298)
- You can open the changelog and documentation from `...` button at the right of package list
- Option to exclude VPM Packages from backups [`#2185`](https://github.com/vrc-get/vrc-get/pull/2185)
- You can exclude VPM Packages from backups to reduce size of backup a little
- However, if the package author ignored the recommendation from VRChat and us, and removed package from their repository, you may need to install another version when restoring the backup.
- Since many of the repository maintainers have removed many packages in their repository and VPM Packages are relatively small, this feature is disabled by default. You can enable this on the settings page.
- Show the range of requested package in missing dependencies dialog [`#2187`](https://github.com/vrc-get/vrc-get/pull/2187)
- `LastSceneManagerSetup.txt` in `Library` directory will be included in backups or copying project [`#2205`](https://github.com/vrc-get/vrc-get/pull/2205)
- With this file preserved, you can expect to open the last opened scene file when you opened projects restored from backups.
- Improved behavior when the project directory is not a valid project but the directory exists [`#2225`](https://github.com/vrc-get/vrc-get/pull/2225)
- Open Unity now will update `Last Modified` of a project. [`#2228`](https://github.com/vrc-get/vrc-get/pull/2228)
### Fixed
- Layout shift on select package [`#2045`](https://github.com/vrc-get/vrc-get/pull/2045)
- Unable to change the unity version from "unknown" if ProjectVersion.txt does not exists [`#2183`](https://github.com/vrc-get/vrc-get/pull/2183)
- Uninstall package is not reverted successfully if removing package is prevented by `ERROR_SHARING_VIOLATION` [`#2209`](https://github.com/vrc-get/vrc-get/pull/2209)
- Too Many Open Files on backing up some projects [`#2262`](https://github.com/vrc-get/vrc-get/pull/2262)
## [1.0.1] - 2025-02-05
### Added
- Add Korean localization [`#1822`](https://github.com/vrc-get/vrc-get/pull/1822)
### Fixed
- Fixed toast message when adding repositories [`#1815`](https://github.com/vrc-get/vrc-get/pull/1815)
- Improved several linux desktop support [`#1821`](https://github.com/vrc-get/vrc-get/pull/1821)
- Backup file used UTC time instead of Local time [`#1862`](https://github.com/vrc-get/vrc-get/pull/1862)
- Worlds templates doesn't have proper input axis settings [`#1902`](https://github.com/vrc-get/vrc-get/pull/1902)
## [1.0.0] - 2025-01-01
### Fixed
- Link to unity hub is hardcoded to Japanese [`#1810`](https://github.com/vrc-get/vrc-get/pull/1810)
- Fixed link to respect currently configured language
- Fixed Logs page autoscroll not enable on start [`#1811`](https://github.com/vrc-get/vrc-get/pull/1811)
- Fixed failed to load project list with invalid unity version stored [`#1813`](https://github.com/vrc-get/vrc-get/pull/1813)
## [0.1.17] - 2024-12-22
### Changed
- Several GUI improvements [`#1672`](https://github.com/vrc-get/vrc-get/pull/1672) [`#1771`](https://github.com/vrc-get/vrc-get/pull/1771) [`#1775`](https://github.com/vrc-get/vrc-get/pull/1775) [`#1772`](https://github.com/vrc-get/vrc-get/pull/1772) [`#1779`](https://github.com/vrc-get/vrc-get/pull/1779)
- Removed `-debugCodeOptimization` from default unity arguments [`#1742`](https://github.com/vrc-get/vrc-get/pull/1742)
- Projects that failes to resolve will also be added to Project List now [`#1748`](https://github.com/vrc-get/vrc-get/pull/1748)
- Previsously project dir is created but not added to list
- Dialog is shown when some installing packages are not found [`#1749`](https://github.com/vrc-get/vrc-get/pull/1749) [`#1776`](https://github.com/vrc-get/vrc-get/pull/1776)
- The new dialog also suggest you to google & add repository for the package
- Previously the first package we could not found are shown on the error toast but now collect and show missing packages as many as possible
### Fixed
- Prerelease version is choosen even if good stable version exists [`#1745`](https://github.com/vrc-get/vrc-get/pull/1745)
## [0.1.16] - 2024-11-12
### Added
- Support for China version of Unity releases like `2022.3.22f1c1` `#1558
- `rpm` `deb` packaging for Linux [`#1575`](https://github.com/vrc-get/vrc-get/pull/1575)
- This is to test how good / bad `rpm` or `deb` distribution is.
- We **may** create dnf / apt package repository in the future, but not planned for now.
- Skipping finding legacy assets when downgrading / upgrading / reinstalling package [`#1581`](https://github.com/vrc-get/vrc-get/pull/1581)
- This will speed up the process of downgrading / upgrading / reinstalling package.
### Changed
- Separated quick open actions to own settings box. [`#1496`](https://github.com/vrc-get/vrc-get/pull/1496)
- Improved behavior with downloading package error [`#1557`](https://github.com/vrc-get/vrc-get/pull/1557)
- Installing unlocked package is now possible with warning [`#1557`](https://github.com/vrc-get/vrc-get/pull/1557)
- Added many logs for installing package [`#1557`](https://github.com/vrc-get/vrc-get/pull/1557)
- Migration feature is no longer marked as experimental [`#1559`](https://github.com/vrc-get/vrc-get/pull/1559)
- Several UX improvements [`#1561`](https://github.com/vrc-get/vrc-get/pull/1561) [`#1565`](https://github.com/vrc-get/vrc-get/pull/1565) [`#1569`](https://github.com/vrc-get/vrc-get/pull/1569) [`#1571`](https://github.com/vrc-get/vrc-get/pull/1571) [`#1573`](https://github.com/vrc-get/vrc-get/pull/1573)
- Added more error log [`#1652`](https://github.com/vrc-get/vrc-get/pull/1652)
- Improved error message when specified drive not found [`#1653`](https://github.com/vrc-get/vrc-get/pull/1653)
### Fixed
- Clicking VCC link while adding vpm repository would close previously opened add repository dialog [`#1570`](https://github.com/vrc-get/vrc-get/pull/1570)
- Opnening Templetes directory might fails [`#1641`](https://github.com/vrc-get/vrc-get/pull/1641)
- Backup file name is incorrect if project name contains '.' [`#1648`](https://github.com/vrc-get/vrc-get/pull/1648)
- Error creating project if the project path is "C:" [`#1651`](https://github.com/vrc-get/vrc-get/pull/1651)
- "missing field Verison" error if some unity version is missing [`#1654`](https://github.com/vrc-get/vrc-get/pull/1654)
## [0.1.15] - 2024-09-05
### Added
- System Information card to Settings Page [`#1406`](https://github.com/vrc-get/vrc-get/pull/1406)
- Traditional Chinese translation [`#1442`](https://github.com/vrc-get/vrc-get/pull/1442)
- Reinstall some selected packages [`#1450`](https://github.com/vrc-get/vrc-get/pull/1450)
- Install and Upgrade packages at once [`#1450`](https://github.com/vrc-get/vrc-get/pull/1450)
- Upgrade to the stable latest version even if some package has newer prerelease version [`#1450`](https://github.com/vrc-get/vrc-get/pull/1450)
- Buttons to open settings, logs, and templates location [`#1451`](https://github.com/vrc-get/vrc-get/pull/1451)
- Error page [`#1457`](https://github.com/vrc-get/vrc-get/pull/1457)
- Ctrl + F on Log, Projects List, and Project page will focus search box on the page [`#1485`](https://github.com/vrc-get/vrc-get/pull/1485)
### Changed
- GitHub Releases for ALCOM is no longer prereleases
- Moved log files to `<vpm-home>/vrc-get/gui-logs` [`#1446`](https://github.com/vrc-get/vrc-get/pull/1446)
- Logs pages overhaul [`#1456`](https://github.com/vrc-get/vrc-get/pull/1456)
### Fixed
- Fails to uninstall packages on macOS with filesystem that doesn't support resource fork [`#1402`](https://github.com/vrc-get/vrc-get/pull/1402)
- This is typically seen on ExFAT or FAT32 filesystems, not on APFS or HFS+ filesystems.
- macOS internally creates files starting with `._` for resource fork if the filesystem does not support resource fork.
- vrc-get-vpm does not handle this file correctly and fails to uninstall the package.
- environment version mismatch error after resolving packages `#1447`
- Raw error for InstallAsUnlocked is shown on gui `#1448`
- Ctrl + F on Windows will show the search box by WebView2 `#1485`
### Security
- environment version mismatch error after resolving packages [`#1447`](https://github.com/vrc-get/vrc-get/pull/1447)
- Raw error for InstallAsUnlocked is shown on gui [`#1448`](https://github.com/vrc-get/vrc-get/pull/1448)
- Ctrl + F on Windows will show the search box by WebView2 [`#1485`](https://github.com/vrc-get/vrc-get/pull/1485)
- Project Path is shown instead of Project Name [`#1484`](https://github.com/vrc-get/vrc-get/pull/1484)
## [0.1.14] - 2024-08-13
### Added
@ -446,7 +703,19 @@ Release pipeline fixes
- Apple code signing [`#422`](https://github.com/anatawa12/vrc-get/pull/422)
- Migrate vpm 2019 project to 2022 [`#435`](https://github.com/anatawa12/vrc-get/pull/435)
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.14...HEAD
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.6...HEAD
[1.1.6]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.5...gui-v1.1.6
[1.1.5]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.4...gui-v1.1.5
[1.1.4]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.3...gui-v1.1.4
[1.1.3]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.2...gui-v1.1.3
[1.1.2]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.1...gui-v1.1.2
[1.1.1]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.0...gui-v1.1.1
[1.1.0]: https://github.com/vrc-get/vrc-get/compare/gui-v1.0.1...gui-v1.1.0
[1.0.1]: https://github.com/vrc-get/vrc-get/compare/gui-v1.0.0...gui-v1.0.1
[1.0.0]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.17...gui-v1.0.0
[0.1.17]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.16...gui-v0.1.17
[0.1.16]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.15...gui-v0.1.16
[0.1.15]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.14...gui-v0.1.15
[0.1.14]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.13...gui-v0.1.14
[0.1.13]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.12...gui-v0.1.13
[0.1.12]: https://github.com/vrc-get/vrc-get/compare/gui-v0.1.11...gui-v0.1.12

View file

@ -8,34 +8,87 @@ The format is based on [Keep a Changelog].
## [Unreleased]
### Added
- Per-package `headers` field support `#718`
- Since this is adding support for missing features, I treat this as a bugfix and not bump minor version.
- De-duplicating duplicated projects or Unity in VCC project list `#1081`
- `vrc-get cache clear`, command to clear package cache `#1204`
- Importing / Exporting Repositories list `#1209`
- `vrc-get repo import <list file>` and `vrc-get repo export`
- User Package Management `#1222`
- This release adds `vrc-get user-package` subcommands to manage user packages.
- `vrc-get reinstall <package id>` to reinstall specified packages `#1223`
### Changed
- Error message will be shown if the SHA256 hash of the downloaded zip file does not match with the hash in the repository `#1183`
- Currently, official VCC does not verify the hash of the downloaded zip file, but it's better to verify the hash.
- For compatibility, even if the hash does not match, the file will be extracted with an error message.
- In the future, we may make this a hard error.
- Improved saving interacting with setting files `#2485` `#2710`
- This should reduce "EOF while parsing a value at line 1 column 0" error on launch.
- This should reduce losing settings after crashing ALCOM or PC.
- null as vpmDependencies value is not allowed `#2709`
- It's not recommended, but we allow null for `vpmDependencies` as a alias of `{}`
- Improved robustness for package installation errors `#2844`
- It is now unlikely that vrc-get will leave the project directory corrupted if an I/O error occurs while installing a package
- Backslashes in path in zip file are now treated as path separator on unix `#2845`
- This fixes problem with Gesture Manager 3.9.7
### Deprecated
### Removed
### Fixed
- Unity from Unity Hub will be registered as manually registered Unity `#1081`
- Fails to uninstall packages on macOS with filesystem that doesn't support resource fork `#1402`
- Fix 'Detected Loop' panic with valid database file `#2607`
- Panic when resolving projects where dependency packages depend on newer versions of locked packages `#2822`
- Warning for backup/project path in AppData folder not shown when path is in Roaming or LocalLow [`#2827`](https://github.com/vrc-get/vrc-get/pull/2827)
- Unclear error message for invalid version name or version range `#2842`
- Empty string for `documentationUrl` and `changelogUrl` are now allowed and ignored `#2930`
- They are formerly rejected as invalid url
### Security
- Package hash checks are now enforced when installing packages `#2849`
- It has been about two years since the error message for package hash mismatches was introduced.
- It is now enforced for security.
## [1.9.1] - 2025-07-28
### Changed
- Changed how we read VCC's project information [`#1997`](https://github.com/vrc-get/vrc-get/pull/1997)
- Along with this, building this project no longer needs dotnet SDK to build.
- Migrated the project to Rust 2024 [`#1956`](https://github.com/vrc-get/vrc-get/pull/1956)
- This is internal changes should not cause behavior changes
- This would require Rust 1.85 for building this project
- Removed `cargo-about` from build-time dependency [`#1961`](https://github.com/vrc-get/vrc-get/pull/1961)
- This is internal changes should not cause behavior changes
- I listed here since this may need update on package metadata of some package managers
- The method to retrieve the list of Unity from Unity Hub [`#1808`](https://github.com/vrc-get/vrc-get/pull/1808) [`#1971`](https://github.com/vrc-get/vrc-get/pull/1971)
- You now can select multiple folders at once to adding project [`#2018`](https://github.com/vrc-get/vrc-get/pull/2018)
- I didn't know official VCC had such a feature. Sorry for lack of feature!
- The requirements for unity project [`#2106`](https://github.com/vrc-get/vrc-get/pull/2106)
- Since this version, `Projectsettings/ProjectVersion.txt` is required.
### Fixed
- Uninstall package is not reverted successfully if removing package is prevented by `ERROR_SHARING_VIOLATION` [`#2209`](https://github.com/vrc-get/vrc-get/pull/2209)
- Fixed `a - b` version range is not correctly serialized on the `vpm-manifest.json`
## [1.9.0] - 2025-01-01
### Added
- Per-package `headers` field support [`#718`](https://github.com/vrc-get/vrc-get/pull/718)
- Since this is adding support for missing features, I treat this as a bugfix and not bump minor version.
- De-duplicating duplicated projects or Unity in VCC project list [`#1081`](https://github.com/vrc-get/vrc-get/pull/1081)
- `vrc-get cache clear`, command to clear package cache [`#1204`](https://github.com/vrc-get/vrc-get/pull/1204)
- Importing / Exporting Repositories list [`#1209`](https://github.com/vrc-get/vrc-get/pull/1209)
- `vrc-get repo import <list file>` and `vrc-get repo export`
- User Package Management [`#1222`](https://github.com/vrc-get/vrc-get/pull/1222)
- This release adds `vrc-get user-package` subcommands to manage user packages.
- `vrc-get reinstall <package id>` to reinstall specified packages [`#1223`](https://github.com/vrc-get/vrc-get/pull/1223)
- Skipping finding legacy assets when downgrading / upgrading / reinstalling package [`#1581`](https://github.com/vrc-get/vrc-get/pull/1581)
- This will speed up the process of downgrading / upgrading / reinstalling package.
### Changed
- Error message will be shown if the SHA256 hash of the downloaded zip file does not match with the hash in the repository [`#1183`](https://github.com/vrc-get/vrc-get/pull/1183)
- Currently, official VCC does not verify the hash of the downloaded zip file, but it's better to verify the hash.
- For compatibility, even if the hash does not match, the file will be extracted with an error message.
- In the future, we may make this a hard error.
- Migration feature is no longer marked as experimental [`#1559`](https://github.com/vrc-get/vrc-get/pull/1559)
### Fixed
- Unity from Unity Hub will be registered as manually registered Unity [`#1081`](https://github.com/vrc-get/vrc-get/pull/1081)
- Fails to uninstall packages on macOS with filesystem that doesn't support resource fork [`#1402`](https://github.com/vrc-get/vrc-get/pull/1402)
- This is typically seen on ExFAT or FAT32 filesystems, not on APFS or HFS+ filesystems.
- macOS internally creates files starting with `._` for resource fork if the filesystem does not support resource fork.
- vrc-get-vpm does not handle this file correctly and fails to uninstall the package.
- Prerelease version is choosen even if good stable version exists [`#1745`](https://github.com/vrc-get/vrc-get/pull/1745)
### Security
## [1.8.2] - 2024-10-16
### Fixed
- Hotfix: Added contact information about author of the project to the User-Agent
## [1.8.1] - 2024-05-13
### Changed
@ -453,7 +506,10 @@ The format is based on [Keep a Changelog].
## [0.1.0] - 2023-01-25
Initial Release
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/v1.8.1...HEAD
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/v1.9.1...HEAD
[1.9.1]: https://github.com/vrc-get/vrc-get/compare/v1.9.0...v1.9.1
[1.9.0]: https://github.com/vrc-get/vrc-get/compare/v1.8.2...v1.9.0
[1.8.2]: https://github.com/vrc-get/vrc-get/compare/v1.8.1...v1.8.2
[1.8.1]: https://github.com/vrc-get/vrc-get/compare/v1.8.0...v1.8.1
[1.8.0]: https://github.com/vrc-get/vrc-get/compare/v1.7.1...v1.8.0
[1.7.1]: https://github.com/anatawa12/vrc-get/compare/v1.7.0...v1.7.1

View file

@ -6,7 +6,6 @@ This project consists of multiple projects.
Each project may have its own contribution guidelines, so please read the `CONTRIBUTING.md` file in the project folder.
- [vrc-get CLI](vrc-get/CONTRIBUTING.md) (not available yet)
- [vrc-get LiteDB](vrc-get-litedb/CONTRIBUTING.md)
- [vrc-get GUI](vrc-get-gui/CONTRIBUTING.md)
- [vrc-get VPM](vrc-get-vpm/CONTRIBUTING.md) (not available yet)
@ -23,11 +22,7 @@ so it is recommended to install with rustup and update it regularly.
Not only Rust, some projects may require additional dependencies.
For VCC-related features of vrc-get, and ALCOM, you need to install .NET SDK to work with.
Please refer to the [.NET installation guide](https://dotnet.microsoft.com/download) to install .NET SDK if you don't have it.
For ALCOM, you need to install any LTS version of Node.js and npm for building the frontend.
For ALCOM, you need to install Node.js >=20 supported and npm for building the frontend.
Please refer to the [Node.js installation guide](https://nodejs.org/en/download/) to install Node.js if you don't have it.
@ -45,7 +40,3 @@ You can work on any OS system, but this repository generally uses Symbolic Links
For Windows machines, you may need to set up so your current user can create symbolic links.
Please refer to git-for-windows documentation page <https://github.com/git-for-windows/git/wiki/Symbolic-Links>
In addition, when you work with `vrc-get-litedb` project,
you need to clone the repository with `--recurse-submodules` option
(or setup submodules manually with `git submodule update --init --recursive` after cloning).

4879
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,11 +2,10 @@
resolver = "2"
members = [
"build-check-static-link",
"build-updater-json",
"xtask",
"vrc-get",
"vrc-get-gui",
"vrc-get-litedb",
"vrc-get-gui/windows-installer-wrapper",
"vrc-get-vpm",
]
@ -14,15 +13,21 @@ members = [
# "build-check-static-link" is excluded since "build-check-static-link" is not a part of the main project, a utility for project
default-members = [
"vrc-get",
"vrc-get-litedb",
"vrc-get-vpm",
]
[workspace.package]
edition = "2021"
edition = "2024"
license = "MIT"
authors = ["anatawa12 <anatawa12@icloud.com>"]
homepage = "https://github.com/anatawa12/vrc-get#readme"
repository = "https://github.com/anatawa12/vrc-get"
readme = "README.md"
[profile.xtask]
inherits = "dev"
incremental = false
debug = 1
opt-level = 0
lto = "off"

View file

@ -9,6 +9,7 @@
[![MacPorts Version][shields-macports-vrc-get]][macports-vrc-get]
[![Scoop Version][shields-scoop-version]][scoop-vrc-get]
[![AUR Version][shields-aur-version]][aur-vrc-get]
[![WinGet Version][shields-winget-version]][winget-vrc-get]
Open Source command line client of VRChat Package Manager,
the main feature of VRChat Creator Companion (VCC), which supports Windows, Linux, and macOS.
@ -141,6 +142,7 @@ See [README of ALCOM][alcom] for more details.
[shields-homebrew-version]: https://img.shields.io/homebrew/v/vrc-get
[shields-macports-vrc-get]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fports.macports.org%2Fapi%2Fv1%2Fports%2Fvrc-get%2F&query=%24.version&label=macports
[shields-scoop-version]: https://img.shields.io/scoop/v/vrc-get?bucket=https%3A%2F%2Fgithub.com%2Fbabo4d%2Fscoop-xrtools
[shields-winget-version]: https://img.shields.io/winget/v/anatawa12.vrc-get
<!-- TODO: macports: https://github.com/badges/shields/issues/9588 -->
@ -162,6 +164,7 @@ See [README of ALCOM][alcom] for more details.
[homebrew-vrc-get]: https://formulae.brew.sh/formula/vrc-get
[macports-vrc-get]: https://ports.macports.org/port/vrc-get
[scoop-vrc-get]: https://github.com/babo4d/scoop-xrtools/blob/master/bucket/vrc-get.json
[winget-vrc-get]: https://github.com/microsoft/winget-pkgs/tree/master/manifests/a/anatawa12/vrc-get
## Contribution

View file

@ -1 +0,0 @@
/*

View file

@ -1,23 +0,0 @@
[package]
name = "build-check-static-link"
version = "0.1.0"
edition.workspace = true
license.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.object]
version = "0.36"
default-features = false
features = [
"read_core",
"macho",
"pe",
"elf",
]

View file

@ -1,11 +0,0 @@
This crate is to ensure built binary is statically linked or dynamically linked to the system libraries.
this crate use `object` crate to read the binary file.
## Usage
```
cargo run -p build-check-static-link <path/to/binary>
```
exits with zero if statically linked or linked with allowed dynamic libraries, otherwise exits with non-zero.

View file

@ -1,136 +0,0 @@
use object::{Endian, Endianness, FileKind, Object};
use std::fs;
use std::process::exit;
fn main() {
let mut args = std::env::args();
let _ = args.next();
let mut success = true;
for arg in args {
if arg.ends_with(".d") {
println!("skipping .d file: {}", arg);
continue;
}
let binary = std::path::Path::new(&arg);
let binary = fs::read(binary).unwrap();
success |= match FileKind::parse(binary.as_slice()).expect("detecting type") {
FileKind::MachO64 => process_mach_64::<Endianness>(&binary),
FileKind::Pe64 => process_pe_64(&binary),
FileKind::Elf64 => process_elf_64::<Endianness>(&binary),
unknown => panic!("unknown file type: {:?}", unknown),
};
}
if success {
exit(0)
} else {
exit(1)
}
}
fn process_mach_64<E: Endian>(binary: &[u8]) -> bool {
use object::macho::*;
use object::read::macho::*;
let mut success = true;
let parsed = MachHeader64::<E>::parse(binary, 0).expect("failed to parse binary");
let endian = parsed.endian().unwrap();
let mut commands = parsed
.load_commands(endian, binary, 0)
.expect("parsing binary");
while let Some(command) = commands.next().expect("reading binary") {
if let Some(dylib) = command.dylib().unwrap() {
let dylib = command.string(endian, dylib.dylib.name).unwrap();
match dylib {
| b"/System/Library/Frameworks/Security.framework/Versions/A/Security"
| b"/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration"
| b"/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
| b"/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation"
| b"/usr/lib/libobjc.A.dylib"
| b"/usr/lib/libiconv.2.dylib"
| b"/usr/lib/libSystem.B.dylib"
=> {
// known system library
println!("system dylib: {}", std::str::from_utf8(dylib).unwrap());
}
unknown => {
println!("ERROR: unknown dylib: {:?}", std::str::from_utf8(unknown).unwrap_or("unable to parse with utf8"));
success = false;
},
}
} else if command.cmd() == LC_LOAD_DYLINKER {
let data: &DylinkerCommand<E> = command.data().expect("parse LC_LOAD_DYLINKER");
if command.string(endian, data.name).unwrap() != b"/usr/lib/dyld" {
println!("ERROR: dylinker is not /usr/lib/dyld");
success = false;
} else {
println!("dylinker: /usr/lib/dyld");
}
}
}
success
}
fn process_pe_64(binary: &[u8]) -> bool {
use object::read::pe::*;
use object::LittleEndian as LE;
let mut success = true;
let parsed = PeFile64::parse(binary).expect("failed to parse binary");
let table = parsed.import_table().unwrap().unwrap();
let mut iter = table.descriptors().unwrap();
while let Some(x) = iter.next().unwrap() {
let dll = table.name(x.name.get(LE)).unwrap();
match dll.to_ascii_lowercase().as_slice() {
| b"advapi32.dll"
| b"kernel32.dll"
| b"bcrypt.dll" // TODO: check if this is a system library
| b"ntdll.dll"
| b"shell32.dll"
| b"ole32.dll"
| b"ws2_32.dll"
| b"crypt32.dll"
=> {
println!("system dll: {}", std::str::from_utf8(dll).unwrap());
// known system library
}
unknown => {
println!("ERROR: unknown dll: {:?}", std::str::from_utf8(unknown).unwrap_or("unable to parse with utf8"));
success = false;
},
}
}
success
}
fn process_elf_64<E: Endian>(binary: &[u8]) -> bool {
use object::elf::*;
use object::read::elf::*;
let mut success = true;
let parsed = ElfFile64::<E>::parse(binary).expect("failed to parse binary");
for x in parsed.imports().unwrap() {
println!(
"dynamic importing symbol: {}",
std::str::from_utf8(x.name()).unwrap()
);
success = false;
}
for segment in parsed.elf_program_headers() {
if segment.p_type.get(parsed.endian()) == PT_INTERP {
let data = segment.data(parsed.endian(), parsed.data()).unwrap();
println!("interpreter: {:?}", std::str::from_utf8(data).unwrap());
success = false;
}
}
success
}

View file

@ -1 +0,0 @@
/*

View file

@ -1,17 +0,0 @@
[package]
name = "build-updater-json"
version = "0.1.0"
edition.workspace = true
license.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = { version = "0.4", default-features = false, features = ["now", "serde"] }
indexmap = { version = "2", features = ["serde"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

View file

@ -1,90 +0,0 @@
// see https://tauri.app/v1/guides/distribution/updater/ for json format
use chrono::{Timelike, Utc};
use indexmap::IndexMap;
use serde::Serialize;
use std::path::Path;
#[derive(Serialize)]
struct UpdaterJson {
version: String,
notes: String,
pub_date: chrono::DateTime<Utc>,
platforms: IndexMap<String, Platform>,
}
#[derive(Serialize)]
struct Platform {
signature: String,
url: String,
}
fn main() {
// consts
const DOWNLOAD_URL_BASE: &str =
"https://github.com/vrc-get/vrc-get/releases/download/gui-v{version}";
let platform_file_name = [
("darwin-x86_64", "ALCOM-{version}-universal.app.tar.gz"),
("darwin-aarch64", "ALCOM-{version}-universal.app.tar.gz"),
("linux-x86_64", "alcom-{version}-x86_64.AppImage.tar.gz"),
//("linux-aarch64", "alcom-{version}-aarch64.AppImage.tar.gz"),
("windows-x86_64", "ALCOM-{version}-x86_64-setup.nsis.zip"),
//("windows-aarch64", "ALCOM-{version}-aarch64-setup.nsis.zip"),
]
.into_iter()
.collect::<IndexMap<_, _>>();
let version = std::env::var("GUI_VERSION").expect("GUI_VERSION not set");
let base_url = DOWNLOAD_URL_BASE.replace("{version}", &version);
// create platforms info
let mut platforms = IndexMap::new();
for (platform, file_name) in platform_file_name {
let file_name = file_name.replace("{version}", &version);
std::fs::metadata(format!("assets/{file_name}"))
.unwrap_or_else(|e| panic!("{}: {}", file_name, e));
let signature = std::fs::read_to_string(format!("assets/{file_name}.sig"))
.unwrap_or_else(|e| panic!("{}.sig: {}", file_name, e));
let url = format!("{}/{}", base_url, file_name);
platforms.insert(platform.to_string(), Platform { signature, url });
}
let stable_notes = get_notes("vrc-get-gui/notes.txt".as_ref());
let beta_notes = get_notes("vrc-get-gui/notes-beta.txt".as_ref());
let is_beta = version.contains('-');
let mut updater = UpdaterJson {
version,
notes: String::new(),
pub_date: Utc::now().with_nanosecond(0).unwrap(),
platforms,
};
if !is_beta {
updater.notes = stable_notes;
write_json("updater.json", &updater);
}
updater.notes = beta_notes;
write_json("updater-beta.json", &updater);
}
fn write_json(path: impl AsRef<Path>, json: impl Serialize) {
let json = serde_json::to_string_pretty(&json).unwrap();
std::fs::write(path, json).expect("write updater.json");
}
fn get_notes(path: &Path) -> String {
let notes = std::fs::read_to_string(path).expect("read notes.txt");
// lines starts with # are comments
notes
.trim_end()
.lines()
.filter(|x| !x.starts_with('#'))
.map(|x| x.trim_end())
.collect::<Vec<_>>()
.join("\n")
}

View file

@ -0,0 +1,45 @@
# Repository List file format
This document describes the format of the repository list file used in ALCOM / vrc-get.
## File format
1. The file is a UTF-8 encoded text file.
2. For each line, text after '#' will be ignored as a comment.
3. Each line contains a repository URL, or empty.
4. Each line is trimmed before processing. (this mean any line only with spaces will be ignored)
5. Each repository line should only contain a valid URL.
6. The URL schema must be `http`, `https`, or `vcc`.\
Other schemas are ignored and might be recognized for other purposes in the future.
7. If the URL is a `http` or `https` URL, the URL represents a VPM repository without headers.
8. If the URL is a `vcc` URL, the URL should be a VCC URL to add VPM repository, which is described below.\
This notation is used to express the repository with headers.
## VCC URL format
The VCC URL to add VPM Repository will be a valid URL with the following format:
- schema must be `vcc`
- the host part must be `vpm`
- the path part must be `/addRepo`
- the query part must contain single `url` parameter which represents the repository URL to add.
- the query part may contain `headers[]` parameter with represents the HTTP headers for the repository.
- query value will be split by `:` and prior part will be the header name and the rest will be the header value.
## Examples
```text
# This is a comment
http://example.com/repo
https://example.com/repo
vcc://vpm/addRepo?url=http://example.com/repo&headers[]=header-name:header-value
```
This file represents a repository list with the following repositories:
- `http://example.com/repo`
- `https://example.com/repo`
- `http://example.com/repo` with a custom header `header-name:header-value`
Another example may be found at the `repositories.txt` at the root of this repository.

View file

@ -4,11 +4,5 @@
.pnp.js
/gen
# next.js
/.next/
/out/
/build/
# typescript
*.tsbuildinfo
next-env.d.ts

1
vrc-get-gui/.npmrc Normal file
View file

@ -0,0 +1 @@
ignore-scripts=true

View file

@ -25,12 +25,13 @@
/*.ts
/*.tsx
/*.json
/index.html
# documentation
/*.md
# template
/templates/**
/project-templates/**
# icons
/app-icon.afdesign

View file

@ -1,7 +1,7 @@
[package]
name = "vrc-get-gui"
version = "0.1.15-beta.0"
description = "A Tauri App"
version = "1.1.7-beta.0"
description = "A fast open-source alternative of VRChat Creator Companion"
homepage.workspace = true
authors.workspace = true
@ -16,23 +16,25 @@ path = "src/main.rs"
[build-dependencies]
flate2 = "1"
tar = "0.4"
tauri-build = { version = "2.0.0-rc.3", features = [ "config-toml" ] }
tauri-build = { version = "2", features = [ "config-toml" ] }
[dependencies]
serde_json = "1"
serde = { version = "1", features = ["derive"] }
tauri = { version = "2.0.0-rc.3", features = [ "config-toml" ] }
vrc-get-vpm = { path = "../vrc-get-vpm", features = ["experimental-project-management", "experimental-unity-management", "tokio"] }
reqwest = "0.12"
specta = { version = "2.0.0-rc.20", features = [ "chrono", "url", "indexmap" ] }
tauri-specta = { version = "2.0.0-rc.17", features = ["typescript"] }
specta-typescript = "0.0.7"
serde_with = { version = "3", features = ["base64"] }
tauri = { version = "=2.11.2", features = [ "config-toml" ] } # = for sync version between npm and cargo
vrc-get-vpm = { path = "../vrc-get-vpm", features = ["experimental-project-management", "experimental-unity-management"] }
reqwest = { version = "0.13", features = ["gzip", "brotli", "json"] }
specta = { version = "2.0.0-rc.24", features = [ "chrono", "url", "indexmap" ] }
tauri-specta = { version = "2.0.0-rc.24", features = ["typescript"] }
specta-typescript = "0.0.11"
open = "5"
arc-swap = "1"
log = { version = "0.4", features = [ "std", "kv" ] }
chrono = { version = "0.4", features = [ "serde" ] }
ringbuffer = "0.15"
ringbuffer = "0.16"
tokio = { version = "1", features = ["process"] }
tokio-util = "0.7"
fs_extra = "1"
indexmap = "2"
futures = "0.3"
@ -40,28 +42,43 @@ tar = "0.4"
flate2 = "1"
uuid = { version = "1", features = ["v4"] }
trash = "5"
async_zip = { version = "0.0.17", features = ["deflate", "tokio"] }
async_zip = { version = "0.0.18", features = ["tokio", "deflate"] }
async-compression = { version = "0.4", features = ["gzip", "futures-io"] }
async-stream = "0.3"
tauri-plugin-single-instance = "2.0.0-rc.0"
tauri-plugin-updater = "2.0.0-rc.1"
tauri-plugin-dialog = "2.0.0-rc.1"
tauri-plugin-single-instance = "2"
tauri-plugin-dialog = "2"
minisign-verify = "0.2"
base64 = "0.22"
semver = "1"
tempfile = "3"
sha2 = "0.11"
hex = "0.4"
sys-locale = "0.3"
log-panics = { version = "2", features = ["with-backtrace"] }
url = "2"
dirs-next = "2"
yoke = { version = "0.7", features = ["derive"] }
yoke = { version = "0.8", features = ["derive"] }
atomicbox = "0.4"
stable_deref_trait = "1"
itertools = "0.14"
sysinfo = "0.39.3"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.58", features = ["Win32_Storage_FileSystem", "Win32_System_IO", "Win32_NetworkManagement_IpHelper", "Wdk_System_SystemServices", "Win32_System_SystemInformation"] }
winreg = "0.52"
windows = { version = "0.62", features = ["Win32_Storage_FileSystem", "Win32_System_IO", "Win32_NetworkManagement_IpHelper", "Wdk_System_SystemServices", "Win32_System_SystemInformation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
winreg = "0.56"
wmi = "0.18"
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.26"
plist = { version = "1" }
objc2-app-kit = { version = "0.3.0", features = ['NSWorkspace', "block2"] }
objc2-foundation = "0.3.0"
block2 = "0.6.0"
objc2 = "0.6.0"
dispatch2 = "0.3.0"
rlimit = "0.11.0"
[target.'cfg(unix)'.dependencies]
nix = { version = "0.29", features = ["fs"] }
nix = { version = "0.31", features = ["fs", "mount"] }
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
@ -69,7 +86,11 @@ nix = { version = "0.29", features = ["fs"] }
# DO NOT REMOVE!!
custom-protocol = [ "tauri/custom-protocol" ]
# rustc-check-cfg is not supported by tauri 1.x yet so we need to ignore it
# https://github.com/tauri-apps/tauri/pull/10392
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(dev)'] }
no-self-updater = []
# Devtools
#
# Enables browser devtools for debugging javascript part.
# It's not recommended to enable this for production builds,
# development use only!
devtools = ["tauri/devtools"]

View file

@ -15,5 +15,48 @@
</array>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>ALCOM Project Template</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSItemContentTypes</key>
<array>
<string>com.anatawa12.vrc-get.alcomtemplate</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>com.anatawa12.vrc-get.alcomtemplate</string>
<key>UTTypeIcons</key>
<dict>
<key>UTTypeIconText</key>
<string>Template</string>
<key>UTTypeIconBackgroundName</key>
<string></string>
<key>UTTypeIconBadgeName</key>
<string>icon.icns</string>
</dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>ALCOM Project Template</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>alcomtemplate</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View file

@ -1,46 +1,114 @@
# ALCOM (experimental)
# ALCOM
This folder contains the experimental GUI version of vrc-get, ALCOM.
[![Github Release][shields-github-version]][release-alcom]
[![Homebrew Version][shields-homebrew-version]][homebrew-alcom]
[![Scoop Version][shields-scoop-version]][scoop-alcom]
[![AUR Version][shields-aur-version]][aur-alcom]
[![WinGet Version][shields-winget-version]][winget-alcom]
<!-- [![MacPorts Version][shields-macports-vrc-get]][macports-vrc-get] -->
[Homepage (Help Wanted)](https://vrc-get.anatawa12.com/alcom/)
[shields-github-version]: https://img.shields.io/github/v/release/vrc-get/vrc-get?filter=gui-v*
[shields-homebrew-version]: https://img.shields.io/homebrew/cask/v/alcom
[shields-scoop-version]: https://img.shields.io/scoop/v/vrc-alcom?bucket=https%3A%2F%2Fgithub.com%2Fbabo4d%2Fscoop-xrtools
[shields-aur-version]: https://img.shields.io/aur/version/alcom
[shields-winget-version]: https://img.shields.io/winget/v/anatawa12.ALCOM
<!-- [shields-macports-vrc-get]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fports.macports.org%2Fapi%2Fv1%2Fports%2Falcom%2F&query=%24.version&label=macports -->
<!-- TODO: macports: https://github.com/badges/shields/issues/9588 -->
[release-alcom]: https://github.com/vrc-get/vrc-get/releases?q=gui-v1
[homebrew-alcom]: https://formulae.brew.sh/cask/alcom
[scoop-alcom]: https://github.com/babo4d/scoop-xrtools/blob/master/bucket/vrc-alcom.json
[aur-alcom]: https://aur.archlinux.org/packages/alcom
[winget-alcom]: https://github.com/microsoft/winget-pkgs/tree/master/manifests/a/anatawa12/ALCOM
<!-- [macports-vrc-get]: https://ports.macports.org/port/alcom -->
[scoop-xrtools]: https://github.com/babo4d/scoop-xrtools/
A crossplatform fast open-source alternative of VRChat Creator Companion
[Homepage](https://vrc-get.anatawa12.com/alcom/)
## Installation
The recommended way to install ALCOM is download from [GitHub Releases][alcom-releases].
The recommended way to install ALCOM is download from [Website][alcom-site].
Or you can install ALCOM from package managers like [Homebrew][homebrew-alcom], [Scoop][scoop-xrtools], [AUR][aur-alcom], or [WinGet][winget-alcom].
If you want, you may download the HEAD build from [GitHub Actions][alcom-nightly]
[alcom-releases]: https://github.com/anatawa12/vrc-get/releases?q=gui-v0
[alcom-site]: https://vrc-get.anatawa12.com/alcom/
[alcom-nightly]: https://github.com/vrc-get/vrc-get/actions/workflows/ci-gui.yml?query=branch%3Amaster
## Supported Platforms
ALCOM runs on macOS, Windows, and Linux.
We support modern versions of the platforms.
Basically, we support the versions that the platform vendor supports.
This support policy is to describe how my limited development resources use so it's welcome
to pull requests that ports ALCOM to an older version of OSes.
However, I won't maintain the backports so may break at any moment, I'll try to not break as possible though.
Here are detailed version support policies for each platform:
Version numbers shown here are as of the writing (Dec 2024), so might be outdated.
- macOS: We support the latest version of macOS that is available for non-vintage and non-obsoleted Macs.\
This means currently we support macOS 13 (Ventura) or later.
On macOS, we use WKWebView, which is built-in to macOS, so no additional requirements are needed.
- Windows: We support the latest version of Windows that is supported as mainstream by Microsoft.\
This means currently we support Windows 10 21H2 or later and Windows 11 23H2 or later.
On windows, we use WebView2 so WebView2 should also be updated to supported versions.
Currently, WebView2 with Edge 130 or later is supported.
- Linux: Linux is not well-supported, Linux support is best-effort by the community.\
No maintainer is using Linux as a primary platform, so we can't guarantee the quality of the Linux version.\
No specific version is guaranteed to work, but we will try to fix issues with your help.\
Basically, modern webkit2gtk 4.1 is required to run ALCOM since we use modern web features.
## Requirements (building)
To build ALCOM, you need to have the following installed:
- [Node.js] LTS — to build the web part of the project
- [Node.js] >=20 supported — to build the web part of the project
- [npm] v10 — to install the dependencies of the web part (bundled with node.js so no extra attention needed in most case)
- [cargo] latest — to build the most part of the project
- [cargo-about] latest — to generate the licenses json (for development, not required but required for building release binary)
- [.NET SDK] v8 — to build vrc-get-litedb crate
- And other requirements for tauri, see [tauri requirements](https://v2.tauri.app/start/prerequisites/#system-dependencies)
Please note that ALCOM requires the latest version of cargo and cargo-about at that time.
We update the required version of cargo and cargo-about without notice.
Therefore, you may need to update them before building the project.
Please note that ALCOM requires the latest version of rust toolchain at that time.
We update the required version of cargo without notice.
Therefore, It's recommended to update rust toolchain before building the project.
[Node.js]: https://nodejs.org/en
[npm]: https://www.npmjs.com
[cargo]: https://doc.rust-lang.org/cargo/
[cargo-about]: https://github.com/EmbarkStudios/cargo-about
[.NET SDK]: https://dotnet.microsoft.com/download
## Building
To build the project, run the following command:
```bash
npm run tauri build
cargo xtask build-alcom --release
```
This command builds the main ALCOM executable for the current platform.
For cross-compilation, add the `--target` command-line parameter.
The executable will be created in the `target/release` directory.
There are a few build options available when building ALCOM.
Most notably, you can disable the self-updater with the `--no-self-updater` option.
Note that this does not disable update checks.
ALCOM will show a message when a newer release is available instead of offering a self-update.
Directly distributing the executable may be suitable for some environments, but we also provide bundled distributions.
To bundle ALCOM, run the following command after building it.
```bash
cargo xtask bundle-alcom --release --bundles <bundles>
```
Check `--help` for the list of supported bundle types.
## Development
ALCOM is currently based on tauri and next.js.
@ -50,3 +118,7 @@ Run `npm run tauri dev` to start the development server and gui.
## Contribution
For how to contribute localization to ALCOM (vrc-get-gui): [CONTRIBUTING.md](CONTRIBUTING.md) (**Please read [../CONTRIBUTING.md#configuration-requirements](../CONTRIBUTING.md#configuration-requirements) first before you read [CONTRIBUTING.md](CONTRIBUTING.md)!**)
## License
ALCOM is licensed under the MIT License. See [LICENSE](../LICENSE) for more information.

View file

@ -6,52 +6,3 @@ beforeBuildCommand = "npm run build"
beforeDevCommand = "npm run dev"
devUrl = "http://localhost:3030"
frontendDist = "out"
[bundle]
active = true
targets = [
"appimage",
"nsis", #-setup.exe
"app", # needs for dmg
"dmg",
]
longDescription = "ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri."
shortDescription = "ALCOM - Alternative Creator Companion"
category = "DeveloperTool"
copyright = "(c) anatawa12 and other contributors"
externalBin = []
icon = [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico",
]
resources = []
publisher = "anatawa12"
createUpdaterArtifacts = "v1Compatible" # remove if ci # we do not generate updater artifacts in CI
[bundle.linux.deb]
depends = []
[bundle.macOS]
exceptionDomain = ""
frameworks = []
providerShortName = "anatawa12"
[bundle.windows]
nsis.template = "installer.nsi"
# signing
certificateThumbprint = "0D17F6395EC64A2B1D341BB7AC5B3163EB148BB7"
timestampUrl = "http://ts.ssl.com"
digestAlgorithm = "sha256"
tsp = true
[plugins.updater]
endpoints = []
pubkey = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDkyMjAzMkU2Q0ZGQjQ0MjYKUldRbVJQdlA1aklna2d2NnRoM3ZsT3lzWEQ3MC9zTGpaWVR4NGdQOXR0UGJaOHBlY2xCcFY5bHcK"
[app.security]

View file

@ -1,16 +0,0 @@
import { SideBar } from "@/components/SideBar";
export default function MainLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<>
<SideBar className={"flex-grow-0"} />
<div className={"h-screen flex-grow overflow-hidden flex p-4"}>
{children}
</div>
</>
);
}

View file

@ -1,276 +0,0 @@
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { SearchBox } from "@/components/SearchBox";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { type LogEntry, type LogLevel, commands } from "@/lib/bindings";
import { isFindKey, useDocumentEvent } from "@/lib/events";
import globalInfo from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { BugOff, CircleX, Info, OctagonAlert } from "lucide-react";
import { memo, useMemo, useRef, useState } from "react";
export const LogListCard = memo(function LogListCard({
logEntry,
}: {
logEntry: LogEntry[];
}) {
const [search, setSearch] = useState("");
const [shouldShowLogLevel, setShouldShowLogLevel] = useState<LogLevel[]>([
"Info",
"Warn",
"Error",
]);
const logsShown = useMemo(
() =>
logEntry.filter(
(log) =>
log.message.toLowerCase().includes(search?.toLowerCase() ?? "") &&
shouldShowLogLevel.includes(log.level),
),
[logEntry, search, shouldShowLogLevel],
);
const TABLE_HEAD = ["logs:time", "logs:level", "logs:message"];
return (
<Card className="flex-grow flex-shrink flex shadow-none w-full">
<CardContent className="w-full p-2 flex flex-col gap-2">
<ManageLogsHeading
search={search}
setSearch={setSearch}
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>
<ScrollableCardTable>
<thead>
<tr>
{TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
<th
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
/>
</tr>
</thead>
<tbody>
{logsShown.map((row) => (
<tr key={row.time} className="even:bg-secondary/30">
<LogRow log={row} />
</tr>
))}
</tbody>
</ScrollableCardTable>
</CardContent>
</Card>
);
});
function LogLevelMenuItem({
logLevel,
className,
shouldShowLogLevel,
setShouldShowLogLevel,
}: {
logLevel: LogLevel;
className?: string;
shouldShowLogLevel: LogLevel[];
setShouldShowLogLevel: React.Dispatch<React.SetStateAction<LogLevel[]>>;
}) {
const selected = shouldShowLogLevel.includes(logLevel);
const onChange = () => {
if (selected) {
setShouldShowLogLevel((prev) =>
prev.filter((logLevelFilter) => logLevelFilter !== logLevel),
);
} else {
setShouldShowLogLevel((prev) => [...prev, logLevel]);
}
};
return (
<DropdownMenuItem
className="p-0"
onSelect={(e) => {
e.preventDefault();
}}
>
<label
className={
"flex cursor-pointer items-center gap-2 p-2 whitespace-normal"
}
>
<Checkbox
checked={selected}
onCheckedChange={onChange}
className="hover:before:content-none"
/>
<p className={className}>{logLevel}</p>
</label>
</DropdownMenuItem>
);
}
function ManageLogsHeading({
search,
setSearch,
shouldShowLogLevel,
setShouldShowLogLevel,
}: {
search: string;
setSearch: (value: string) => void;
shouldShowLogLevel: LogLevel[];
setShouldShowLogLevel: React.Dispatch<React.SetStateAction<LogLevel[]>>;
}) {
const searchRef = useRef<HTMLInputElement>(null);
useDocumentEvent(
"keydown",
(e) => {
if (isFindKey(e)) {
searchRef.current?.focus();
}
},
[],
);
return (
<div
className={
"flex flex-wrap flex-shrink-0 flex-grow-0 flex-row gap-2 items-center"
}
>
<SearchBox
className={"w-max flex-grow"}
value={search}
onChange={(e) => setSearch(e.target.value)}
ref={searchRef}
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className={"flex-shrink-0 p-3"}>
{tc("logs:manage:select logs level")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<LogLevelMenuItem
logLevel="Info"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>
<LogLevelMenuItem
logLevel="Warn"
className="text-warning"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>
<LogLevelMenuItem
logLevel="Error"
className="text-destructive"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>
<LogLevelMenuItem
logLevel="Debug"
className="text-info"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>
{/* Currently no trace level logs will be passed to frontend */}
{/*<LogLevelMenuItem
logLevel="Trace"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>*/}
</DropdownMenuContent>
</DropdownMenu>
<Button
onClick={() =>
commands.utilOpen(
`${globalInfo.vpmHomeFolder}/vrc-get/gui-logs`,
"ErrorIfNotExists",
)
}
>
{tc("settings:button:open logs")}
</Button>
</div>
);
}
const LogRow = memo(function LogRow({
log,
}: {
log: LogEntry;
}) {
const cellClass = "p-2.5";
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleString();
};
const getFontColorClass = (level: LogLevel) => {
switch (level) {
case "Info":
return "";
case "Warn":
return "text-warning";
case "Error":
return "text-destructive";
case "Debug":
return "text-info";
default:
return "";
}
};
const fontColorClass = getFontColorClass(log.level);
const typeIconClass = `${fontColorClass} w-5 h-5`;
return (
<>
<td className={`${cellClass} min-w-32 w-32`}>{formatDate(log.time)}</td>
<td className={`${cellClass} min-w-28 w-28`}>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{log.level === "Info" ? (
<Info className={typeIconClass} />
) : log.level === "Warn" ? (
<OctagonAlert className={typeIconClass} />
) : log.level === "Error" ? (
<CircleX className={typeIconClass} />
) : log.level === "Debug" ? (
<BugOff className={typeIconClass} />
) : (
<Info className={typeIconClass} />
)}
</div>
<div className="flex flex-col justify-center">
<p className={`font-normal ${fontColorClass}`}>{log.level}</p>
</div>
</div>
</td>
<td className={`${cellClass} min-w-32 w-32`}>{log.message}</td>
</>
);
});

View file

@ -1,43 +0,0 @@
"use client";
import { HNavBar, VStack } from "@/components/layout";
import type { LogEntry } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { useTauriListen } from "@/lib/use-tauri-listen";
import React, { useCallback, useEffect } from "react";
import { LogListCard } from "./log-list-card";
export default function Page() {
const [logEntries, setLogEntries] = React.useState<LogEntry[]>([]);
useEffect(() => {
commands
.utilGetLogEntries()
.then((list) => setLogEntries([...list].reverse()));
}, []);
useTauriListen<LogEntry>(
"log",
useCallback((event) => {
setLogEntries((entries) => {
const entry = event.payload as LogEntry;
return [entry, ...entries];
});
}, []),
);
return (
<VStack>
<HNavBar className={"flex-shrink-0"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0">
{tc("logs")}
</p>
<div className={"flex-grow"} />
</HNavBar>
<main className="flex-shrink overflow-hidden flex w-full">
<LogListCard logEntry={logEntries} />
</main>
</VStack>
);
}

View file

@ -1,305 +0,0 @@
"use client";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { HNavBar, VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { TauriUserRepository } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import { useTauriListen } from "@/lib/use-tauri-listen";
import { useQuery } from "@tanstack/react-query";
import { ChevronDown, CircleX } from "lucide-react";
import type React from "react";
import {
Suspense,
useCallback,
useEffect,
useId,
useMemo,
useState,
} from "react";
import { HeadingPageName } from "../tab-selector";
import { useAddRepository } from "./use-add-repository";
import { useImportRepositories } from "./use-import-repositories";
export default function Page() {
return (
<Suspense>
<PageBody />
</Suspense>
);
}
function PageBody() {
const result = useQuery({
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
});
const addRepositoryInfo = useAddRepository({
refetch: () => result.refetch(),
});
const importRepositoryInfo = useImportRepositories({
refetch: () => result.refetch(),
});
const [exportRepositoriesRaw, exportDialog] = useFilePickerFunction(
commands.environmentExportRepositories,
);
const exportRepositories = useCallback(async () => {
try {
await exportRepositoriesRaw();
} catch (e) {
toastThrownError(e);
}
}, [exportRepositoriesRaw]);
const hiddenUserRepos = useMemo(
() => new Set(result.data?.hidden_user_repositories),
[result],
);
async function removeRepository(id: string) {
try {
await commands.environmentRemoveRepository(id);
await result.refetch();
} catch (e) {
toastThrownError(e);
}
}
const addRepository = addRepositoryInfo.addRepository;
const processDeepLink = useCallback(
async function processDeepLink() {
const data = await commands.deepLinkTakeAddRepository();
if (data == null) return;
await addRepository(data.url, data.headers);
},
[addRepository],
);
useTauriListen<null>(
"deep-link-add-repository",
useCallback(
(_) => {
// noinspection JSIgnoredPromiseFromCall
processDeepLink();
},
[processDeepLink],
),
);
// biome-ignore lint/correctness/useExhaustiveDependencies: we want to do on mount
useEffect(() => {
// noinspection JSIgnoredPromiseFromCall
processDeepLink();
// Only for initial load
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<VStack>
<HNavBar className={"flex-shrink-0"}>
<HeadingPageName pageType={"/packages/repositories"} />
<div className={"flex-grow"} />
<DropdownMenu>
<div className={"flex divide-x"}>
<Button
className={"rounded-r-none"}
onClick={addRepositoryInfo.openAddDialog}
>
{tc("vpm repositories:button:add repository")}
</Button>
<DropdownMenuTrigger asChild className={"rounded-l-none pl-2 pr-2"}>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuItem
onClick={importRepositoryInfo.startImportingRepositories}
>
{tc("vpm repositories:button:import repositories")}
</DropdownMenuItem>
<DropdownMenuItem onClick={exportRepositories}>
{tc("vpm repositories:button:export repositories")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</HNavBar>
<ScrollableCardTable>
<RepositoryTableBody
userRepos={result.data?.user_repositories || []}
hiddenUserRepos={hiddenUserRepos}
removeRepository={removeRepository}
refetch={() => result.refetch()}
/>
</ScrollableCardTable>
{addRepositoryInfo.dialog}
{importRepositoryInfo.dialog}
{exportDialog}
</VStack>
);
}
function RepositoryTableBody({
userRepos,
hiddenUserRepos,
removeRepository,
refetch,
}: {
userRepos: TauriUserRepository[];
hiddenUserRepos: Set<string>;
removeRepository: (id: string) => void;
refetch: () => void;
}) {
const TABLE_HEAD = [
"", // checkbox
"general:name",
"vpm repositories:url",
"", // actions
];
return (
<>
<thead>
<tr>
{TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
</tr>
</thead>
<tbody>
{userRepos.map((repo) => (
<RepositoryRow
key={repo.id}
repo={repo}
hiddenUserRepos={hiddenUserRepos}
remove={() => removeRepository(repo.id)}
refetch={refetch}
/>
))}
</tbody>
</>
);
}
function RepositoryRow({
repo,
hiddenUserRepos,
remove,
refetch,
}: {
repo: TauriUserRepository;
hiddenUserRepos: Set<string>;
remove: () => void;
refetch: () => void;
}) {
const cellClass = "p-2.5";
const id = useId();
const [removeDialogOpen, setRemoveDialogOpen] = useState(false);
const selected = !hiddenUserRepos.has(repo.id);
const onChange = () => {
if (selected) {
commands.environmentHideRepository(repo.id).then(refetch);
} else {
commands.environmentShowRepository(repo.id).then(refetch);
}
};
let dialog: React.ReactNode;
if (removeDialogOpen) {
dialog = (
<DialogOpen>
<DialogTitle>{tc("vpm repositories:remove repository")}</DialogTitle>
<DialogDescription>
<p className={"whitespace-normal font-normal"}>
{tc("vpm repositories:dialog:confirm remove description", {
name: repo.display_name,
})}
</p>
</DialogDescription>
<DialogFooter>
<Button onClick={() => setRemoveDialogOpen(false)}>
{tc("general:button:cancel")}
</Button>
<Button
onClick={() => {
remove();
setRemoveDialogOpen(false);
}}
className={"ml-2"}
>
{tc("vpm repositories:remove repository")}
</Button>
</DialogFooter>
</DialogOpen>
);
}
return (
<tr className="even:bg-secondary/30">
<td className={cellClass}>
<Checkbox id={id} checked={selected} onCheckedChange={onChange} />
</td>
<td className={cellClass}>
<label htmlFor={id}>
<p className="font-normal">{repo.display_name}</p>
</label>
</td>
<td className={cellClass}>
<p className="font-normal">{repo.url}</p>
</td>
<td className={`${cellClass} w-0`}>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => setRemoveDialogOpen(true)}
variant={"ghost"}
size={"icon"}
>
<CircleX className={"size-5 text-destructive"} />
</Button>
</TooltipTrigger>
<TooltipContent>
{tc("vpm repositories:remove repository")}
</TooltipContent>
</Tooltip>
</td>
{dialog}
</tr>
);
}

View file

@ -1,398 +0,0 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { assertNever } from "@/lib/assert-never";
import type {
TauriDownloadRepository,
TauriRepositoryDescriptor,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { callAsyncCommand } from "@/lib/call-async-command";
import { tc, tt } from "@/lib/i18n";
import { toastSuccess, toastThrownError } from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import type React from "react";
import { useCallback, useState } from "react";
type ParsedRepositories = {
repositories: TauriRepositoryDescriptor[];
unparsable_lines: string[];
};
type State =
| {
type: "normal";
}
| {
type: "confirmingRepositories";
pickResult: ParsedRepositories;
}
| {
type: "loadingRepositories";
totalCount: number;
downloaded: number;
cancel: () => void;
}
| {
type: "confirmingPackages";
repositories: [TauriRepositoryDescriptor, TauriDownloadRepository][];
}
| {
type: "addingRepositories";
};
interface AddRepository {
dialog: React.ReactNode;
startImportingRepositories: () => void;
}
export function useImportRepositories({
refetch,
}: {
refetch: () => void;
}): AddRepository {
const [state, setState] = useState<State>({ type: "normal" });
const [importRepositoryPick, pickDialog] = useFilePickerFunction(
commands.environmentImportRepositoryPick,
);
function cancel() {
if ("cancel" in state) state.cancel();
setState({ type: "normal" });
}
const startImportingRepositories = useCallback(
async function startImportingRepositories() {
try {
const pickResult = await importRepositoryPick();
switch (pickResult.type) {
case "NoFilePicked":
// no-op
return;
case "ParsedRepositories":
// continue
break;
default:
assertNever(pickResult, "pickResult");
}
console.log("confirmingRepositories", pickResult);
setState({ type: "confirmingRepositories", pickResult });
} catch (e) {
toastThrownError(e);
setState({ type: "normal" });
}
},
[importRepositoryPick],
);
const downloadRepositories = useCallback(async function downloadRepositories(
repositories: TauriRepositoryDescriptor[],
) {
try {
const totalCount = repositories.length;
const [cancel, resultPromise] = callAsyncCommand(
commands.environmentImportDownloadRepositories,
[repositories],
(downloaded) => {
setState({
type: "loadingRepositories",
totalCount,
downloaded,
cancel,
});
},
);
setState({
type: "loadingRepositories",
totalCount,
downloaded: 0,
cancel,
});
const result = await resultPromise;
if (result === "cancelled") {
return;
}
setState({ type: "confirmingPackages", repositories: result });
} catch (e) {
toastThrownError(e);
setState({ type: "normal" });
}
}, []);
const addRepositories = useCallback(
async function addRepositories(repositories: TauriRepositoryDescriptor[]) {
try {
setState({ type: "addingRepositories" });
await commands.environmentImportAddRepositories(repositories);
toastSuccess(tt("vpm repositories:toast:repositories added"));
refetch();
setState({ type: "normal" });
} catch (e) {
toastThrownError(e);
setState({ type: "normal" });
}
},
[refetch],
);
let dialogBody: React.ReactNode;
switch (state.type) {
case "normal":
dialogBody = null;
break;
case "confirmingRepositories":
dialogBody = (
<ConfirmingRepositoryList
pickResult={state.pickResult}
cancel={cancel}
importRepositories={downloadRepositories}
/>
);
break;
case "loadingRepositories":
dialogBody = (
<LoadingRepositories
cancel={cancel}
downloaded={state.downloaded}
totalCount={state.totalCount}
/>
);
break;
case "confirmingPackages":
dialogBody = (
<ConfirmingPackages
repositories={state.repositories}
cancel={cancel}
addRepositories={addRepositories}
/>
);
break;
case "addingRepositories":
dialogBody = <AddingRepositories />;
break;
default:
assertNever(state, "state");
}
const confirmDialog = dialogBody ? (
<DialogOpen>
<DialogTitle>
{tc("vpm repositories:dialog:import repositories")}
</DialogTitle>
{dialogBody}
</DialogOpen>
) : null;
return {
dialog: (
<>
{pickDialog}
{confirmDialog}
</>
),
startImportingRepositories,
};
}
function shortRepositoryDescription(
repo: TauriRepositoryDescriptor,
): React.ReactNode {
if (Object.keys(repo.headers).length > 0) {
return tc("vpm repositories:dialog:repository with headers", {
repoUrl: repo.url,
});
}
return repo.url;
}
function ConfirmingRepositoryList({
pickResult,
cancel,
importRepositories,
}: {
pickResult: ParsedRepositories;
cancel: () => void;
importRepositories: (repositories: TauriRepositoryDescriptor[]) => void;
}) {
const onContinue = useCallback(
async function onContinue() {
importRepositories(pickResult.repositories);
},
[importRepositories, pickResult.repositories],
);
return (
<>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"max-h-[50vh] overflow-y-auto font-normal"}>
<p className={"font-normal whitespace-normal"}>
{tc("vpm repositories:dialog:confirm repository list")}
</p>
<ul className={"list-disc pl-6"}>
{pickResult.repositories.map((info) => (
<li key={info.url}>{shortRepositoryDescription(info)}</li>
))}
</ul>
{pickResult.unparsable_lines.length > 0 && (
<>
<p className={"font-normal whitespace-normal"}>
{tc("vpm repositories:dialog:unparsable lines list")}
</p>
<ul className={"list-disc pl-6"}>
{pickResult.unparsable_lines.map((line, idx) => (
// biome-ignore lint/suspicious/noArrayIndexKey: unchanged
<li key={idx} className={"whitespace-pre"}>
{line}
</li>
))}
</ul>
</>
)}
</DialogDescription>
<DialogFooter className={"gap-2"}>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
<Button onClick={onContinue}>
{tc("vpm repositories:dialog:button:continue importing repositories")}
</Button>
</DialogFooter>
</>
);
}
function LoadingRepositories({
cancel,
downloaded,
totalCount,
}: {
cancel: () => void;
downloaded: number;
totalCount: number;
}) {
return (
<>
<DialogDescription>
<p>{tc("vpm repositories:dialog:downloading repositories...")}</p>
<Progress value={downloaded} max={totalCount} />
<div className={"text-center"}>
{tc("vpm repositories:dialog:downloaded n/m", {
downloaded,
totalCount,
})}
</div>
</DialogDescription>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
</DialogFooter>
</>
);
}
function ConfirmingPackages({
repositories,
cancel,
addRepositories,
}: {
repositories: [TauriRepositoryDescriptor, TauriDownloadRepository][];
cancel: () => void;
addRepositories: (repositories: TauriRepositoryDescriptor[]) => void;
}) {
const add = useCallback(
async function add() {
addRepositories(
repositories
.filter(([_, download]) => download.type === "Success")
.map(([repo, _]) => repo),
);
},
[addRepositories, repositories],
);
return (
<>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"font-normal"}>
<p className={"whitespace-normal"}>
{tc("vpm repositories:dialog:confirm packages list")}
</p>
<Accordion
type="single"
collapsible
className="max-h-[50vh] overflow-y-auto w-full"
>
{repositories.map(([repo, download]) => {
let error: boolean;
let content: React.ReactNode;
switch (download.type) {
case "BadUrl":
throw new Error("BadUrl should not be here");
case "Duplicated":
error = true;
content = tc(
"vpm repositories:dialog:download error:duplicated",
);
break;
case "DownloadError":
error = true;
content = tc(
"vpm repositories:dialog:download error:download error",
);
break;
case "Success":
error = false;
content = (
<ul className={"list-disc pl-6"}>
{download.value.packages.map((info, idx) => (
<li key={info.name}>{info.display_name ?? info.name}</li>
))}
</ul>
);
break;
default:
assertNever(download, "download");
}
const destrucive = error ? "text-destructive" : "";
return (
<AccordionItem value={repo.url} key={repo.url}>
<AccordionTrigger className={`${destrucive} py-2 text-base`}>
{shortRepositoryDescription(repo)}
</AccordionTrigger>
<AccordionContent className={destrucive}>
{content}
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
</DialogDescription>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
<Button onClick={add} className={"ml-2"}>
{tc("vpm repositories:button:add repositories")}
</Button>
</DialogFooter>
</>
);
}
function AddingRepositories() {
return (
<>
<DialogDescription>
<p>{tc("vpm repositories:dialog:adding repositories...")}</p>
</DialogDescription>
</>
);
}

View file

@ -1,54 +0,0 @@
import { tc } from "@/lib/i18n";
import Link from "next/link";
type PageType = "/packages/user-packages" | "/packages/repositories";
export function HeadingPageName({
pageType,
}: {
pageType: PageType;
}) {
return (
<div className={"-ml-2"}>
<div
className={"grid grid-cols-2 gap-1.5 bg-secondary p-1 -m-1 rounded-md"}
>
<HeadingButton
currentPage={pageType}
targetPage={"/packages/repositories"}
>
{tc("packages:community repositories")}
</HeadingButton>
<HeadingButton
currentPage={pageType}
targetPage={"/packages/user-packages"}
>
{tc("packages:user packages")}
</HeadingButton>
</div>
</div>
);
}
function HeadingButton({
currentPage,
targetPage,
children,
}: {
currentPage: PageType;
targetPage: PageType;
children: React.ReactNode;
}) {
const button =
"cursor-pointer py-1.5 font-bold flex-grow-0 hover:bg-background rounded-sm text-center p-2";
if (currentPage === targetPage) {
return <div className={`${button} bg-background`}>{children}</div>;
} else {
return (
<Link href={targetPage} className={button}>
{children}
</Link>
);
}
}

View file

@ -1,407 +0,0 @@
import { VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { assertNever } from "@/lib/assert-never";
import type {
TauriProjectDirCheckResult,
TauriProjectTemplate,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc, tt } from "@/lib/i18n";
import { pathSeparator } from "@/lib/os";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import { useDebounce } from "@uidotdev/usehooks";
import { RefreshCw } from "lucide-react";
import { useRouter } from "next/navigation";
import type React from "react";
import { useEffect, useState } from "react";
type CreateProjectstate =
| "loadingInitialInformation"
| "enteringInformation"
| "creating";
export function CreateProject({
close,
refetch,
}: {
close?: () => void;
refetch?: () => void;
}) {
const router = useRouter();
const [state, setState] = useState<CreateProjectstate>(
"loadingInitialInformation",
);
const [projectNameCheckState, setProjectNameCheckState] = useState<
"checking" | TauriProjectDirCheckResult
>("Ok");
type CustomTemplate = TauriProjectTemplate & { type: "Custom" };
const templateUnityVersions = [
"2022.3.22f1",
"2022.3.6f1",
"2019.4.31f1",
] as const;
const latestUnityVersion = templateUnityVersions[0];
type TemplateType = "avatars" | "worlds" | "custom";
type TemplateUnityVersion = (typeof templateUnityVersions)[number];
const [customTemplates, setCustomTemplates] = useState<CustomTemplate[]>([]);
const [templateType, setTemplateType] = useState<TemplateType>("avatars");
const [unityVersion, setUnityVersion] =
useState<TemplateUnityVersion>(latestUnityVersion);
const [customTemplate, setCustomTemplate] = useState<CustomTemplate>();
function onCustomTemplateChange(value: string) {
const newCustomTemplate: CustomTemplate = {
type: "Custom",
name: value,
};
setCustomTemplate(newCustomTemplate);
}
const [projectNameRaw, setProjectName] = useState("New Project");
const projectName = projectNameRaw.trim();
const [projectLocation, setProjectLocation] = useState("");
const projectNameDebounced = useDebounce(projectName, 500);
const [pickProjectDefaultPath, dialog] = useFilePickerFunction(
commands.environmentPickProjectDefaultPath,
);
useEffect(() => {
(async () => {
const information =
await commands.environmentProjectCreationInformation();
const customTemplates = information.templates.filter(
(template): template is CustomTemplate => template.type === "Custom",
);
setCustomTemplates(customTemplates);
setCustomTemplate(customTemplates[0]);
setProjectLocation(information.default_path);
setState("enteringInformation");
})();
}, []);
useEffect(() => {
let canceled = false;
(async () => {
try {
setProjectNameCheckState("checking");
const result = await commands.environmentCheckProjectName(
projectLocation,
projectNameDebounced,
);
if (canceled) return;
setProjectNameCheckState(result);
} catch (e) {
console.error("Error checking project name", e);
toastThrownError(e);
}
})();
return () => {
canceled = true;
};
}, [projectNameDebounced, projectLocation]);
const selectProjectDefaultFolder = async () => {
try {
const result = await pickProjectDefaultPath();
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("general:toast:invalid directory"));
break;
case "Successful":
setProjectLocation(result.new_path);
break;
default:
assertNever(result);
}
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const createProject = async () => {
try {
setState("creating");
let template: TauriProjectTemplate;
switch (templateType) {
case "avatars":
case "worlds":
template = {
type: "Builtin",
id: `${templateType}-${unityVersion}`,
name: `${templateType}-${unityVersion}`,
};
break;
case "custom":
if (customTemplate === undefined)
throw new Error("Custom template not selected");
template = customTemplate;
break;
default:
assertNever(templateType, "template type");
}
await commands.environmentCreateProject(
projectLocation,
projectName,
template,
);
toastSuccess(tt("projects:toast:project created"));
close?.();
refetch?.();
const projectPath = `${projectLocation}${pathSeparator()}${projectName}`;
router.push(`/projects/manage?${new URLSearchParams({ projectPath })}`);
} catch (e) {
console.error(e);
toastThrownError(e);
close?.();
}
};
const checking =
projectNameDebounced !== projectName ||
projectNameCheckState === "checking";
let projectNameState: "Ok" | "warn" | "err";
let projectNameCheck: React.ReactNode;
switch (projectNameCheckState) {
case "Ok":
projectNameCheck = tc("projects:hint:create project ready");
projectNameState = "Ok";
break;
case "InvalidNameForFolderName":
projectNameCheck = tc("projects:hint:invalid project name");
projectNameState = "err";
break;
case "MayCompatibilityProblem":
projectNameCheck = tc("projects:hint:warn symbol in project name");
projectNameState = "warn";
break;
case "WideChar":
projectNameCheck = tc(
"projects:hint:warn multibyte char in project name",
);
projectNameState = "warn";
break;
case "AlreadyExists":
projectNameCheck = tc("projects:hint:project already exists");
projectNameState = "err";
break;
case "checking":
projectNameCheck = <RefreshCw className={"w-5 h-5 animate-spin"} />;
projectNameState = "Ok";
break;
default:
assertNever(projectNameCheckState);
}
let projectNameStateClass: React.ReactNode;
switch (projectNameState) {
case "Ok":
projectNameStateClass = "text-success";
break;
case "warn":
projectNameStateClass = "text-warning";
break;
case "err":
projectNameStateClass = "text-destructive";
}
if (checking)
projectNameCheck = <RefreshCw className={"w-5 h-5 animate-spin"} />;
let dialogBody: React.ReactNode;
switch (state) {
case "loadingInitialInformation":
dialogBody = <RefreshCw className={"w-5 h-5 animate-spin"} />;
break;
case "enteringInformation": {
const renderUnityVersion = (unityVersion: string) => {
if (unityVersion === latestUnityVersion) {
return (
<>
{unityVersion}{" "}
<span className={"text-success"}>{tc("projects:latest")}</span>
</>
);
} else {
return unityVersion;
}
};
dialogBody = (
<>
<VStack>
<div className={"flex gap-1"}>
<div className={"flex items-center"}>
<label>{tc("projects:template:type")}</label>
</div>
<Select
defaultValue={templateType}
onValueChange={(value) =>
setTemplateType(value as TemplateType)
}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value={"avatars"}>
{tc("projects:type:avatars")}
</SelectItem>
<SelectItem value={"worlds"}>
{tc("projects:type:worlds")}
</SelectItem>
<SelectItem
value={"custom"}
disabled={customTemplates.length === 0}
>
{tc("projects:type:custom")}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
{templateType !== "custom" ? (
<div className={"flex gap-1"}>
<div className={"flex items-center"}>
<label>{tc("projects:template:unity version")}</label>
</div>
<Select
defaultValue={unityVersion}
onValueChange={(value) =>
setUnityVersion(value as TemplateUnityVersion)
}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{templateUnityVersions.map((unityVersion) => (
<SelectItem value={unityVersion} key={unityVersion}>
{renderUnityVersion(unityVersion)}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
) : (
<div className={"flex gap-1"}>
<div className={"flex items-center"}>
<label>{tc("projects:template")}</label>
</div>
<Select
value={customTemplate?.name}
onValueChange={onCustomTemplateChange}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{customTemplates.map((template) => (
<SelectItem value={template.name} key={template.name}>
{template.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
)}
<Input
value={projectNameRaw}
onChange={(e) => setProjectName(e.target.value)}
/>
<div className={"flex gap-1 items-center"}>
<Input className="flex-auto" value={projectLocation} disabled />
<Button
className="flex-none px-4"
onClick={selectProjectDefaultFolder}
>
{tc("general:button:select")}
</Button>
</div>
<small className={"whitespace-normal"}>
{tc(
"projects:hint:path of creating project",
{ path: `${projectLocation}${pathSeparator()}${projectName}` },
{
components: {
path: (
<span
className={
"p-0.5 font-path whitespace-pre bg-secondary text-secondary-foreground"
}
/>
),
},
},
)}
</small>
<small className={`whitespace-normal ${projectNameStateClass}`}>
{projectNameCheck}
</small>
</VStack>
</>
);
break;
}
case "creating":
dialogBody = (
<>
<RefreshCw className={"w-5 h-5 animate-spin"} />
<p>{tc("projects:creating project...")}</p>
</>
);
break;
}
return (
<DialogOpen>
<DialogTitle>{tc("projects:create new project")}</DialogTitle>
<DialogDescription>{dialogBody}</DialogDescription>
<DialogFooter className={"gap-2"}>
<Button onClick={close} disabled={state === "creating"}>
{tc("general:button:cancel")}
</Button>
<Button
onClick={createProject}
disabled={
state === "creating" || checking || projectNameState === "err"
}
>
{tc("projects:button:create")}
</Button>
</DialogFooter>
{dialog}
</DialogOpen>
);
}

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
type ComponentProps,
type ElementRef,
createContext,
forwardRef,
useContext,
} from "react";
interface PageContext {
isLoading: boolean;
}
export const PageContext = createContext<PageContext>({
isLoading: false,
});
PageContext.displayName = "PageContext";
export const PageContextProvider = PageContext.Provider;
export function usePageContext() {
return useContext(PageContext);
}
export const ButtonDisabledIfLoading = forwardRef<
ElementRef<typeof Button>,
ComponentProps<typeof Button>
>(function ButtonDisabledIfLoading({ disabled, ...props }, ref) {
const { isLoading } = usePageContext();
return <Button disabled={isLoading || disabled} {...props} ref={ref} />;
});
export const CheckboxDisabledIfLoading = forwardRef<
ElementRef<typeof Checkbox>,
ComponentProps<typeof Checkbox>
>(function CheckboxDisabledIfLoading({ disabled, ...props }, ref) {
const { isLoading } = usePageContext();
return <Checkbox disabled={isLoading || disabled} {...props} ref={ref} />;
});

View file

@ -1,671 +0,0 @@
"use client";
import { HNavBar, VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
} from "@/components/ui/select";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
UnityArgumentsSettings,
useUnityArgumentsSettings,
} from "@/components/unity-arguments-settings";
import { useBackupProjectModal } from "@/lib/backup-project";
import type { TauriProjectDetails, TauriUnityVersions } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { nameFromPath } from "@/lib/os";
import { useRemoveProjectModal } from "@/lib/remove-project";
import { toastSuccess, toastThrownError } from "@/lib/toast";
import { useOpenUnity } from "@/lib/use-open-unity";
import { compareUnityVersionString } from "@/lib/version";
import {
type UseQueryResult,
useQueries,
useQuery,
} from "@tanstack/react-query";
import { ArrowLeft, ChevronDown } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { Suspense, useCallback, useMemo, useState } from "react";
import {
VRCSDK_PACKAGES,
combinePackagesAndProjectDetails,
} from "./collect-package-row-info";
import { PackageListCard } from "./package-list-card";
import { PageContextProvider } from "./page-context";
import {
useUnity2022Migration,
useUnity2022PatchMigration,
useUnityVersionChange,
} from "./unity-migration";
import { usePackageChangeDialog } from "./use-package-change";
export default function Page() {
return (
<Suspense>
<PageBody />
</Suspense>
);
}
function PageBody() {
const searchParams = useSearchParams();
const router = useRouter();
const projectRemoveModal = useRemoveProjectModal({
onRemoved: () => router.back(),
});
const backupProjectModal = useBackupProjectModal();
const projectPath = searchParams.get("projectPath") ?? "";
const projectName = nameFromPath(projectPath);
// repositoriesInfo: list of repositories and their visibility
// packagesResult: list of packages
// detailsResult: project details including installed packages
// unityVersionsResult: list of unity versions installed
const [repositoriesInfo, packagesResult, detailsResult, unityVersionsResult] =
useQueries({
queries: [
{
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
refetchOnWindowFocus: false,
},
{
queryKey: ["environmentPackages"],
queryFn: commands.environmentPackages,
refetchOnWindowFocus: false,
},
{
queryKey: ["projectDetails", projectPath],
queryFn: () => commands.projectDetails(projectPath),
refetchOnWindowFocus: false,
},
{
queryKey: ["environmentUnityVersions"],
queryFn: () => commands.environmentUnityVersions(),
},
],
});
const [manualRefetching, setManualRefething] = useState<boolean>(false);
const packageRowsData = useMemo(() => {
const packages = packagesResult.data ?? [];
const details = detailsResult.data ?? null;
const hiddenRepositories =
repositoriesInfo.data?.hidden_user_repositories ?? [];
const hideUserPackages =
repositoriesInfo.data?.hide_local_user_packages ?? false;
const definedRepositories = repositoriesInfo.data?.user_repositories ?? [];
const showPrereleasePackages =
repositoriesInfo.data?.show_prerelease_packages ?? false;
return combinePackagesAndProjectDetails(
packages,
details,
hiddenRepositories,
hideUserPackages,
definedRepositories,
showPrereleasePackages,
);
}, [repositoriesInfo.data, packagesResult.data, detailsResult.data]);
const onRefresh = useCallback(async () => {
try {
setManualRefething(true);
await commands.environmentRefetchPackages();
packagesResult.refetch();
detailsResult.refetch();
repositoriesInfo.refetch();
unityVersionsResult.refetch();
} finally {
setManualRefething(false);
}
}, [detailsResult, packagesResult, repositoriesInfo, unityVersionsResult]);
const onRefreshProject = useCallback(() => {
detailsResult.refetch();
packagesResult.refetch(); // package changes require package list to be refreshed
}, [detailsResult, packagesResult]);
const packageChangeDialog = usePackageChangeDialog({
projectPath,
onRefreshProject,
packageRowsData,
existingPackages: detailsResult.data?.installed_packages,
});
const unity2022Migration = useUnity2022Migration({
projectPath,
refresh: onRefresh,
});
const unity2022PatchMigration = useUnity2022PatchMigration({
projectPath,
refresh: onRefresh,
});
const onRefreshRepositories = useCallback(() => {
repositoriesInfo.refetch();
}, [repositoriesInfo]);
const onRemoveProject = useCallback(() => {
projectRemoveModal.startRemove({
path: projectPath,
name: projectName,
is_exists: true,
});
}, [projectName, projectPath, projectRemoveModal]);
const onBackupProject = useCallback(() => {
backupProjectModal.startBackup({
path: projectPath,
name: projectName,
});
}, [backupProjectModal, projectName, projectPath]);
const onResolveRequest = useCallback(() => {
packageChangeDialog.createChanges(
{ type: "resolve" },
commands.projectResolve(projectPath),
);
}, [packageChangeDialog, projectPath]);
const isLoading =
packagesResult.isFetching ||
detailsResult.isFetching ||
repositoriesInfo.isFetching ||
unityVersionsResult.isLoading ||
packageChangeDialog.installingPackage ||
manualRefetching;
console.log(`rerender: isloading: ${isLoading}`);
function checkIfMigrationTo2022Recommended(data: TauriProjectDetails) {
if (data.unity == null) return false;
// migrate if the project is using 2019 and has vrcsdk
if (data.unity[0] !== 2019) return false;
return data.installed_packages.some(([id, _]) =>
VRCSDK_PACKAGES.includes(id),
);
}
function checkIf2022PatchMigrationRecommended(
data: TauriProjectDetails,
unityData: TauriUnityVersions,
) {
if (
!data.installed_packages.some(([id, _]) => VRCSDK_PACKAGES.includes(id))
)
return false;
if (data.unity == null) return false;
if (data.unity[0] !== 2022) return false;
// unity patch is 2022.
return data.unity_str !== unityData.recommended_version;
}
const isResolveRecommended = detailsResult?.data?.should_resolve;
const isMigrationTo2022Recommended =
detailsResult.status === "success" &&
checkIfMigrationTo2022Recommended(detailsResult.data);
const is2022PatchMigrationRecommended =
detailsResult.status === "success" &&
unityVersionsResult.status === "success" &&
checkIf2022PatchMigrationRecommended(
detailsResult.data,
unityVersionsResult.data,
);
const pageContext = useMemo(() => ({ isLoading }), [isLoading]);
return (
<PageContextProvider value={pageContext}>
<VStack>
<ProjectViewHeader
className={"flex-shrink-0"}
projectName={projectName}
projectPath={projectPath}
unityVersion={detailsResult.data?.unity_str ?? null}
unityRevision={detailsResult.data?.unity_revision ?? null}
onRemove={onRemoveProject}
onBackup={onBackupProject}
/>
<Card
className={"flex-shrink-0 p-2 flex flex-row flex-wrap items-center"}
>
<p className="cursor-pointer py-1.5 font-bold flex-grow flex-shrink overflow-hidden basis-52">
{tc(
"projects:manage:project location",
{ path: projectPath },
{
components: {
path: (
<span
className={
"p-0.5 font-path whitespace-pre bg-secondary text-secondary-foreground"
}
/>
),
},
},
)}
</p>
<div className={"flex-grow-0 flex-shrink-0 w-2"} />
<div className="flex-grow-0 flex-shrink-0 flex flex-row items-center">
<p className="cursor-pointer py-1.5 font-bold flex-grow-0 flex-shrink-0">
{tc("projects:manage:unity version")}
</p>
<div className={"flex-grow-0 flex-shrink-0"}>
<UnityVersionSelector
disabled={isLoading}
projectPath={projectPath}
detailsResult={detailsResult}
unityVersions={unityVersionsResult.data}
/>
</div>
</div>
</Card>
{isResolveRecommended && (
<SuggestResolveProjectCard
disabled={isLoading}
onResolveRequested={onResolveRequest}
/>
)}
{isMigrationTo2022Recommended && (
<SuggestMigrateTo2022Card
disabled={isLoading}
onMigrateRequested={() => unity2022Migration.request({})}
/>
)}
{is2022PatchMigrationRecommended && (
<Suggest2022PatchMigrationCard
disabled={isLoading}
onMigrateRequested={() => unity2022PatchMigration.request({})}
/>
)}
<main className="flex-shrink overflow-hidden flex w-full">
<PackageListCard
projectPath={projectPath}
createChanges={packageChangeDialog.createChanges}
packageRowsData={packageRowsData}
repositoriesInfo={repositoriesInfo.data}
onRefresh={onRefresh}
onRefreshRepositories={onRefreshRepositories}
/>
</main>
{packageChangeDialog.dialog}
{unity2022Migration.dialog}
{unity2022PatchMigration.dialog}
{projectRemoveModal.dialog}
{backupProjectModal.dialog}
</VStack>
</PageContextProvider>
);
}
function UnityVersionSelector({
disabled,
projectPath,
detailsResult,
unityVersions,
}: {
disabled?: boolean;
projectPath: string;
detailsResult: UseQueryResult<TauriProjectDetails>;
unityVersions?: TauriUnityVersions;
}) {
const unityChangeVersion = useUnityVersionChange({
projectPath,
refresh: () => detailsResult.refetch(),
});
const unityVersionNames = useMemo(() => {
if (unityVersions == null) return null;
const versionNames = [
...new Set<string>(unityVersions.unity_paths.map(([, path]) => path)),
];
versionNames.sort((a, b) => compareUnityVersionString(b, a));
return versionNames;
}, [unityVersions]);
const onChange = useCallback(
async (version: string) => {
const detailsData = detailsResult.data;
if (detailsData == null) return;
const currentUnityVersion = detailsData.unity_str;
if (currentUnityVersion == null) return;
const isVRCProject = detailsData.installed_packages.some(([id, _]) =>
VRCSDK_PACKAGES.includes(id),
);
unityChangeVersion.request({
version,
isVRCProject,
currentUnityVersion,
});
},
[detailsResult.data, unityChangeVersion],
);
return (
<Select
disabled={disabled}
value={detailsResult.data?.unity_str ?? undefined}
onValueChange={onChange}
>
<SelectTrigger>
{detailsResult.status === "success" ? (
detailsResult.data.unity_str ?? "unknown"
) : (
<span className={"text-primary"}>Loading...</span>
)}
</SelectTrigger>
<SelectContent>
<SelectGroup>
{unityVersionNames == null ? (
<SelectLabel>Loading...</SelectLabel>
) : (
unityVersionNames.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
))
)}
</SelectGroup>
</SelectContent>
{unityChangeVersion.dialog}
</Select>
);
}
function SuggestResolveProjectCard({
disabled,
onResolveRequested,
}: {
disabled?: boolean;
onResolveRequested: () => void;
}) {
return (
<Card className={"flex-shrink-0 p-2 flex flex-row items-center"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0 flex-shrink overflow-hidden whitespace-normal text-sm">
{tc("projects:manage:suggest resolve")}
</p>
<div className={"flex-grow flex-shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onResolveRequested}
disabled={disabled}
>
{tc("projects:manage:button:resolve")}
</Button>
</Card>
);
}
function SuggestMigrateTo2022Card({
disabled,
onMigrateRequested,
}: {
disabled?: boolean;
onMigrateRequested: () => void;
}) {
return (
<Card className={"flex-shrink-0 p-2 flex flex-row items-center"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0 flex-shrink overflow-hidden whitespace-normal text-sm">
{tc("projects:manage:suggest unity migration")}
</p>
<div className={"flex-grow flex-shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onMigrateRequested}
disabled={disabled}
>
{tc("projects:manage:button:unity migrate")}
</Button>
</Card>
);
}
function Suggest2022PatchMigrationCard({
disabled,
onMigrateRequested,
}: {
disabled?: boolean;
onMigrateRequested: () => void;
}) {
return (
<Card className={"flex-shrink-0 p-2 flex flex-row items-center"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0 flex-shrink overflow-hidden whitespace-normal text-sm">
{tc("projects:manage:suggest unity patch migration")}
</p>
<div className={"flex-grow flex-shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onMigrateRequested}
disabled={disabled}
>
{tc("projects:manage:button:unity migrate")}
</Button>
</Card>
);
}
function ProjectViewHeader({
className,
projectName,
projectPath,
unityVersion,
unityRevision,
onRemove,
onBackup,
}: {
className?: string;
projectName: string;
projectPath: string;
unityVersion: string | null;
unityRevision: string | null;
onRemove?: () => void;
onBackup?: () => void;
}) {
const openUnity = useOpenUnity();
const [openLaunchOptions, setOpenLaunchOptions] = useState<
| false
| {
initialArgs: null | string[];
defaultArgs: string[];
}
>(false);
const onChangeLaunchOptions = async () => {
const initialArgs = await commands.projectGetCustomUnityArgs(projectPath);
const defaultArgs = await commands.environmentGetDefaultUnityArguments();
setOpenLaunchOptions({
initialArgs,
defaultArgs,
});
};
const closeChangeLaunchOptions = () => {
setOpenLaunchOptions(false);
};
return (
<HNavBar className={className}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={"ghost"}
size={"icon"}
onClick={() => history.back()}
>
<ArrowLeft className={"w-5 h-5"} />
</Button>
</TooltipTrigger>
<TooltipContent>
{tc("projects:manage:tooltip:back to projects")}
</TooltipContent>
</Tooltip>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0 whitespace-pre">
{projectName}
</p>
<div className="relative flex gap-2 w-max flex-grow" />
<DropdownMenu>
<div className={"flex divide-x"}>
<Button
onClick={() =>
openUnity.openUnity(projectPath, unityVersion, unityRevision)
}
className={"rounded-r-none pl-4 pr-3"}
>
{tc("projects:button:open unity")}
</Button>
<DropdownMenuTrigger asChild className={"rounded-l-none pl-2 pr-2"}>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuContentBody
projectPath={projectPath}
onRemove={onRemove}
onBackup={onBackup}
onChangeLaunchOptions={onChangeLaunchOptions}
/>
</DropdownMenuContent>
</DropdownMenu>
{openUnity.dialog}
{openLaunchOptions !== false && (
<DialogOpen>
<LaunchSettings
projectPath={projectPath}
initialValue={openLaunchOptions.initialArgs}
defaultUnityArgs={openLaunchOptions.defaultArgs}
close={closeChangeLaunchOptions}
/>
</DialogOpen>
)}
</HNavBar>
);
}
function LaunchSettings({
projectPath,
defaultUnityArgs,
initialValue,
close,
}: {
projectPath: string;
defaultUnityArgs: string[];
initialValue: string[] | null;
close: () => void;
}) {
const context = useUnityArgumentsSettings(initialValue, defaultUnityArgs);
const saveAndClose = async () => {
await commands.projectSetCustomUnityArgs(projectPath, context.currentValue);
close();
};
return (
<>
<DialogTitle>{tc("projects:dialog:launch options")}</DialogTitle>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"max-h-[50dvh] overflow-y-auto"}>
<h3 className={"text-lg"}>
{tc("projects:dialog:command-line arguments")}
</h3>
<UnityArgumentsSettings context={context} />
</DialogDescription>
<DialogFooter>
<Button onClick={close} variant={"destructive"}>
{tc("general:button:cancel")}
</Button>
<Button onClick={saveAndClose} disabled={context.hasError}>
{tc("general:button:save")}
</Button>
</DialogFooter>
</>
);
}
function DropdownMenuContentBody({
projectPath,
onRemove,
onBackup,
onChangeLaunchOptions,
}: {
projectPath: string;
onRemove?: () => void;
onBackup?: () => void;
onChangeLaunchOptions?: () => void;
}) {
const openProjectFolder = () =>
commands.utilOpen(projectPath, "ErrorIfNotExists");
const forgetUnity = async () => {
try {
await commands.projectSetUnityPath(projectPath, null);
toastSuccess(tc("projects:toast:forgot unity path"));
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const unityPathQuery = useQuery({
queryFn: () => commands.projectGetUnityPath(projectPath),
queryKey: ["projectGetUnityPath", projectPath],
refetchOnWindowFocus: false,
});
const unityPath = unityPathQuery.data;
return (
<>
<DropdownMenuItem onClick={onChangeLaunchOptions}>
{tc("projects:menuitem:change launch options")}
</DropdownMenuItem>
{unityPath && (
<DropdownMenuItem onClick={forgetUnity}>
{tc("projects:menuitem:forget unity path")}
</DropdownMenuItem>
)}
<DropdownMenuItem onClick={openProjectFolder}>
{tc("projects:menuitem:open directory")}
</DropdownMenuItem>
<DropdownMenuItem onClick={onBackup}>
{tc("projects:menuitem:backup")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={onRemove}
className={"bg-destructive text-destructive-foreground"}
>
{tc("projects:remove project")}
</DropdownMenuItem>
</>
);
}

View file

@ -1,730 +0,0 @@
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { assertNever } from "@/lib/assert-never";
import type { TauriUnityVersions } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { callAsyncCommand } from "@/lib/call-async-command";
import { tc, tt } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { useUnitySelectorDialog } from "@/lib/use-unity-selector-dialog";
import { compareUnityVersionString, parseUnityVersion } from "@/lib/version";
import { useRouter } from "next/navigation";
import React, { Fragment, useCallback } from "react";
type UnityInstallation = [path: string, version: string, fromHub: boolean];
function findRecommendedUnity(
unityVersions: TauriUnityVersions,
): FindUnityResult {
const versions = unityVersions.unity_paths.filter(
([_p, v, _]) => v === unityVersions.recommended_version,
);
if (versions.length === 0) {
return {
expectingVersion: unityVersions.recommended_version,
installLink: unityVersions.install_recommended_version_link,
found: false,
};
} else {
return {
expectingVersion: unityVersions.recommended_version,
found: true,
installations: versions,
};
}
}
export function useUnity2022Migration({
projectPath,
refresh,
}: {
projectPath: string;
refresh?: () => void;
}): Result<Record<string, never>> {
return useMigrationInternal({
projectPath,
updateProjectPreUnityLaunch: async (project) =>
await commands.projectMigrateProjectTo2022(project),
findUnity: findRecommendedUnity,
refresh,
ConfirmComponent: MigrationConfirmMigrationDialog,
dialogHeader: () => tc("projects:manage:dialog:unity migrate header"),
});
}
function MigrationConfirmMigrationDialog({ cancel, doMigrate }: ConfirmProps) {
return (
<>
<DialogDescription>
<p className={"text-destructive"}>
{tc("projects:dialog:vpm migrate description")}
</p>
</DialogDescription>
<DialogFooter>
<Button onClick={cancel} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button
onClick={() => doMigrate(false)}
variant={"destructive"}
className="mr-1"
>
{tc("projects:button:migrate copy")}
</Button>
<Button onClick={() => doMigrate(true)} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</>
);
}
export function useUnity2022PatchMigration({
projectPath,
refresh,
}: {
projectPath: string;
refresh?: () => void;
}): Result<Record<string, never>> {
return useMigrationInternal({
projectPath,
updateProjectPreUnityLaunch: async () => {}, // nothing pre-launch
findUnity: findRecommendedUnity,
refresh,
ConfirmComponent: MigrationConfirmMigrationPatchDialog,
dialogHeader: () => tc("projects:manage:dialog:unity migrate header"),
});
}
function MigrationConfirmMigrationPatchDialog({
result,
cancel,
doMigrate,
}: ConfirmProps) {
const unity = result.expectingVersion;
return (
<>
<DialogDescription>
<p className={"text-destructive"}>
{tc("projects:dialog:migrate unity2022 patch description", { unity })}
</p>
</DialogDescription>
<DialogFooter>
<Button onClick={cancel} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button onClick={() => doMigrate(true)} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</>
);
}
// endregion unity version change
export function useUnityVersionChange({
projectPath,
refresh,
}: {
projectPath: string;
refresh?: () => void;
}): Result<{
version: string;
currentUnityVersion: string;
isVRCProject: boolean;
}> {
const use = useMigrationInternal({
projectPath,
updateProjectPreUnityLaunch: async (project, data) => {
if (
data.isVRC &&
data.kind === "upgradeMajor" &&
data.targetUnityVersion.startsWith("2022.")
) {
await commands.projectMigrateProjectTo2022(project);
}
},
findUnity: findUnityForUnityChange,
refresh,
ConfirmComponent: UnityVersionChange,
dialogHeader: (data) => {
if (data.isVRC && data.isTargetVersionSupportedByVRC) {
switch (data.kind) {
case "upgradePatchOrMinor":
case "upgradeMajor":
return tc("projects:manage:dialog:unity migrate header");
}
}
return tc("projects:manage:dialog:unity change version header");
},
});
const request = use.request;
return {
dialog: use.dialog,
request: useCallback(
({ version, currentUnityVersion, isVRCProject }) => {
if (currentUnityVersion == null) throw new Error("unexpected");
const v = detectChangeUnityKind(
currentUnityVersion,
version,
isVRCProject,
);
request(v);
},
[request],
),
};
}
function UnityVersionChange({
cancel,
doMigrate,
data,
result,
}: ConfirmProps<ChangeUnityData>) {
// TODO: description
if (data.isVRC && data.isTargetVersionSupportedByVRC) {
// for supported migrations, show dialog same as migration
switch (data.kind) {
case "upgradePatchOrMinor":
return (
<MigrationConfirmMigrationPatchDialog
cancel={cancel}
doMigrate={doMigrate}
result={result}
data={{}}
/>
);
case "upgradeMajor":
return (
<MigrationConfirmMigrationDialog
cancel={cancel}
doMigrate={doMigrate}
result={result}
data={{}}
/>
);
}
}
let mainMessage: React.ReactNode;
switch (data.kind) {
case "downgradeMajor":
if (data.isVRC) {
if (data.isTargetVersionSupportedByVRC) {
mainMessage = tc([
"projects:manage:dialog:downgrade major vrchat supported",
"projects:manage:dialog:downgrade major",
]);
} else {
mainMessage = tc([
"projects:manage:dialog:downgrade major vrchat unsupported",
"projects:manage:dialog:downgrade major",
]);
}
} else {
mainMessage = tc("projects:manage:dialog:downgrade major");
}
break;
case "downgradePatchOrMinor":
if (data.isVRC) {
if (data.isTargetVersionSupportedByVRC) {
mainMessage = tc([
"projects:manage:dialog:downgrade minor vrchat supported",
"projects:manage:dialog:downgrade minor",
]);
} else {
mainMessage = tc([
"projects:manage:dialog:downgrade minor vrchat unsupported",
"projects:manage:dialog:downgrade minor",
]);
}
} else {
mainMessage = tc("projects:manage:dialog:downgrade minor");
}
break;
case "upgradePatchOrMinor":
if (data.isVRC) {
if (data.isTargetVersionSupportedByVRC) {
mainMessage = tc([
"projects:manage:dialog:upgrade minor vrchat supported",
"projects:manage:dialog:upgrade minor",
]);
} else {
mainMessage = tc([
"projects:manage:dialog:upgrade minor vrchat unsupported",
"projects:manage:dialog:upgrade minor",
]);
}
} else {
mainMessage = tc("projects:manage:dialog:upgrade minor");
}
break;
case "upgradeMajor":
if (data.isVRC) {
if (data.isTargetVersionSupportedByVRC) {
mainMessage = tc([
"projects:manage:dialog:upgrade major vrchat supported",
"projects:manage:dialog:upgrade major",
]);
} else {
mainMessage = tc([
"projects:manage:dialog:upgrade major vrchat unsupported",
"projects:manage:dialog:upgrade major",
]);
}
} else {
mainMessage = tc("projects:manage:dialog:upgrade major");
}
break;
default:
assertNever(data.kind);
}
return (
<>
<DialogDescription>
<p className={"text-destructive"}>{mainMessage}</p>
</DialogDescription>
<DialogFooter>
<Button onClick={cancel} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button onClick={() => doMigrate(true)} variant={"destructive"}>
{tc("projects:button:change unity version")}
</Button>
</DialogFooter>
</>
);
}
type ChangeUnityKind =
| "downgradeMajor"
| "downgradePatchOrMinor"
| "upgradePatchOrMinor"
| "upgradeMajor";
type ChangeUnityData = (
| {
kind: ChangeUnityKind;
isVRC: false;
}
| {
kind: ChangeUnityKind;
isVRC: true;
isTargetVersionSupportedByVRC: boolean;
}
) & {
targetUnityVersion: string;
};
function detectChangeUnityKind(
currentVersion: string,
targetUnityVersion: string,
isVRCProject: boolean,
): ChangeUnityData {
// biome-ignore lint/style/noNonNullAssertion: the version is known to be valid
const parsedCurrent = parseUnityVersion(currentVersion)!;
// biome-ignore lint/style/noNonNullAssertion: the version is known to be valid
const parsedTarget = parseUnityVersion(targetUnityVersion)!;
const kind: ChangeUnityData["kind"] =
compareUnityVersionString(currentVersion, targetUnityVersion) >= 0
? parsedCurrent.major === parsedTarget.major
? "downgradePatchOrMinor"
: "downgradeMajor"
: parsedCurrent.major === parsedTarget.major
? "upgradePatchOrMinor"
: "upgradeMajor";
if (isVRCProject) {
const supportedVersions = ["2019.4.31f1", "2022.3.6f1", "2022.3.22f1"];
return {
kind,
isVRC: true,
isTargetVersionSupportedByVRC:
supportedVersions.includes(targetUnityVersion),
targetUnityVersion,
};
} else {
return {
kind,
isVRC: false,
targetUnityVersion,
};
}
}
function findUnityForUnityChange(
unityVersions: TauriUnityVersions,
data: ChangeUnityData,
): FindUnityResult {
const foundVersions = unityVersions.unity_paths.filter(
([_p, v, _]) => v === data.targetUnityVersion,
);
if (foundVersions.length === 0) throw new Error("unreachable");
return {
expectingVersion: data.targetUnityVersion,
found: true,
installations: foundVersions,
};
}
// endregion
type StateInternal<Data> =
| {
state: "normal";
}
| {
state: "confirm";
data: Data;
findResult: FindUnityResult & { found: true };
}
| {
state: "noExactUnity2022";
data: Data;
findResult: FindUnityResult & { found: false };
}
| {
state: "copyingProject";
data: Data;
}
| {
state: "updating";
data: Data;
}
| {
state: "finalizing";
data: Data;
lines: [number, string][];
};
type Result<Data> = {
dialog: React.ReactNode;
request: (data: Data) => void;
};
type ConfirmProps<Data = Record<string, never>> = {
result: FindUnityResult;
data: Data;
cancel: () => void;
doMigrate: (inPlace: boolean) => void;
};
type FindUnityResult = FindUnityFoundResult | FindUnityNotFoundResult;
interface FindUnityFoundResult {
expectingVersion: string;
found: true;
installations: UnityInstallation[];
}
interface FindUnityNotFoundResult {
expectingVersion: string;
installLink: string;
found: false;
}
function useMigrationInternal<Data>({
projectPath,
updateProjectPreUnityLaunch,
findUnity,
refresh,
ConfirmComponent,
dialogHeader,
}: {
projectPath: string;
updateProjectPreUnityLaunch: (
projectPath: string,
data: Data,
) => Promise<unknown>;
findUnity: (unityVersions: TauriUnityVersions, data: Data) => FindUnityResult;
refresh?: () => void;
ConfirmComponent: React.ComponentType<ConfirmProps<Data>>;
dialogHeader: (data: Data) => React.ReactNode;
}): Result<Data> {
const router = useRouter();
const unitySelector = useUnitySelectorDialog();
const [installStatus, setInstallStatus] = React.useState<StateInternal<Data>>(
{ state: "normal" },
);
const request = async (data: Data) => {
if (await commands.projectIsUnityLaunching(projectPath)) {
toastError(tt("projects:toast:close unity before migration"));
return;
}
const unityVersions = await commands.environmentUnityVersions();
const findResult = findUnity(unityVersions, data);
if (!findResult.found) {
setInstallStatus({ state: "noExactUnity2022", data, findResult });
} else setInstallStatus({ state: "confirm", data, findResult });
};
const startChangeUnityVersion = async (
inPlace: boolean,
unityFound: UnityInstallation[],
data: Data,
) => {
try {
switch (unityFound.length) {
case 0:
throw new Error("unreachable");
case 1:
void continueChangeUnityVersion(inPlace, unityFound[0][0], data);
break;
default: {
const selected = await unitySelector.select(unityFound);
if (selected == null) setInstallStatus({ state: "normal" });
else
void continueChangeUnityVersion(inPlace, selected.unityPath, data);
break;
}
}
} catch (e) {
console.error(e);
toastThrownError(e);
setInstallStatus({ state: "normal" });
}
};
const continueChangeUnityVersion = async (
inPlace: boolean,
unityPath: string,
data: Data,
) => {
try {
let migrateProjectPath: string;
if (inPlace) {
migrateProjectPath = projectPath;
} else {
// copy
setInstallStatus({ state: "copyingProject", data });
migrateProjectPath =
await commands.environmentCopyProjectForMigration(projectPath);
}
setInstallStatus({ state: "updating", data });
await updateProjectPreUnityLaunch(migrateProjectPath, data);
setInstallStatus({ state: "finalizing", lines: [], data });
let lineNumber = 0;
const [, promise] = callAsyncCommand(
commands.projectCallUnityForMigration,
[migrateProjectPath, unityPath],
(lineString) => {
setInstallStatus((prev) => {
if (prev.state !== "finalizing") return prev;
lineNumber++;
const line: [number, string] = [lineNumber, lineString];
if (prev.lines.length > 200) {
return { ...prev, lines: [...prev.lines.slice(1), line] };
} else {
return { ...prev, lines: [...prev.lines, line] };
}
});
},
);
const finalizeResult = await promise;
if (finalizeResult === "cancelled") {
throw new Error("unexpectedly cancelled");
}
switch (finalizeResult.type) {
case "ExistsWithNonZero":
toastError(tt("projects:toast:unity exits with non-zero"));
break;
case "FinishedSuccessfully":
toastSuccess(tt("projects:toast:unity migrated"));
break;
default:
assertNever(finalizeResult);
}
if (inPlace) {
setInstallStatus({ state: "normal" });
refresh?.();
} else {
setInstallStatus({ state: "normal" });
router.replace(
`/projects/manage?${new URLSearchParams({ projectPath: migrateProjectPath })}`,
);
}
} catch (e) {
console.error(e);
toastThrownError(e);
setInstallStatus({ state: "normal" });
}
};
const cancelChangeUnityVersion = async () => {
setInstallStatus({ state: "normal" });
};
let dialogHeaderForState: React.ReactNode = null;
let dialogBodyForState: React.ReactNode = null;
switch (installStatus.state) {
case "normal":
dialogBodyForState = null;
break;
case "confirm":
dialogHeaderForState = dialogHeader(installStatus.data);
dialogBodyForState = (
<ConfirmComponent
result={installStatus.findResult}
cancel={cancelChangeUnityVersion}
data={installStatus.data}
doMigrate={(inPlace) =>
startChangeUnityVersion(
inPlace,
installStatus.findResult.installations,
installStatus.data,
)
}
/>
);
break;
case "copyingProject":
dialogHeaderForState = dialogHeader(installStatus.data);
dialogBodyForState = <MigrationCopyingDialog />;
break;
case "updating":
dialogHeaderForState = dialogHeader(installStatus.data);
dialogBodyForState = <MigrationMigratingDialog />;
break;
case "noExactUnity2022":
dialogHeaderForState = dialogHeader(installStatus.data);
dialogBodyForState = (
<NoExactUnity2022Dialog
expectedVersion={installStatus.findResult.expectingVersion}
installWithUnityHubLink={installStatus.findResult.installLink}
close={cancelChangeUnityVersion}
/>
);
break;
case "finalizing":
dialogHeaderForState = dialogHeader(installStatus.data);
dialogBodyForState = (
<MigrationCallingUnityForMigrationDialog lines={installStatus.lines} />
);
break;
default:
assertNever(installStatus);
}
return {
dialog: (
<>
{unitySelector.dialog}
{dialogBodyForState == null ? null : (
<DialogOpen className={"whitespace-normal leading-relaxed"}>
<DialogTitle>{dialogHeaderForState}</DialogTitle>
{dialogBodyForState}
</DialogOpen>
)}
</>
),
request,
};
}
function MigrationCopyingDialog() {
return (
<DialogDescription>
<p>{tc("projects:pre-migrate copying...")}</p>
<p>{tc("projects:do not close")}</p>
</DialogDescription>
);
}
function MigrationMigratingDialog() {
return (
<DialogDescription>
<p>{tc("projects:migrating...")}</p>
<p>{tc("projects:do not close")}</p>
</DialogDescription>
);
}
function MigrationCallingUnityForMigrationDialog({
lines,
}: {
lines: [number, string][];
}) {
const ref = React.useRef<HTMLDivElement>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: we want to scroll to bottom on lines changed
React.useEffect(() => {
ref.current?.scrollIntoView({ behavior: "auto" });
}, [lines]);
return (
<DialogDescription>
<p>{tc("projects:manage:dialog:unity migrate finalizing...")}</p>
<p>{tc("projects:do not close")}</p>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<pre
className={
"overflow-y-auto h-[50vh] bg-secondary text-secondary-foreground text-sm"
}
>
{lines.map(([lineNumber, line]) => (
<Fragment key={lineNumber}>
{line}
{"\n"}
</Fragment>
))}
<div ref={ref} />
</pre>
</DialogDescription>
);
}
function NoExactUnity2022Dialog({
expectedVersion,
installWithUnityHubLink,
close,
}: {
expectedVersion: string;
installWithUnityHubLink: string;
close: () => void;
}) {
const openUnityHub = async () => {
await commands.utilOpenUrl(installWithUnityHubLink);
};
return (
<>
<DialogDescription>
<p>
{tc(
"projects:manage:dialog:exact version unity not found for patch migration description",
{ unity: expectedVersion },
)}
</p>
</DialogDescription>
<DialogFooter className={"gap-2"}>
<Button onClick={openUnityHub}>
{tc("projects:dialog:open unity hub")}
</Button>
<Button onClick={close} className="mr-1">
{tc("general:button:close")}
</Button>
</DialogFooter>
</>
);
}

View file

@ -1,489 +0,0 @@
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { assertNever } from "@/lib/assert-never";
import type {
TauriBasePackageInfo,
TauriPackage,
TauriPackageChange,
TauriPendingProjectChanges,
TauriRemoveReason,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc, tt } from "@/lib/i18n";
import { toastInfo, toastSuccess, toastThrownError } from "@/lib/toast";
import { compareVersion, toVersionString } from "@/lib/version";
import type React from "react";
import { useCallback, useMemo, useState } from "react";
import type { PackageRowInfo } from "./collect-package-row-info";
export type RequestedOperation =
| {
type: "install";
pkg: TauriPackage;
hasUnityIncompatibleLatest?: boolean;
}
| {
type: "upgradeAll";
hasUnityIncompatibleLatest: boolean;
}
| {
type: "resolve";
}
| {
type: "reinstallAll";
}
| {
type: "remove";
displayName: string;
}
| {
type: "bulkInstalled";
hasUnityIncompatibleLatest: boolean;
}
| {
type: "bulkReinstalled";
}
| {
type: "bulkRemoved";
};
type InstallStatus =
| {
status: "normal";
}
| {
status: "creatingChanges";
}
| {
status: "promptingChanges";
changes: TauriPendingProjectChanges;
requested: RequestedOperation;
}
| {
status: "applyingChanges";
};
interface PackageChangeDialog {
createChanges: (
operation: RequestedOperation,
createPromise: Promise<TauriPendingProjectChanges>,
) => void;
dialog: React.ReactNode;
installingPackage: boolean;
}
export function usePackageChangeDialog({
projectPath,
onRefreshProject,
packageRowsData,
existingPackages,
}: {
projectPath: string;
onRefreshProject: () => void;
packageRowsData: PackageRowInfo[];
existingPackages?: [string, TauriBasePackageInfo][];
}): PackageChangeDialog {
const [installStatus, setInstallStatus] = useState<InstallStatus>({
status: "normal",
});
const createChanges = useCallback(
async (
operation: RequestedOperation,
createPromise: Promise<TauriPendingProjectChanges>,
) => {
try {
setInstallStatus({ status: "creatingChanges" });
const changes = await createPromise;
setInstallStatus({
status: "promptingChanges",
changes,
requested: operation,
});
} catch (e) {
console.error(e);
toastThrownError(e);
setInstallStatus({ status: "normal" });
}
},
[],
);
let dialogForState: React.ReactNode = null;
switch (installStatus.status) {
case "promptingChanges": {
const applyChanges = async ({
changes,
requested,
}: {
changes: TauriPendingProjectChanges;
requested: RequestedOperation;
}) => {
try {
setInstallStatus({ status: "applyingChanges" });
await commands.projectApplyPendingChanges(
projectPath,
changes.changes_version,
);
setInstallStatus({ status: "normal" });
onRefreshProject();
switch (requested.type) {
case "install":
toastSuccess(
tt("projects:manage:toast:package installed", {
name: requested.pkg.display_name ?? requested.pkg.name,
version: toVersionString(requested.pkg.version),
}),
);
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:the package has newer latest with incompatible unity",
),
);
}
break;
case "remove":
toastSuccess(
tt("projects:manage:toast:package removed", {
name: requested.displayName,
}),
);
break;
case "resolve":
toastSuccess(tt("projects:manage:toast:resolved"));
break;
case "reinstallAll":
toastSuccess(
tt("projects:manage:toast:all packages reinstalled"),
);
break;
case "upgradeAll":
toastSuccess(tt("projects:manage:toast:all packages upgraded"));
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:some package has newer latest with incompatible unity",
),
);
}
break;
case "bulkInstalled":
toastSuccess(
tt("projects:manage:toast:selected packages installed"),
);
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:some package has newer latest with incompatible unity",
),
);
}
break;
case "bulkRemoved":
toastSuccess(
tt("projects:manage:toast:selected packages removed"),
);
break;
case "bulkReinstalled":
toastSuccess(
tt("projects:manage:toast:selected packages reinstalled"),
);
break;
default:
assertNever(requested);
}
} catch (e) {
console.error(e);
setInstallStatus({ status: "normal" });
toastThrownError(e);
}
};
const cancel = async () => {
setInstallStatus({ status: "normal" });
try {
await commands.projectClearPendingChanges();
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
dialogForState = (
<ProjectChangesDialog
packages={packageRowsData}
changes={installStatus.changes}
existingPackages={existingPackages}
cancel={cancel}
apply={() => applyChanges(installStatus)}
/>
);
break;
}
}
return {
dialog: dialogForState,
createChanges,
installingPackage: installStatus.status !== "normal",
};
}
function ProjectChangesDialog({
changes,
packages,
existingPackages,
cancel,
apply,
}: {
changes: TauriPendingProjectChanges;
packages: PackageRowInfo[];
existingPackages?: [string, TauriBasePackageInfo][];
cancel: () => void;
apply: () => void;
}) {
const versionConflicts = changes.conflicts.filter(
([_, c]) => c.packages.length > 0,
);
const unityConflicts = changes.conflicts.filter(([_, c]) => c.unity_conflict);
const getPackageDisplayName = useMemo(() => {
const packagesById = new Map(packages.map((p) => [p.id, p]));
return (pkgId: string) => packagesById.get(pkgId)?.displayName ?? pkgId;
}, [packages]);
const TypographyItem = ({ children }: { children: React.ReactNode }) => (
<div className={"p-3"}>
<p className={"font-normal"}>{children}</p>
</div>
);
function isInstallNew(
pair: [string, TauriPackageChange],
): pair is [string, { InstallNew: TauriPackage }] {
return "InstallNew" in pair[1];
}
function isRemove(
pair: [string, TauriPackageChange],
): pair is [string, { Remove: TauriRemoveReason }] {
return "Remove" in pair[1];
}
const existingPackageMap = new Map(existingPackages ?? []);
const installingPackages = changes.package_changes.filter(isInstallNew);
const removingPackages = changes.package_changes.filter(isRemove);
const reInstallingPackages = installingPackages.filter(([pkgId, c]) => {
const info = existingPackageMap.get(pkgId);
return (
info !== undefined &&
compareVersion(c.InstallNew.version, info.version) === 0
);
});
const installingNewPackages = installingPackages.filter(([pkgId, c]) => {
const info = existingPackageMap.get(pkgId);
return (
info === undefined ||
compareVersion(c.InstallNew.version, info.version) !== 0
);
});
const removingRequestedPackages = removingPackages.filter(
([_, c]) => c.Remove === "Requested",
);
const removingLegacyPackages = removingPackages.filter(
([_, c]) => c.Remove === "Legacy",
);
const removingUnusedPackages = removingPackages.filter(
([_, c]) => c.Remove === "Unused",
);
reInstallingPackages.sort(comparePackageChangeByName);
installingNewPackages.sort(comparePackageChangeByName);
removingRequestedPackages.sort(comparePackageChangeByName);
removingLegacyPackages.sort(comparePackageChangeByName);
removingUnusedPackages.sort(comparePackageChangeByName);
const ChangelogButton = ({ url }: { url?: string | null }) => {
if (url == null) return null;
try {
const parsed = new URL(url);
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
return (
<Button
className={"ml-1 px-2"}
size={"sm"}
onClick={() => commands.utilOpenUrl(url)}
>
{tc("projects:manage:button:see changelog")}
</Button>
);
}
} catch {}
return null;
};
return (
<DialogOpen className={"whitespace-normal"}>
<DialogTitle>{tc("projects:manage:button:apply changes")}</DialogTitle>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"overflow-y-auto max-h-[50vh]"}>
<p>{tc("projects:manage:dialog:confirm changes description")}</p>
<div className={"flex flex-col gap-1 p-2"}>
{installingNewPackages.map(([pkgId, pkgChange]) => {
const name =
pkgChange.InstallNew.display_name ?? pkgChange.InstallNew.name;
const version = toVersionString(pkgChange.InstallNew.version);
return (
<div key={pkgId} className={"flex items-center p-3"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:install package", {
name,
version,
})}
</p>
<ChangelogButton url={pkgChange.InstallNew.changelog_url} />
</div>
);
})}
{installingNewPackages.length > 0 &&
reInstallingPackages.length > 0 && <hr />}
{reInstallingPackages.map(([pkgId, pkgChange]) => {
const name =
pkgChange.InstallNew.display_name ?? pkgChange.InstallNew.name;
const version = toVersionString(pkgChange.InstallNew.version);
return (
<div key={pkgId} className={"flex items-center p-3"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:reinstall package", {
name,
version,
})}
</p>
<ChangelogButton url={pkgChange.InstallNew.changelog_url} />
</div>
);
})}
{removingRequestedPackages.map(([pkgId, _]) => {
const name = getPackageDisplayName(pkgId);
return (
<TypographyItem key={pkgId}>
{tc("projects:manage:dialog:uninstall package as requested", {
name,
})}
</TypographyItem>
);
})}
{removingLegacyPackages.map(([pkgId, _]) => {
const name = getPackageDisplayName(pkgId);
return (
<TypographyItem key={pkgId}>
{tc("projects:manage:dialog:uninstall package as legacy", {
name,
})}
</TypographyItem>
);
})}
{removingUnusedPackages.map(([pkgId, _]) => {
const name = getPackageDisplayName(pkgId);
return (
<TypographyItem key={pkgId}>
{tc("projects:manage:dialog:uninstall package as unused", {
name,
})}
</TypographyItem>
);
})}
</div>
{versionConflicts.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc("projects:manage:dialog:package version conflicts", {
count: versionConflicts.length,
})}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{versionConflicts.map(([pkgId, conflict]) => {
return (
<TypographyItem key={pkgId}>
{tc("projects:manage:dialog:conflicts with", {
pkg: getPackageDisplayName(pkgId),
other: conflict.packages
.map((p) => getPackageDisplayName(p))
.join(", "),
})}
</TypographyItem>
);
})}
</div>
</>
) : null}
{unityConflicts.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc("projects:manage:dialog:unity version conflicts", {
count: unityConflicts.length,
})}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{unityConflicts.map(([pkgId, _]) => (
<TypographyItem key={pkgId}>
{tc(
"projects:manage:dialog:package not supported your unity",
{ pkg: getPackageDisplayName(pkgId) },
)}
</TypographyItem>
))}
</div>
</>
) : null}
{changes.remove_legacy_files.length > 0 ||
changes.remove_legacy_folders.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc(
"projects:manage:dialog:files and directories are removed as legacy",
)}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{changes.remove_legacy_files.map((f) => (
<TypographyItem key={f}>{f}</TypographyItem>
))}
{changes.remove_legacy_folders.map((f) => (
<TypographyItem key={f}>{f}</TypographyItem>
))}
</div>
</>
) : null}
</DialogDescription>
<DialogFooter>
<Button onClick={cancel} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button onClick={apply} variant={"destructive"}>
{tc("projects:manage:button:apply")}
</Button>
</DialogFooter>
</DialogOpen>
);
}
function comparePackageChangeByName(
[aName, _1]: [string, TauriPackageChange],
[bName, _2]: [string, TauriPackageChange],
): number {
return aName.localeCompare(bName);
}

View file

@ -1,443 +0,0 @@
"use client";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { SearchBox } from "@/components/SearchBox";
import { HNavBar, VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { assertNever } from "@/lib/assert-never";
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { isFindKey, useDocumentEvent } from "@/lib/events";
import { tc, tt } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import { type OpenUnityFunction, useOpenUnity } from "@/lib/use-open-unity";
import { compareUnityVersionString } from "@/lib/version";
import { useQuery } from "@tanstack/react-query";
import {
ChevronDown,
ChevronUp,
ChevronsUpDown,
RefreshCw,
Star,
} from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";
import { CreateProject } from "./create-project";
import { ProjectRow } from "./project-row";
const sortings = ["lastModified", "name", "unity", "type"] as const;
type SimpleSorting = (typeof sortings)[number];
type Sorting = SimpleSorting | `${SimpleSorting}Reversed`;
function isSorting(s: string): s is Sorting {
return sortings.some(
(sorting) => sorting === s || `${sorting}Reversed` === s,
);
}
export default function Page() {
const result = useQuery({
queryKey: ["projects"],
queryFn: commands.environmentProjects,
});
const [search, setSearch] = useState("");
const [loadingOther, setLoadingOther] = useState(false);
const [createProjectState, setCreateProjectState] = useState<
"normal" | "creating"
>("normal");
const openUnity = useOpenUnity();
const startCreateProject = () => setCreateProjectState("creating");
const loading = result.isFetching || loadingOther;
return (
<VStack>
<ProjectViewHeader
className={"flex-shrink-0"}
refresh={() => result.refetch()}
startCreateProject={startCreateProject}
isLoading={loading}
search={search}
setSearch={setSearch}
/>
{result.status === "pending" ? (
<Card className="w-full shadow-none overflow-hidden p-4">
{tc("general:loading...")}
</Card>
) : result.status === "error" ? (
<Card className="w-full shadow-none overflow-hidden p-4">
{tc("projects:error:load error", { msg: result.error.message })}
</Card>
) : (
<ProjectsTableCard
projects={result.data}
search={search}
loading={loading}
openUnity={openUnity.openUnity}
refresh={() => result.refetch()}
onRemoved={() => result.refetch()}
/>
)}
{createProjectState === "creating" && (
<CreateProject
close={() => setCreateProjectState("normal")}
refetch={() => result.refetch()}
/>
)}
{openUnity.dialog}
</VStack>
);
}
function compareProjectType(
a: TauriProjectType,
b: TauriProjectType,
): 0 | -1 | 1 {
if (a === b) return 0;
// legacy unknown
if (a === "LegacySdk2") return 1;
if (b === "LegacySdk2") return -1;
if (a === "UpmStarter") return 1;
if (b === "UpmStarter") return -1;
// legacy worlds
if (a === "LegacyWorlds") return 1;
if (b === "LegacyWorlds") return -1;
if (a === "UpmWorlds") return 1;
if (b === "UpmWorlds") return -1;
// legacy avatars
if (a === "LegacyAvatars") return 1;
if (b === "LegacyAvatars") return -1;
if (a === "UpmAvatars") return 1;
if (b === "UpmAvatars") return -1;
// unknown
if (a === "Unknown") return 1;
if (b === "Unknown") return -1;
if (a === "VpmStarter") return 1;
if (b === "VpmStarter") return -1;
// worlds
if (a === "Worlds") return 1;
if (b === "Worlds") return -1;
// avatars
if (a === "Avatars") return 1;
if (b === "Avatars") return -1;
assertNever(a, "project type");
}
function ProjectsTableCard({
projects,
search,
onRemoved,
loading,
refresh,
openUnity,
}: {
projects: TauriProject[];
openUnity: OpenUnityFunction;
search?: string;
loading?: boolean;
onRemoved?: () => void;
refresh?: () => void;
}) {
const [sorting, setSortingState] = useState<Sorting>("lastModified");
useEffect(() => {
(async () => {
let newSorting = await commands.environmentGetProjectSorting();
if (newSorting === null) newSorting = "lastModified";
if (!isSorting(newSorting)) {
setSortingState("lastModified");
} else {
setSortingState(newSorting);
}
})();
}, []);
const projectsShown = useMemo(() => {
const searched = projects.filter((project) =>
project.name.toLowerCase().includes(search?.toLowerCase() ?? ""),
);
searched.sort((a, b) => b.last_modified - a.last_modified);
switch (sorting) {
case "lastModified":
// already sorted
break;
case "lastModifiedReversed":
searched.sort((a, b) => a.last_modified - b.last_modified);
break;
case "name":
searched.sort((a, b) => a.name.localeCompare(b.name));
break;
case "nameReversed":
searched.sort((a, b) => b.name.localeCompare(a.name));
break;
case "type":
searched.sort((a, b) =>
compareProjectType(a.project_type, b.project_type),
);
break;
case "typeReversed":
searched.sort((a, b) =>
compareProjectType(b.project_type, a.project_type),
);
break;
case "unity":
searched.sort((a, b) => compareUnityVersionString(a.unity, b.unity));
break;
case "unityReversed":
searched.sort((a, b) => compareUnityVersionString(b.unity, a.unity));
break;
default:
assertNever(sorting);
}
searched.sort((a, b) => {
if (a.favorite && !b.favorite) return -1;
if (!a.favorite && b.favorite) return 1;
return 0;
});
return searched;
}, [projects, sorting, search]);
const thClass = "sticky top-0 z-10 border-b border-primary p-2.5";
const iconClass = "size-3 invisible project-table-header-chevron-up-down";
const setSorting = async (simpleSorting: SimpleSorting) => {
let newSorting: Sorting;
if (sorting === simpleSorting) {
newSorting = `${simpleSorting}Reversed`;
} else if (sorting === `${simpleSorting}Reversed`) {
newSorting = simpleSorting;
} else {
newSorting = simpleSorting;
}
setSortingState(newSorting);
try {
await commands.environmentSetProjectSorting(newSorting);
} catch (e) {
console.error("Error setting project sorting", e);
toastThrownError(e);
}
};
const headerBg = (target: SimpleSorting) =>
sorting === target || sorting === `${target}Reversed`
? "bg-primary text-primary-foreground"
: "bg-secondary text-secondary-foreground";
const icon = (target: SimpleSorting) =>
sorting === target ? (
<ChevronDown className={"size-3"} />
) : sorting === `${target}Reversed` ? (
<ChevronUp className={"size-3"} />
) : (
<ChevronsUpDown className={iconClass} />
);
return (
<ScrollableCardTable>
<thead>
<tr>
<th className={`${thClass} bg-secondary text-secondary-foreground`}>
<Star className={"size-4"} />
</th>
<th className={`${thClass} ${headerBg("name")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("name")}
>
{icon("name")}
<small className="font-normal leading-none">
{tc("general:name")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("type")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("type")}
>
{icon("type")}
<small className="font-normal leading-none">
{tc("projects:type")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("unity")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("unity")}
>
{icon("unity")}
<small className="font-normal leading-none">
{tc("projects:unity")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("lastModified")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("lastModified")}
>
{icon("lastModified")}
<small className="font-normal leading-none">
{tc("projects:last modified")}
</small>
</button>
</th>
<th className={`${thClass} bg-secondary text-secondary-foreground`} />
</tr>
</thead>
<tbody>
{projectsShown.map((project) => (
<ProjectRow
key={project.index}
project={project}
loading={loading}
refresh={refresh}
onRemoved={onRemoved}
openUnity={openUnity}
/>
))}
</tbody>
</ScrollableCardTable>
);
}
function ProjectViewHeader({
className,
refresh,
startCreateProject,
isLoading,
search,
setSearch,
}: {
className?: string;
refresh?: () => void;
startCreateProject?: () => void;
isLoading?: boolean;
search: string;
setSearch: (search: string) => void;
}) {
const [addProjectWithPicker, dialog] = useFilePickerFunction(
commands.environmentAddProjectWithPicker,
);
const addProject = async () => {
try {
const result = await addProjectWithPicker();
switch (result) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tt("projects:toast:project added"));
refresh?.();
break;
case "AlreadyAdded":
toastError(tt("projects:toast:project already exists"));
break;
default:
assertNever(result);
}
} catch (e) {
console.error("Error adding project", e);
toastThrownError(e);
}
};
const searchRef = useRef<HTMLInputElement>(null);
useDocumentEvent(
"keydown",
(e) => {
if (isFindKey(e)) {
searchRef.current?.focus();
}
},
[],
);
return (
<HNavBar className={`${className}`}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0">
{tc("projects")}
</p>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={"ghost"}
size={"icon"}
onClick={() => refresh?.()}
disabled={isLoading}
>
{isLoading ? (
<RefreshCw className="w-5 h-5 animate-spin" />
) : (
<RefreshCw className={"w-5 h-5"} />
)}
</Button>
</TooltipTrigger>
<TooltipContent>{tc("projects:tooltip:refresh")}</TooltipContent>
</Tooltip>
<SearchBox
className={"w-max flex-grow"}
value={search}
onChange={(e) => setSearch(e.target.value)}
ref={searchRef}
/>
<DropdownMenu>
<div className={"flex divide-x"}>
<Button
className={"rounded-r-none pl-4 pr-3"}
onClick={startCreateProject}
>
{tc("projects:create new project")}
</Button>
<DropdownMenuTrigger asChild className={"rounded-l-none pl-2 pr-2"}>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuItem onClick={addProject}>
{tc("projects:add existing project")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{dialog}
</HNavBar>
);
}

View file

@ -1,548 +0,0 @@
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipPortal,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useBackupProjectModal } from "@/lib/backup-project";
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc, tt } from "@/lib/i18n";
import { useRemoveProjectModal } from "@/lib/remove-project";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import type { OpenUnityFunction } from "@/lib/use-open-unity";
import {
CircleHelp,
CircleUserRound,
Ellipsis,
Globe,
Star,
} from "lucide-react";
import { useRouter } from "next/navigation";
import React, {
type ComponentProps,
forwardRef,
useContext,
useState,
} from "react";
const ProjectDisplayType: Record<
TauriProjectType,
"avatars" | "worlds" | "sdk2" | "unknown"
> = {
Unknown: "unknown",
LegacySdk2: "sdk2",
LegacyWorlds: "worlds",
LegacyAvatars: "avatars",
UpmWorlds: "worlds",
UpmAvatars: "avatars",
UpmStarter: "unknown",
Worlds: "worlds",
Avatars: "avatars",
VpmStarter: "unknown",
};
const LegacyProjectTypes = [
"LegacySdk2",
"LegacyWorlds",
"LegacyAvatars",
"UpmWorlds",
"UpmAvatars",
"UpmStarter",
];
export function ProjectRow({
project,
openUnity,
onRemoved,
loading,
refresh,
}: {
project: TauriProject;
openUnity: OpenUnityFunction;
onRemoved?: () => void;
loading?: boolean;
refresh?: () => void;
}) {
const removeProjectModal = useRemoveProjectModal({ onRemoved });
const backupProjectModal = useBackupProjectModal();
const cellClass = "p-2.5";
const noGrowCellClass = `${cellClass} w-1`;
const typeIconClass = "w-5 h-5";
const projectTypeKind = ProjectDisplayType[project.project_type] ?? "unknown";
const displayType = tc(`projects:type:${projectTypeKind}`);
const isLegacy = LegacyProjectTypes.includes(project.project_type);
const lastModified = new Date(project.last_modified);
const lastModifiedHumanReadable = `${lastModified.getFullYear().toString().padStart(4, "0")}-${(lastModified.getMonth() + 1).toString().padStart(2, "0")}-${lastModified.getDate().toString().padStart(2, "0")} ${lastModified.getHours().toString().padStart(2, "0")}:${lastModified.getMinutes().toString().padStart(2, "0")}:${lastModified.getSeconds().toString().padStart(2, "0")}`;
const openProjectFolder = () =>
commands.utilOpen(project.path, "ErrorIfNotExists");
const onToggleFavorite = async () => {
try {
await commands.environmentSetFavoriteProject(
project.list_version,
project.index,
!project.favorite,
);
refresh?.();
} catch (e) {
console.error("Error migrating project", e);
toastThrownError(e);
}
};
const removed = !project.is_exists;
return (
<ProjectRowContext.Provider value={{ removed, loading: Boolean(loading) }}>
<tr
className={`even:bg-secondary/30 ${removed || loading ? "opacity-50" : ""}`}
>
<td className={`${cellClass} w-3`}>
<div className={"relative inline-flex"}>
<Checkbox
checked={project.favorite}
onCheckedChange={onToggleFavorite}
disabled={removed || loading}
className="hover:before:content-none before:transition-none border-none !text-primary peer"
/>
<span
className={
"text-background opacity-0 peer-data-[state=checked]:opacity-100 pointer-events-none absolute top-2/4 left-2/4 -translate-y-2/4 -translate-x-2/4"
}
>
<Star strokeWidth={3} className={"size-3"} />
</span>
</div>
</td>
<td className={`${cellClass} max-w-64 overflow-hidden`}>
<Tooltip>
<TooltipTriggerIfRemoved
className={"text-left select-text cursor-auto w-full"}
>
<div className="flex flex-col">
<Tooltip>
<TooltipTriggerIfExists
className={"text-left select-text cursor-auto w-full"}
>
<p className="font-normal whitespace-pre">{project.name}</p>
</TooltipTriggerIfExists>
<TooltipContent>{project.name}</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTriggerIfExists
className={"text-left select-text cursor-auto w-full"}
>
<p className="font-normal opacity-50 text-sm whitespace-pre">
{project.path}
</p>
</TooltipTriggerIfExists>
<TooltipContent>{project.path}</TooltipContent>
</Tooltip>
</div>
</TooltipTriggerIfRemoved>
<TooltipPortal>
<TooltipContent>
{tc("projects:tooltip:no directory")}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</td>
<td className={`${cellClass} w-[8em] min-w-[8em]`}>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{projectTypeKind === "avatars" ? (
<CircleUserRound className={typeIconClass} />
) : projectTypeKind === "worlds" ? (
<Globe className={typeIconClass} />
) : (
<CircleHelp className={typeIconClass} />
)}
</div>
<div className="flex flex-col justify-center">
<p className="font-normal">{displayType}</p>
{isLegacy && (
<p className="font-normal opacity-50 dark:opacity-80 text-sm text-destructive">
{tc("projects:type:legacy")}
</p>
)}
</div>
</div>
</td>
<td className={noGrowCellClass}>
<p className="font-normal">{project.unity}</p>
</td>
<td className={noGrowCellClass}>
<Tooltip>
<TooltipTrigger>
<time dateTime={lastModified.toISOString()}>
<time className="font-normal">
{formatDateOffset(project.last_modified)}
</time>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>{lastModifiedHumanReadable}</TooltipContent>
</TooltipPortal>
</Tooltip>
</td>
<td className={noGrowCellClass}>
<div className="flex flex-row gap-2 max-w-min">
<ButtonDisabledIfRemoved
onClick={() =>
openUnity(project.path, project.unity, project.unity_revision)
}
>
{tc("projects:button:open unity")}
</ButtonDisabledIfRemoved>
<ManageOrMigrateButton project={project} refresh={refresh} />
<ButtonDisabledIfRemoved
onClick={() => backupProjectModal.startBackup(project)}
variant={"success"}
>
{tc("projects:backup")}
</ButtonDisabledIfRemoved>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size={"icon"}
className={
"hover:bg-primary/10 text-primary hover:text-primary"
}
>
<Ellipsis className={"size-5"} />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={openProjectFolder}
disabled={removed || loading}
>
{tc("projects:menuitem:open directory")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => removeProjectModal.startRemove(project)}
disabled={loading}
className={"text-destructive focus:text-destructive"}
>
{tc("projects:remove project")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
{removeProjectModal.dialog}
{backupProjectModal.dialog}
</td>
</tr>
</ProjectRowContext.Provider>
);
}
function ManageOrMigrateButton({
project,
refresh,
}: {
project: TauriProject;
refresh?: () => void;
}) {
const router = useRouter();
switch (project.project_type) {
case "LegacySdk2":
return (
<Tooltip>
<TooltipTriggerIfExists asChild>
<ButtonDisabledIfRemoved variant="success" disabled>
{tc("projects:button:migrate")}
</ButtonDisabledIfRemoved>
</TooltipTriggerIfExists>
<TooltipContent>
{tc("projects:tooltip:sdk2 migration hint")}
</TooltipContent>
</Tooltip>
);
case "LegacyWorlds":
case "LegacyAvatars":
return <MigrateButton project={project} refresh={refresh} />;
case "UpmWorlds":
case "UpmAvatars":
case "UpmStarter":
return (
<Tooltip>
<TooltipTriggerIfExists asChild>
<ButtonDisabledIfRemoved variant="info" disabled>
{tc("projects:button:manage")}
</ButtonDisabledIfRemoved>
</TooltipTriggerIfExists>
<TooltipContent>
{tc("projects:tooltip:git-vcc not supported")}
</TooltipContent>
</Tooltip>
);
case "Unknown":
case "Worlds":
case "Avatars":
case "VpmStarter":
return (
<ButtonDisabledIfRemoved
onClick={() =>
router.push(
`/projects/manage?${new URLSearchParams({ projectPath: project.path })}`,
)
}
variant="info"
>
{tc("projects:button:manage")}
</ButtonDisabledIfRemoved>
);
}
}
function MigrateButton({
project,
refresh,
}: {
project: TauriProject;
refresh?: () => void;
}) {
type MigrateState =
| {
type: "normal";
}
| {
type: "migrateVpm:confirm";
}
| {
type: "migrateVpm:copyingProject";
}
| {
type: "migrateVpm:updating";
};
const [dialogStatus, setDialogStatus] = useState<MigrateState>({
type: "normal",
});
const startMigrateVpm = async () => {
if (await commands.projectIsUnityLaunching(project.path)) {
toastError(tt("projects:toast:close unity before migration"));
return;
}
setDialogStatus({ type: "migrateVpm:confirm" });
};
const doMigrateVpm = async (inPlace: boolean) => {
setDialogStatus({ type: "normal" });
try {
let migrateProjectPath: string;
if (inPlace) {
migrateProjectPath = project.path;
} else {
// copy
setDialogStatus({ type: "migrateVpm:copyingProject" });
migrateProjectPath = await commands.environmentCopyProjectForMigration(
project.path,
);
}
setDialogStatus({ type: "migrateVpm:updating" });
await commands.projectMigrateProjectToVpm(migrateProjectPath);
setDialogStatus({ type: "normal" });
toastSuccess(tt("projects:toast:project migrated"));
refresh?.();
} catch (e) {
console.error("Error migrating project", e);
setDialogStatus({ type: "normal" });
toastThrownError(e);
}
};
let dialogContent: React.ReactNode = null;
switch (dialogStatus.type) {
case "migrateVpm:confirm":
dialogContent = (
<DialogOpen className={"whitespace-normal"}>
<DialogTitle>{tc("projects:dialog:vpm migrate header")}</DialogTitle>
<DialogDescription>
<p className={"text-destructive"}>
{tc("projects:dialog:vpm migrate description")}
</p>
</DialogDescription>
<DialogFooter>
<Button
onClick={() => setDialogStatus({ type: "normal" })}
className="mr-1"
>
{tc("general:button:cancel")}
</Button>
<Button
onClick={() => doMigrateVpm(false)}
variant={"destructive"}
className="mr-1"
>
{tc("projects:button:migrate copy")}
</Button>
<Button onClick={() => doMigrateVpm(true)} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</DialogOpen>
);
break;
case "migrateVpm:copyingProject":
dialogContent = (
<DialogOpen className={"whitespace-normal"}>
<DialogTitle>{tc("projects:dialog:vpm migrate header")}</DialogTitle>
<DialogDescription>
<p>{tc("projects:pre-migrate copying...")}</p>
</DialogDescription>
</DialogOpen>
);
break;
case "migrateVpm:updating":
dialogContent = (
<DialogOpen className={"whitespace-normal"}>
<DialogTitle>{tc("projects:dialog:vpm migrate header")}</DialogTitle>
<DialogDescription>
<p>{tc("projects:migrating...")}</p>
</DialogDescription>
</DialogOpen>
);
break;
}
return (
<>
<ButtonDisabledIfRemoved variant={"success"} onClick={startMigrateVpm}>
{tc("projects:button:migrate")}
</ButtonDisabledIfRemoved>
{dialogContent}
</>
);
}
// region utilities
const ProjectRowContext = React.createContext<{
removed: boolean;
loading: boolean;
}>({
removed: false,
loading: false,
});
const ButtonDisabledIfRemoved = forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(function RemovedButton(props, ref) {
const rowContext = useContext(ProjectRowContext);
if (rowContext.removed) {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button
{...props}
className={`disabled:pointer-events-auto ${props.className}`}
disabled
ref={ref}
/>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>{tt("projects:tooltip:no directory")}</TooltipContent>
</TooltipPortal>
</Tooltip>
);
} else {
return (
<Button
{...props}
className={`disabled:pointer-events-auto ${props.className}`}
disabled={props.disabled || rowContext.loading || rowContext.removed}
ref={ref}
/>
);
}
});
const TooltipTriggerIfRemoved = ({
children,
...props
}: ComponentProps<typeof TooltipTrigger>) => {
const rowContext = useContext(ProjectRowContext);
if (rowContext.removed) {
return <TooltipTrigger {...props}>{children}</TooltipTrigger>;
} else {
return children;
}
};
const TooltipTriggerIfExists = ({
children,
...props
}: ComponentProps<typeof TooltipTrigger>) => {
const rowContext = useContext(ProjectRowContext);
if (rowContext.removed) {
return children;
} else {
return <TooltipTrigger {...props}>{children}</TooltipTrigger>;
}
};
function formatDateOffset(date: number): React.ReactNode {
const now = Date.now();
const diff = now - date;
const PER_SECOND = 1000;
const PER_MINUTE = 60 * PER_SECOND;
const PER_HOUR = 60 * PER_MINUTE;
const PER_DAY = 24 * PER_HOUR;
const PER_WEEK = 7 * PER_DAY;
const PER_MONTH = 30 * PER_DAY;
const PER_YEAR = 365 * PER_DAY;
const diffAbs = Math.abs(diff);
if (diffAbs < PER_MINUTE) return tc("projects:last modified:moments");
if (diffAbs < PER_HOUR)
return tc("projects:last modified:minutes", {
count: Math.floor(diff / PER_MINUTE),
});
if (diffAbs < PER_DAY)
return tc("projects:last modified:hours", {
count: Math.floor(diff / PER_HOUR),
});
if (diffAbs < PER_WEEK)
return tc("projects:last modified:days", {
count: Math.floor(diff / PER_DAY),
});
if (diffAbs < PER_MONTH)
return tc("projects:last modified:weeks", {
count: Math.floor(diff / PER_WEEK),
});
if (diffAbs < PER_YEAR)
return tc("projects:last modified:months", {
count: Math.floor(diff / PER_MONTH),
});
return tc("projects:last modified:years", {
count: Math.floor(diff / PER_YEAR),
});
}
// endregion

View file

@ -1,8 +0,0 @@
import { loadLicenses } from "@/lib/licenses";
import RenderPage from "./render-client";
const licenses = await loadLicenses();
export default function Page() {
return <RenderPage licenses={licenses} />;
}

View file

@ -1,618 +0,0 @@
"use client";
import { CheckForUpdateMessage } from "@/components/CheckForUpdateMessage";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import {
BackupFormatSelect,
BackupPathWarnings,
FilePathRow,
LanguageSelector,
ProjectPathWarnings,
ThemeSelector,
} from "@/components/common-setting-parts";
import { HNavBar, VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
UnityArgumentsSettings,
useUnityArgumentsSettings,
} from "@/components/unity-arguments-settings";
import { assertNever } from "@/lib/assert-never";
import type {
CheckForUpdateResponse,
TauriEnvironmentSettings,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import globalInfo, { useGlobalInfo } from "@/lib/global-info";
import { tc, tt } from "@/lib/i18n";
import {
toastError,
toastNormal,
toastSuccess,
toastThrownError,
} from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import type React from "react";
import { useState } from "react";
export default function Page() {
const result = useQuery({
queryKey: ["environmentGetSettings"],
queryFn: commands.environmentGetSettings,
});
let body: React.ReactNode;
switch (result.status) {
case "error":
body = <Card className={"p-4"}>{tc("settings:error:load error")}</Card>;
break;
case "pending":
body = <Card className={"p-4"}>{tc("general:loading...")}</Card>;
break;
case "success":
body = <Settings settings={result.data} refetch={result.refetch} />;
break;
default:
assertNever(result);
}
return (
<VStack>
<HNavBar className={"flex-shrink-0"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0">
{tc("settings")}
</p>
</HNavBar>
{body}
</VStack>
);
}
function Settings({
settings,
refetch,
}: {
settings: TauriEnvironmentSettings;
refetch: () => void;
}) {
const isMac = useGlobalInfo().osType === "Darwin";
return (
<ScrollPageContainer>
<main className="flex flex-col gap-2 flex-shrink flex-grow">
<Card className={"flex-shrink-0 p-4"}>
<h2 className={"pb-2"}>{tc("settings:unity hub path")}</h2>
<FilePathRow
withoutSelect
path={settings.unity_hub}
pick={commands.environmentPickUnityHub}
refetch={refetch}
notFoundMessage={"Unity Hub Not Found"}
successMessage={tc("settings:toast:unity hub path updated")}
/>
</Card>
<UnityInstallationsCard
refetch={refetch}
unityPaths={settings.unity_paths}
/>
<UnityLaunchArgumentsCard
refetch={refetch}
unityArgs={settings.default_unity_arguments}
/>
<Card className={"flex-shrink-0 p-4"}>
<h2>{tc("settings:default project path")}</h2>
<p className={"whitespace-normal"}>
{tc("settings:default project path description")}
</p>
<FilePathRow
path={settings.default_project_path}
pick={commands.environmentPickProjectDefaultPath}
refetch={refetch}
successMessage={tc("settings:toast:default project path updated")}
/>
<ProjectPathWarnings projectPath={settings.default_project_path} />
</Card>
<BackupCard
projectBackupPath={settings.project_backup_path}
backupFormat={settings.backup_format}
refetch={refetch}
/>
<PackagesCard
showPrereleasePackages={settings.show_prerelease_packages}
refetch={refetch}
/>
<AppearanceCard />
<AlcomCard
isMac={isMac}
releaseChannel={settings.release_channel}
useAlcomForVccProtocol={settings.use_alcom_for_vcc_protocol}
refetch={refetch}
/>
<SystemInformationCard />
</main>
</ScrollPageContainer>
);
}
function UnityInstallationsCard({
refetch,
unityPaths,
}: {
refetch: () => void;
unityPaths: [path: string, version: string, fromHub: boolean][];
}) {
const [pickUnity, unityDialog] = useFilePickerFunction(
commands.environmentPickUnity,
);
const addUnity = async () => {
try {
const result = await pickUnity();
switch (result) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("settings:toast:not unity"));
break;
case "AlreadyAdded":
toastError(tt("settings:toast:unity already added"));
break;
case "Successful":
toastSuccess(tt("settings:toast:unity added"));
refetch();
break;
default:
assertNever(result);
}
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const UNITY_TABLE_HEAD = [
"settings:unity:version",
"settings:unity:path",
"general:source",
];
return (
<Card className={"flex-shrink-0 p-4"}>
<div className={"pb-2 flex align-middle"}>
<div className={"flex-grow flex items-center"}>
<h2>{tc("settings:unity installations")}</h2>
</div>
<Button onClick={addUnity} size={"sm"} className={"m-1"}>
{tc("settings:button:add unity")}
</Button>
</div>
<ScrollableCardTable className="w-full min-h-[20vh]">
<thead>
<tr>
{UNITY_TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
</tr>
</thead>
<tbody>
{unityPaths.map(([path, version, isFromHub]) => (
<tr key={path} className="even:bg-secondary/30">
<td className={"p-2.5"}>{version}</td>
<td className={"p-2.5"}>{path}</td>
<td className={"p-2.5"}>
{isFromHub
? tc("settings:unity:source:unity hub")
: tc("settings:unity:source:manual")}
</td>
</tr>
))}
</tbody>
</ScrollableCardTable>
{unityDialog}
</Card>
);
}
function UnityLaunchArgumentsCard({
refetch,
unityArgs,
}: {
refetch: () => void;
unityArgs: string[] | null;
}) {
const [open, setOpen] = useState(false);
const defaultUnityArgs = useGlobalInfo().defaultUnityArguments;
const realUnityArgs = unityArgs ?? defaultUnityArgs;
const close = () => setOpen(false);
const openDialog = () => setOpen(true);
return (
<Card className={"flex-shrink-0 p-4"}>
<div className={"pb-2 flex align-middle"}>
<div className={"flex-grow flex items-center"}>
<h2>{tc("settings:default unity arguments")}</h2>
</div>
<Button onClick={openDialog} size={"sm"} className={"m-1"}>
{tc("general:button:edit")}
</Button>
</div>
<p className={"text-sm"}>
{tc("settings:default unity arguments description")}
</p>
<ol className={"flex flex-col"}>
{realUnityArgs.map((v, i) => (
<Input disabled key={i + v} value={v} className={"w-full"} />
))}
</ol>
{open && (
<DialogOpen>
<LaunchArgumentsEditDialogBody
unityArgs={unityArgs}
refetch={refetch}
close={close}
/>
</DialogOpen>
)}
</Card>
);
}
function LaunchArgumentsEditDialogBody({
unityArgs,
refetch,
close,
}: {
unityArgs: string[] | null;
refetch: () => void;
close: () => void;
}) {
const context = useUnityArgumentsSettings(
unityArgs,
globalInfo.defaultUnityArguments,
);
const saveAndClose = async () => {
await commands.environmentSetDefaultUnityArguments(context.currentValue);
close();
refetch();
};
return (
<>
<DialogTitle>
{tc("settings:dialog:default launch arguments")}
</DialogTitle>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"max-h-[50dvh] overflow-y-auto"}>
<UnityArgumentsSettings context={context} />
</DialogDescription>
<DialogFooter>
<Button onClick={close} variant={"destructive"}>
{tc("general:button:cancel")}
</Button>
<Button onClick={saveAndClose} disabled={context.hasError}>
{tc("general:button:save")}
</Button>
</DialogFooter>
</>
);
}
function BackupCard({
projectBackupPath,
backupFormat,
refetch,
}: {
projectBackupPath: string;
backupFormat: string;
refetch: () => void;
}) {
const setBackupFormat = async (format: string) => {
try {
await commands.environmentSetBackupFormat(format);
refetch();
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
return (
<Card className={"flex-shrink-0 p-4"}>
<h2>{tc("projects:backup")}</h2>
<div className="mt-2">
<h3>{tc("settings:backup:path")}</h3>
<p className={"whitespace-normal text-sm"}>
{tc("settings:backup:path description")}
</p>
<FilePathRow
path={projectBackupPath}
pick={commands.environmentPickProjectBackupPath}
refetch={refetch}
successMessage={tc("settings:toast:backup path updated")}
/>
<BackupPathWarnings backupPath={projectBackupPath} />
</div>
<div className="mt-2">
<h3>{tc("settings:backup:format")}</h3>
<p className={"whitespace-normal text-sm"}>
{tc("settings:backup:format description")}
</p>
<label className={"flex items-center"}>
<BackupFormatSelect
backupFormat={backupFormat}
setBackupFormat={setBackupFormat}
/>
</label>
</div>
</Card>
);
}
function PackagesCard({
showPrereleasePackages,
refetch,
}: {
showPrereleasePackages: boolean;
refetch: () => void;
}) {
const clearPackageCache = async () => {
try {
await commands.environmentClearPackageCache();
toastSuccess(tc("settings:toast:package cache cleared"));
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const toggleShowPrereleasePackages = async (e: "indeterminate" | boolean) => {
try {
await commands.environmentSetShowPrereleasePackages(e === true);
refetch();
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
return (
<Card className={"flex-shrink-0 p-4 flex flex-col gap-4"}>
<h2>{tc("settings:packages")}</h2>
<div className={"flex flex-row flex-wrap gap-2"}>
<Button onClick={clearPackageCache}>
{tc("settings:clear package cache")}
</Button>
</div>
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={showPrereleasePackages}
onCheckedChange={(e) => toggleShowPrereleasePackages(e)}
/>
{tc("settings:show prerelease")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:show prerelease description")}
</p>
</div>
</Card>
);
}
function AppearanceCard() {
return (
<Card className={"flex-shrink-0 p-4"}>
<h2>{tc("settings:appearance")}</h2>
<LanguageSelector />
<ThemeSelector />
</Card>
);
}
function AlcomCard({
isMac,
releaseChannel,
useAlcomForVccProtocol,
refetch,
}: {
isMac: boolean;
releaseChannel: string;
useAlcomForVccProtocol: boolean;
refetch: () => void;
}) {
const [updateState, setUpdateState] = useState<CheckForUpdateResponse | null>(
null,
);
const globalInfo = useGlobalInfo();
const checkForUpdate = async () => {
try {
const checkVersion = await commands.utilCheckForUpdate();
if (checkVersion) {
setUpdateState(checkVersion);
} else {
toastNormal(tc("check update:toast:no updates"));
}
} catch (e) {
toastThrownError(e);
console.error(e);
}
};
const reportIssue = async () => {
const url = new URL("https://github.com/vrc-get/vrc-get/issues/new");
url.searchParams.append("labels", "bug,vrc-get-gui");
url.searchParams.append("template", "01_gui_bug-report.yml");
url.searchParams.append("os", `${globalInfo.osInfo} - ${globalInfo.arch}`);
url.searchParams.append("webview-version", `${globalInfo.webviewVersion}`);
let version = globalInfo.version ?? "unknown";
if (globalInfo.commitHash) {
version += ` (${globalInfo.commitHash})`;
} else {
version += " (unknown commit)";
}
url.searchParams.append("version", version);
void commands.utilOpenUrl(url.toString());
};
const changeReleaseChannel = async (value: "indeterminate" | boolean) => {
await commands.environmentSetReleaseChannel(
value === true ? "beta" : "stable",
);
refetch();
};
const changeUseAlcomForVcc = async (value: "indeterminate" | boolean) => {
await commands.environmentSetUseAlcomForVccProtocol(value === true);
refetch();
};
const installVccProtocol = async () => {
try {
await commands.deepLinkInstallVcc();
toastSuccess(tc("settings:toast:vcc scheme installed"));
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const openVpmFolderContent = (subPath: string) => {
return async () => {
try {
await commands.utilOpen(
`${globalInfo.vpmHomeFolder}/${subPath}`,
"ErrorIfNotExists",
);
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
};
return (
<Card className={"flex-shrink-0 p-4 flex flex-col gap-4"}>
{updateState && (
<CheckForUpdateMessage
response={updateState}
close={() => setUpdateState(null)}
/>
)}
<h2>ALCOM</h2>
<div className={"flex flex-row flex-wrap gap-2"}>
<Button onClick={checkForUpdate}>{tc("settings:check update")}</Button>
<Button onClick={reportIssue}>
{tc("settings:button:open issue")}
</Button>
</div>
<div className={"flex flex-row flex-wrap gap-2"}>
<Button onClick={openVpmFolderContent("settings.json")}>
{tc("settings:button:open settings.json")}
</Button>
<Button onClick={openVpmFolderContent("vrc-get/gui-config.json")}>
{tc("settings:button:open gui config.json")}
</Button>
<Button onClick={openVpmFolderContent("vrc-get/gui-logs")}>
{tc("settings:button:open logs")}
</Button>
<Button onClick={openVpmFolderContent("Templates")}>
{tc("settings:button:open custom templates")}
</Button>
</div>
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={releaseChannel === "beta"}
onCheckedChange={(e) => changeReleaseChannel(e)}
/>
{tc("settings:receive beta updates")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:beta updates description")}
</p>
</div>
{!isMac && (
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={useAlcomForVccProtocol}
onCheckedChange={(e) => changeUseAlcomForVcc(e)}
/>
{tc("settings:use alcom for vcc scheme")}
</label>
<Button
className={"my-1"}
disabled={!useAlcomForVccProtocol}
onClick={installVccProtocol}
>
{tc("settings:register vcc scheme now")}
</Button>
<p className={"text-sm whitespace-normal"}>
{tc([
"settings:use vcc scheme description",
"settings:vcc scheme description",
])}
</p>
</div>
)}
<p className={"whitespace-normal"}>
{tc(
"settings:licenses description",
{},
{
components: {
l: <Link href={"/settings/licenses"} className={"underline"} />,
},
},
)}
</p>
</Card>
);
}
function SystemInformationCard() {
const info = useGlobalInfo();
return (
<Card className={"flex-shrink-0 p-4 flex flex-col gap-4"}>
<h2>{tc("settings:system information")}</h2>
<dl>
<dt>{tc("settings:os")}</dt>
<dd className={"ml-8 mb-1"}>{info.osInfo}</dd>
<dt>{tc("settings:architecture")}</dt>
<dd className={"ml-8 mb-1"}>{info.arch}</dd>
<dt>{tc("settings:webview version")}</dt>
<dd className={"ml-8 mb-1"}>{info.webviewVersion}</dd>
<dt>{tc("settings:alcom version")}</dt>
<dd className={"ml-8 mb-1"}>{info.version}</dd>
<dt>{tc("settings:alcom commit hash")}</dt>
<dd className={"ml-8 mb-1"}>{info.commitHash}</dd>
</dl>
</Card>
);
}

View file

@ -1,37 +0,0 @@
"use client";
import { useRouter } from "next/navigation";
export default function SetupLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const isDev = process.env.NODE_ENV === "development";
return (
<>
<div className={"h-screen flex-grow overflow-hidden flex p-4"}>
{children}
</div>
{isDev && <DevTools />}
</>
);
}
function DevTools() {
const router = useRouter();
return (
<div className={"absolute bottom-0 left-0 p-4 flex flex-col gap-3"}>
<p>debug tools</p>
<div className={"flex gap-3"}>
<button type="button" onClick={() => router.back()}>
Go Back
</button>
<button type="button" onClick={() => router.push("/settings")}>
Go Settings
</button>
</div>
</div>
);
}

View file

@ -1,68 +0,0 @@
"use client";
import {
BackupFormatSelect,
BackupPathWarnings,
FilePathRow,
} from "@/components/common-setting-parts";
import { CardDescription } from "@/components/ui/card";
import { commands } from "@/lib/bindings";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
import { type BodyProps, SetupPageBase } from "../setup-page-base";
export default function Page() {
const isMac = useGlobalInfo().osType === "Darwin";
return (
<SetupPageBase
heading={tc("setup:backups:heading")}
Body={Body}
nextPage={isMac ? "/setup/finish" : "/setup/system-setting"}
prevPage={"/setup/project-path"}
pageId={"Backups"}
/>
);
}
function Body({ environment, refetch }: BodyProps) {
const projectBackupPath = environment.project_backup_path;
const backupFormat = environment.backup_format;
const setBackupFormat = async (format: string) => {
try {
await commands.environmentSetBackupFormat(format);
refetch();
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
return (
<>
<h3>{tc("setup:backups:location")}</h3>
<CardDescription className={"whitespace-normal"}>
{tc("setup:backups:location description")}
</CardDescription>
<FilePathRow
withoutSelect
path={projectBackupPath}
pick={commands.environmentPickProjectBackupPath}
refetch={refetch}
successMessage={tc("settings:toast:backup path updated")}
/>
<BackupPathWarnings backupPath={projectBackupPath} />
<div className={"pb-3"} />
<h3>{tc("setup:backups:archive")}</h3>
<CardDescription className={"whitespace-normal"}>
{tc("settings:backup:format description")}
</CardDescription>
<BackupFormatSelect
backupFormat={backupFormat}
setBackupFormat={setBackupFormat}
/>
</>
);
}

View file

@ -1,40 +0,0 @@
"use client";
import {
FilePathRow,
ProjectPathWarnings,
} from "@/components/common-setting-parts";
import { CardDescription } from "@/components/ui/card";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { type BodyProps, SetupPageBase } from "../setup-page-base";
export default function Page() {
return (
<SetupPageBase
heading={tc("setup:project-path:heading")}
Body={Body}
nextPage={"/setup/backups"}
prevPage={"/setup/unity-hub"}
pageId={"ProjectPath"}
/>
);
}
function Body({ environment, refetch }: BodyProps) {
return (
<>
<CardDescription className={"whitespace-normal"}>
{tc("setup:project-path:description")}
</CardDescription>
<FilePathRow
withoutSelect
path={environment.default_project_path}
pick={commands.environmentPickProjectDefaultPath}
refetch={refetch}
successMessage={tc("settings:toast:default project path updated")}
/>
<ProjectPathWarnings projectPath={environment.default_project_path} />
</>
);
}

View file

@ -1,69 +0,0 @@
"use client";
import { Checkbox } from "@/components/ui/checkbox";
import { commands } from "@/lib/bindings";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { useQuery } from "@tanstack/react-query";
import { type BodyProps, SetupPageBase } from "../setup-page-base";
export default function Page() {
return (
<SetupPageBase
heading={tc("setup:system-setting:heading")}
Body={Body}
nextPage={"/setup/finish"}
prevPage={"/setup/backups"}
pageId={"SystemSetting"}
/>
);
}
function Body({ environment, refetch }: BodyProps) {
const useAlcomForVccProtocol = environment.use_alcom_for_vcc_protocol;
const isBadHostName = useQuery({
queryKey: ["util_is_bad_hostname"],
queryFn: commands.utilIsBadHostname,
initialData: false,
});
const changeUseAlcomForVcc = async (value: "indeterminate" | boolean) => {
await commands.environmentSetUseAlcomForVccProtocol(value === true);
refetch();
};
const isMac = useGlobalInfo().osType === "Darwin";
return (
<>
{!isMac ? (
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={useAlcomForVccProtocol}
onCheckedChange={(e) => changeUseAlcomForVcc(e)}
/>
{tc("settings:use alcom for vcc scheme")}
</label>
<p className={"text-sm whitespace-normal text-muted-foreground"}>
{tc("setup:system-setting:vcc scheme description")}
</p>
</div>
) : (
<div>
<p className={"text-sm whitespace-normal text-muted-foreground"}>
{tc("setup:system-setting:macos bug message")}
</p>
</div>
)}
{isBadHostName.data && (
<div className={"mt-3"}>
<p className={"text-sm whitespace-normal text-warning"}>
{tc("setup:system-setting:hostname-with-non-ascii")}
</p>
</div>
)}
</>
);
}

View file

@ -1,20 +1,25 @@
"use client"; // Error components must be Client Components
import { useEffect } from "react";
import { commands } from "@/lib/bindings";
import globalInfo from "@/lib/global-info";
import { useEffect } from "react";
export default function ErrorPage({
error,
}: {
error: Error;
reset: () => void;
error: object;
reset?: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
const errorMessage = `${error}`;
const errorStack = `${error.stack}`;
// When there is overridden toString, use it. if not, use stringify
const errorMessage =
error.toString === Object.prototype.toString
? JSON.stringify(error)
: error.toString();
const errorStack =
"stack" in error ? `${error.stack}` : "No stacktrace provided";
const openIssue = () => {
try {
@ -48,10 +53,10 @@ export default function ErrorPage({
<div className={"w-full flex items-center justify-center"}>
<div
className={
"rounded-xl border bg-card text-card-foreground shadow-sm min-w-[50vw] max-w-[100vw] p-4 flex gap-3"
"rounded-xl border bg-card text-card-foreground shadow-xs min-w-[50vw] max-w-[100vw] p-4 flex gap-3"
}
>
<div className={"flex flex-col flex-grow overflow-hidden"}>
<div className={"flex flex-col grow overflow-hidden"}>
<h2>Client-side unrecoverable error occurred</h2>
<p>This must be a bug! Please report this bug!</p>
<div>

View file

@ -0,0 +1,14 @@
import { LoaderCircle } from "lucide-react";
export default function Loading({
loadingText = "Loading...",
}: {
loadingText?: React.ReactNode;
}) {
return (
<div className="flex flex-col items-center justify-center h-full w-full space-y-4">
<LoaderCircle className="h-10 w-10 animate-spin" />
<p className="text-xl font-semibold text-gray-700">{loadingText}</p>
</div>
);
}

View file

@ -0,0 +1,34 @@
import { createRootRoute, Outlet } from "@tanstack/react-router";
import ErrorPage from "@/app/-error";
import { Providers } from "@/components/providers";
import "./globals.css";
import React, { Suspense } from "react";
const TanStackRouterDevtools = import.meta.env.PROD
? () => null // Render nothing in production
: React.lazy(() =>
// Lazy load in development
import("@tanstack/router-devtools").then((res) => ({
default: res.TanStackRouterDevtools,
// For Embedded Mode
// default: res.TanStackRouterDevtoolsPanel
})),
);
export const Route = createRootRoute({
component: RootComponent,
errorComponent: ErrorPage,
});
function RootComponent() {
return (
<>
<Providers>
<Outlet />
</Providers>
<Suspense>
<TanStackRouterDevtools position={"bottom-right"} />
</Suspense>
</>
);
}

View file

@ -1,8 +1,9 @@
"use client";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { createFileRoute } from "@tanstack/react-router";
import { HNavBar, HNavBarText, VStack } from "@/components/layout";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { HNavBar, VStack } from "@/components/layout";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
@ -16,19 +17,29 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { toastError, toastInfo, toastNormal, toastSuccess } from "@/lib/toast";
import { tc } from "@/lib/i18n";
import {
toastError,
toastInfo,
toastNormal,
toastSuccess,
toastWarning,
} from "@/lib/toast";
export default function Page() {
export const Route = createFileRoute("/_main/dev-palette/")({
component: Page,
});
function Page() {
return (
<VStack>
<HNavBar className={"flex-shrink-0"}>
<p className="cursor-pointer py-1.5 font-bold flex-grow-0">
UI Palette (dev only)
</p>
</HNavBar>
<HNavBar
className="shrink-0"
leading={<HNavBarText>UI Palette (dev only)</HNavBarText>}
/>
<ScrollPageContainer>
<main className="flex flex-col gap-2 flex-shrink flex-grow">
<Card className={"flex-shrink-0 p-4"}>
<main className="flex flex-col gap-2 shrink grow">
<Card className={"shrink-0 p-4"}>
<h2 className={"pb-2"}>File Selector</h2>
<div className={"flex gap-1 items-center"}>
<Input
@ -39,9 +50,9 @@ export default function Page() {
<Button className={"flex-none px-4"}>Select</Button>
</div>
</Card>
<Card className={"flex-shrink-0 p-4"}>
<Card className={"shrink-0 p-4"}>
<div className={"pb-2 flex align-middle"}>
<div className={"flex-grow flex items-center"}>
<div className={"grow flex items-center"}>
<h2>Table</h2>
</div>
<Button size={"sm"} className={"m-1"}>
@ -52,7 +63,7 @@ export default function Page() {
<UnityTableBody />
</ScrollableCardTable>
</Card>
<Card className={"flex-shrink-0 p-4"}>
<Card className={"shrink-0 p-4"}>
<h2>Dropdown Selector</h2>
<div className="mt-2">
<label className={"flex items-center"}>
@ -74,7 +85,7 @@ export default function Page() {
</label>
</div>
</Card>
<Card className={"flex-shrink-0 p-4"}>
<Card className={"shrink-0 p-4"}>
<p className={"whitespace-normal"}>Some Description Here</p>
<label className={"flex items-center"}>
<div className={"p-3"}>
@ -83,7 +94,7 @@ export default function Page() {
Checkbox
</label>
</Card>
<Card className={"flex-shrink-0 p-4"}>
<Card className={"shrink-0 p-4"}>
<h2 className={"pb-2"}>Buttons</h2>
<div className={"flex gap-2 items-center"}>
<Button>Normal</Button>
@ -96,7 +107,7 @@ export default function Page() {
<Button variant={"ghost-destructive"}>Ghost Destructive</Button>
</div>
</Card>
<Card className={"flex-shrink-0 p-4"}>
<Card className={"shrink-0 p-4"}>
<h2 className={"pb-2"}>Toasts</h2>
<div className={"flex gap-2 items-center"}>
<Button onClick={() => toastNormal("Normal Toast Body")}>
@ -108,6 +119,12 @@ export default function Page() {
>
Error
</Button>
<Button
variant={"warning"}
onClick={() => toastWarning("Warning Toast Body")}
>
Warning
</Button>
<Button
variant={"success"}
onClick={() => toastSuccess("Success Toast Body")}
@ -120,6 +137,14 @@ export default function Page() {
>
Info
</Button>
<Button
variant={"info"}
onClick={() =>
toastInfo(tc("settings:toast:vcc scheme installed"))
}
>
Info with html inside
</Button>
</div>
</Card>
</main>
@ -160,7 +185,7 @@ function UnityTableBody() {
</tr>
</thead>
<tbody>
{unityPaths.map(([path, version, isFromHub]) => (
{unityPaths.map(([path, version, _isFromHub]) => (
<tr key={path} className="even:bg-secondary/30">
<td className={"p-2.5"}>{version}</td>
<td className={"p-2.5"}>{path}</td>

View file

@ -0,0 +1,136 @@
import { BugOff, CircleX, Info, OctagonAlert } from "lucide-react";
import { memo, useEffect, useMemo, useRef } from "react";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import type { LogEntry, LogLevel } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
export const LogsListCard = memo(function LogsListCard({
logEntry,
shouldShowLogLevel,
search,
autoScroll,
}: {
logEntry: LogEntry[];
shouldShowLogLevel: LogLevel[];
search: string;
autoScroll: boolean;
}) {
const logsShown = useMemo(
() =>
logEntry.filter(
(log) =>
log.message.toLowerCase().includes(search?.toLowerCase() ?? "") &&
shouldShowLogLevel.includes(log.level),
),
[logEntry, search, shouldShowLogLevel],
);
const scrollContainerRef = useRef<HTMLDivElement>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: should scroll to the bottom whenever the logsShown changes.
useEffect(() => {
if (!autoScroll) return;
if (!scrollContainerRef.current) return;
const container = scrollContainerRef.current;
const isNearBottom =
container.scrollHeight - (container.scrollTop + container.clientHeight) <
50;
if (!isNearBottom) {
container.scrollTop = container.scrollHeight;
}
}, [logsShown, autoScroll]);
const TABLE_HEAD = ["logs:time", "logs:level", "logs:message"];
return (
<ScrollableCardTable
className={"h-full w-full"}
viewportRef={scrollContainerRef}
>
<thead className={"w-full"}>
<tr>
{TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
<th
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
/>
</tr>
</thead>
<tbody>
{logsShown.map((row) => (
<tr key={row.time} className="even:bg-secondary/30">
<LogRow log={row} />
</tr>
))}
</tbody>
</ScrollableCardTable>
);
});
const LogRow = memo(function LogRow({ log }: { log: LogEntry }) {
const cellClass = "p-2.5 compact:py-1";
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleString();
};
const getFontColorClass = (level: LogLevel) => {
switch (level) {
case "Info":
return "";
case "Warn":
return "text-warning";
case "Error":
return "text-destructive";
case "Debug":
return "text-info";
default:
return "";
}
};
const fontColorClass = getFontColorClass(log.level);
const typeIconClass = `${fontColorClass} w-5 h-5`;
return (
<>
<td className={`${cellClass} min-w-32 w-32`}>{formatDate(log.time)}</td>
<td className={`${cellClass} min-w-28 w-28`}>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{log.level === "Info" ? (
<Info className={typeIconClass} />
) : log.level === "Warn" ? (
<OctagonAlert className={typeIconClass} />
) : log.level === "Error" ? (
<CircleX className={typeIconClass} />
) : log.level === "Debug" ? (
<BugOff className={typeIconClass} />
) : (
<Info className={typeIconClass} />
)}
</div>
<div className="flex flex-col justify-center">
<p className={`font-normal ${fontColorClass}`}>{log.level}</p>
</div>
</div>
</td>
<td className={`${cellClass} min-w-32 w-full`}>{log.message}</td>
</>
);
});

View file

@ -0,0 +1,287 @@
"use client";
import {
queryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { ArrowDownFromLine } from "lucide-react";
import { useRef, useState } from "react";
import { HNavBar, HNavBarText, VStack } from "@/components/layout";
import { SearchBox } from "@/components/SearchBox";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { LogEntry, LogLevel } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { isFindKey, useDocumentEvent } from "@/lib/events";
import globalInfo from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
import { useTauriListen } from "@/lib/use-tauri-listen";
import { useSessionStorage } from "@/lib/useSessionStorage";
import { LogsListCard } from "./-logs-list-card";
export const Route = createFileRoute("/_main/log/")({
component: Page,
});
const utilGetLogEntries = queryOptions({
queryKey: ["utilGetLogEntries"],
queryFn: async () => commands.utilGetLogEntries(),
});
const environmentLogsLevel = queryOptions({
queryKey: ["environmentLogsLevel"],
queryFn: async () => commands.environmentLogsLevel(),
});
function Page() {
const [search, setSearch] = useState("");
const queryClient = useQueryClient();
const logEntriesQuery = useQuery(utilGetLogEntries);
const logsLevel = useQuery(environmentLogsLevel);
const handleLogLevelChange = useMutation({
mutationFn: async (value: LogLevel[]) =>
commands.environmentSetLogsLevel(value),
onMutate: async (value) => {
await queryClient.cancelQueries(environmentLogsLevel);
const data = queryClient.getQueryData(environmentLogsLevel.queryKey);
queryClient.setQueryData(environmentLogsLevel.queryKey, value);
return data;
},
onError: (e, _, data) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentLogsLevel.queryKey, data);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentLogsLevel);
},
});
const autoScroll = useSessionStorage({
key: "logs_auto_scroll",
parse: (value) => value === "true",
fallbackValue: true,
});
const handleLogAutoScrollChange = (value: boolean) => {
sessionStorage.setItem("logs_auto_scroll", String(value));
// Manually dispatch storage event to force state synchronization within the same page,
// as native sessionStorage.setItem doesn't trigger storage event for the current origin
window.dispatchEvent(
new StorageEvent("storage", {
key: "logs_auto_scroll",
newValue: String(value),
storageArea: sessionStorage,
}),
);
};
useTauriListen<LogEntry>("log", (event) => {
const entry = event.payload as LogEntry;
const entries = queryClient.getQueryData(utilGetLogEntries.queryKey) ?? [];
queryClient.setQueryData(utilGetLogEntries.queryKey, [...entries, entry]);
});
const shouldShowLogLevel = logsLevel.data ?? [];
return (
<VStack>
<ManageLogsHeading
search={search}
setSearch={setSearch}
shouldShowLogLevel={shouldShowLogLevel}
handleLogLevelChange={handleLogLevelChange.mutate}
handleLogAutoScrollChange={handleLogAutoScrollChange}
autoScroll={autoScroll}
/>
<main className="shrink overflow-hidden flex w-full h-full">
<LogsListCard
logEntry={logEntriesQuery.data ?? []}
search={search}
shouldShowLogLevel={shouldShowLogLevel}
autoScroll={autoScroll}
/>
</main>
</VStack>
);
}
function ManageLogsHeading({
search,
setSearch,
shouldShowLogLevel,
handleLogLevelChange,
handleLogAutoScrollChange,
autoScroll,
}: {
search: string;
setSearch: (value: string) => void;
shouldShowLogLevel: LogLevel[];
handleLogLevelChange: (newLogLevels: LogLevel[]) => void;
handleLogAutoScrollChange: (newAutoScroll: boolean) => void;
autoScroll: boolean;
}) {
const searchRef = useRef<HTMLInputElement>(null);
useDocumentEvent(
"keydown",
(e) => {
if (isFindKey(e)) {
searchRef.current?.focus();
}
},
[],
);
return (
<HNavBar
className="shrink-0"
leading={
<>
<HNavBarText>{tc("logs")}</HNavBarText>
<SearchBox
className={"w-max grow"}
value={search}
onChange={(e) => setSearch(e.target.value)}
ref={searchRef}
/>
</>
}
trailing={
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className={"shrink-0 p-3 compact:h-10"}>
{tc("logs:manage:select logs level")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<LogLevelMenuItem
logLevel="Info"
shouldShowLogLevel={shouldShowLogLevel}
handleLogLevelChange={handleLogLevelChange}
/>
<LogLevelMenuItem
logLevel="Warn"
className="text-warning"
shouldShowLogLevel={shouldShowLogLevel}
handleLogLevelChange={handleLogLevelChange}
/>
<LogLevelMenuItem
logLevel="Error"
className="text-destructive"
shouldShowLogLevel={shouldShowLogLevel}
handleLogLevelChange={handleLogLevelChange}
/>
<LogLevelMenuItem
logLevel="Debug"
className="text-info"
shouldShowLogLevel={shouldShowLogLevel}
handleLogLevelChange={handleLogLevelChange}
/>
{/* Currently no trace level logs will be passed to frontend */}
{/*<LogLevelMenuItem
logLevel="Trace"
shouldShowLogLevel={shouldShowLogLevel}
setShouldShowLogLevel={setShouldShowLogLevel}
/>*/}
</DropdownMenuContent>
</DropdownMenu>
<Button
className={"compact:h-10"}
onClick={() =>
commands.utilOpen(
`${globalInfo.vpmHomeFolder}/vrc-get/gui-logs`,
"ErrorIfNotExists",
)
}
>
{tc("settings:button:open logs")}
</Button>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={"ghost"}
onClick={() => handleLogAutoScrollChange(!autoScroll)}
className={`compact:h-10 ${
autoScroll
? "bg-secondary border border-primary"
: "bg-transparent"
}`}
>
<ArrowDownFromLine className={"w-5 h-5"} />
</Button>
</TooltipTrigger>
<TooltipContent>{tc("logs:manage:auto scroll")}</TooltipContent>
</Tooltip>
</>
}
/>
);
}
function LogLevelMenuItem({
logLevel,
className,
shouldShowLogLevel,
handleLogLevelChange,
}: {
logLevel: LogLevel;
className?: string;
shouldShowLogLevel: LogLevel[];
handleLogLevelChange: (newLogLevels: LogLevel[]) => void;
}) {
const selected = shouldShowLogLevel.includes(logLevel);
const onChange = () => {
const newLogLevels = selected
? shouldShowLogLevel.filter(
(logLevelFilter) => logLevelFilter !== logLevel,
)
: [...shouldShowLogLevel, logLevel];
handleLogLevelChange(newLogLevels);
};
return (
<DropdownMenuItem
className="p-0"
onSelect={(e) => {
e.preventDefault();
}}
>
<label
className={
"flex cursor-pointer items-center gap-2 p-2 whitespace-normal"
}
>
<Checkbox
checked={selected}
onCheckedChange={onChange}
className="hover:before:content-none"
/>
<p className={className}>{logLevel}</p>
</label>
</DropdownMenuItem>
);
}

View file

@ -0,0 +1,67 @@
import { Link } from "@tanstack/react-router";
import { tc } from "@/lib/i18n";
type PageType =
| "/packages/user-packages"
| "/packages/repositories"
| "/packages/templates";
// Note: For historical reasons, templates page are under packages in route.
export function HeadingPageName({ pageType }: { pageType: PageType }) {
// Note for p-1 rounded-md -m-1 compact:m-0
// For normal mode, we use 1-unit of the outer padding for selector rectangle, so we use negative margin to eat padding.
// For compact mode, the height of the button is 2 units shorter than normal with the height of the navbar is remaining.
// Therefore we use the 1 unit space for outer padding for selector rectangle.
return (
<div className={"flex compact:h-10 items-center"}>
<div
className={
"grid grid-cols-3 gap-1.5 bg-secondary p-1 rounded-md -m-1 compact:m-0"
}
>
<HeadingButton
currentPage={pageType}
targetPage={"/packages/repositories"}
>
{tc("packages:repositories")}
</HeadingButton>
<HeadingButton
currentPage={pageType}
targetPage={"/packages/user-packages"}
>
{tc("packages:user packages")}
</HeadingButton>
<HeadingButton
currentPage={pageType}
targetPage={"/packages/templates"}
>
{tc("packages:templates")}
</HeadingButton>
</div>
</div>
);
}
function HeadingButton({
currentPage,
targetPage,
children,
}: {
currentPage: PageType;
targetPage: PageType;
children: React.ReactNode;
}) {
const button =
"cursor-pointer px-3 py-2 font-bold grow-0 hover:bg-background rounded-sm text-center p-2 compact:h-8 compact:py-1";
if (currentPage === targetPage) {
return <div className={`${button} bg-background`}>{children}</div>;
} else {
return (
<Link to={targetPage} className={button}>
{children}
</Link>
);
}
}

View file

@ -1,166 +1,91 @@
import { queryOptions } from "@tanstack/react-query";
import type React from "react";
import { useState } from "react";
import {
ReorderableList,
useReorderableList,
} from "@/components/ReorderableList";
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogOpen,
DialogTitle,
} from "@/components/ui/dialog";
import { DialogFooter } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { assertNever } from "@/lib/assert-never";
import type { TauriRemoteRepositoryInfo } from "@/lib/bindings";
import type {
TauriDuplicatedReason,
TauriRemoteRepositoryInfo,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { type DialogApi, type DialogContext, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import type React from "react";
import { useCallback, useState } from "react";
import { queryClient } from "@/lib/query-client";
import { toastError, toastSuccess } from "@/lib/toast";
type State =
| {
type: "normal";
}
| {
type: "enteringRepositoryInfo";
}
| {
type: "loadingRepository";
}
| {
type: "duplicated";
}
| {
type: "confirming";
repo: TauriRemoteRepositoryInfo;
url: string;
headers: { [key: string]: string };
};
const environmentRepositoriesInfo = queryOptions({
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
});
interface AddRepository {
dialog: React.ReactNode;
openAddDialog: () => void;
addRepository: (
url: string,
headers: { [p: string]: string },
) => Promise<void>;
export async function openAddRepositoryDialog() {
using dialog = showDialog();
const repoInfo = await dialog.ask(EnteringRepositoryInfo, {});
if (repoInfo == null) return;
await addRepositoryImpl(dialog, repoInfo.url, repoInfo.headers);
}
export function useAddRepository({
refetch,
}: {
refetch: () => void;
}): AddRepository {
const [state, setState] = useState<State>({ type: "normal" });
function cancel() {
setState({ type: "normal" });
}
const openAddDialog = useCallback(() => {
setState({ type: "enteringRepositoryInfo" });
}, []);
const addRepository = useCallback(async function addRepository(
url: string,
headers: { [key: string]: string },
) {
try {
setState({ type: "loadingRepository" });
const info = await commands.environmentDownloadRepository(url, headers);
switch (info.type) {
case "BadUrl":
toastError(tt("vpm repositories:toast:invalid url"));
setState({ type: "normal" });
return;
case "DownloadError":
toastError(
tt("vpm repositories:toast:load failed", { message: info.message }),
);
setState({ type: "normal" });
return;
case "Duplicated":
setState({ type: "duplicated" });
return;
case "Success":
break;
default:
assertNever(info, "info");
}
setState({ type: "confirming", repo: info.value, url, headers });
} catch (e) {
toastThrownError(e);
setState({ type: "normal" });
}
}, []);
let dialogBody: React.ReactNode;
switch (state.type) {
case "normal":
dialogBody = null;
break;
case "enteringRepositoryInfo":
dialogBody = (
<EnteringRepositoryInfo
cancel={() => setState({ type: "normal" })}
addRepository={(url, headers) => addRepository(url, headers)}
/>
export async function addRepository(
url: string,
headers: Record<string, string>,
) {
using dialog = showDialog();
await addRepositoryImpl(dialog, url, headers);
}
async function addRepositoryImpl(
dialog: DialogApi,
url: string,
headers: Record<string, string>,
) {
dialog.replace(<LoadingRepository cancel={dialog.close} />);
const info = await commands.environmentDownloadRepository(url, headers);
switch (info.type) {
case "BadUrl":
toastError(tt("vpm repositories:toast:invalid url"));
return;
case "DownloadError":
toastError(
tt("vpm repositories:toast:load failed", {
message: info.message,
}),
);
return;
case "Duplicated":
await dialog.askClosing(Duplicated, {
reason: info.reason,
duplicatedName: info.duplicated_name,
});
return;
case "Success":
break;
case "loadingRepository":
dialogBody = <LoadingRepository cancel={cancel} />;
break;
case "duplicated":
dialogBody = <Duplicated cancel={cancel} />;
break;
case "confirming": {
const doAddRepository = async () => {
try {
await commands.environmentAddRepository(state.url, state.headers);
setState({ type: "normal" });
toastSuccess(tt("vpm repositories:toast:repository added"));
// noinspection ES6MissingAwait
refetch();
} catch (e) {
toastThrownError(e);
setState({ type: "normal" });
}
};
dialogBody = (
<Confirming
repo={state.repo}
headers={state.headers}
cancel={cancel}
add={doAddRepository}
/>
);
break;
}
default:
assertNever(state, "state");
assertNever(info, "info");
}
if (
await dialog.askClosing(Confirming, {
repo: info.value,
headers: headers,
})
) {
await commands.environmentAddRepository(url, headers);
toastSuccess(tt("vpm repositories:toast:repository added"));
await queryClient.invalidateQueries(environmentRepositoriesInfo);
}
const dialog = dialogBody ? (
<DialogOpen>
<DialogTitle>{tc("vpm repositories:button:add repository")}</DialogTitle>
{dialogBody}
</DialogOpen>
) : null;
return {
dialog,
addRepository,
openAddDialog,
};
}
function EnteringRepositoryInfo({
cancel,
addRepository,
dialog,
}: {
cancel: () => void;
addRepository: (url: string, headers: { [name: string]: string }) => void;
dialog: DialogContext<null | {
url: string;
headers: Record<string, string>;
}>;
}) {
const [url, setUrl] = useState("");
@ -226,12 +151,12 @@ function EnteringRepositoryInfo({
if (header.name.trim() === "") continue;
headers[header.name.trim()] = header.value.trim();
}
addRepository(url, headers);
dialog.close({ url, headers });
};
return (
<>
<DialogDescription>
<div>
<p className={"font-normal"}>
{tc("vpm repositories:dialog:enter repository info")}
</p>
@ -270,7 +195,7 @@ function EnteringRepositoryInfo({
<Input
type={"text"}
value={value.name}
className={"flex-grow"}
className={"grow"}
onChange={(e) =>
reordableListContext.update(id, (old) => ({
...old,
@ -285,7 +210,7 @@ function EnteringRepositoryInfo({
<Input
type={"text"}
value={value.value}
className={"flex-grow"}
className={"grow"}
onChange={(e) =>
reordableListContext.update(id, (old) => ({
...old,
@ -317,9 +242,11 @@ function EnteringRepositoryInfo({
{tc("vpm repositories:hint:duplicate headers")}
</p>
)}
</DialogDescription>
</div>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button
onClick={onAddRepository}
className={"ml-2"}
@ -332,16 +259,12 @@ function EnteringRepositoryInfo({
);
}
function LoadingRepository({
cancel,
}: {
cancel: () => void;
}) {
function LoadingRepository({ cancel }: { cancel: () => void }) {
return (
<>
<DialogDescription>
<div>
<p>{tc("vpm repositories:dialog:downloading...")}</p>
</DialogDescription>
</div>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
</DialogFooter>
@ -350,17 +273,44 @@ function LoadingRepository({
}
function Duplicated({
cancel,
reason,
duplicatedName,
dialog,
}: {
cancel: () => void;
reason: TauriDuplicatedReason;
duplicatedName: string;
dialog: DialogContext<void>;
}) {
const duplicatedDisplayName =
duplicatedName === "com.vrchat.repos.curated"
? tt("vpm repositories:source:curated")
: duplicatedName === "com.vrchat.repos.official"
? tt("vpm repositories:source:official")
: duplicatedName;
let message: React.ReactNode;
switch (reason) {
case "URLDuplicated":
message = tc("vpm repositories:dialog:url duplicated", {
name: duplicatedDisplayName,
});
break;
case "IDDuplicated":
message = tc("vpm repositories:dialog:id duplicated", {
name: duplicatedDisplayName,
});
break;
}
return (
<>
<DialogDescription>
<div>
<p>{tc("vpm repositories:dialog:already added")}</p>
</DialogDescription>
<p>{message}</p>
</div>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:ok")}</Button>
<Button onClick={() => dialog.close()}>
{tc("general:button:ok")}
</Button>
</DialogFooter>
</>
);
@ -368,19 +318,17 @@ function Duplicated({
function Confirming({
repo,
cancel,
add,
headers,
dialog,
}: {
repo: TauriRemoteRepositoryInfo;
headers: { [key: string]: string };
cancel: () => void;
add: () => void;
dialog: DialogContext<boolean>;
}) {
return (
<>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<DialogDescription className={"max-h-[50vh] overflow-y-auto font-normal"}>
<div className={"max-h-[50vh] overflow-y-auto font-normal"}>
<p className={"font-normal"}>
{tc("vpm repositories:dialog:name", { name: repo.display_name })}
</p>
@ -393,7 +341,7 @@ function Confirming({
{tc("vpm repositories:dialog:headers")}
</p>
<ul className={"list-disc pl-6"}>
{Object.entries(headers).map(([key, value], idx) => (
{Object.entries(headers).map(([key, value]) => (
<li key={key}>
{key}: {value}
</li>
@ -405,14 +353,16 @@ function Confirming({
{tc("vpm repositories:dialog:packages")}
</p>
<ul className={"list-disc pl-6"}>
{repo.packages.map((info, idx) => (
{repo.packages.map((info) => (
<li key={info.name}>{info.display_name ?? info.name}</li>
))}
</ul>
</DialogDescription>
</div>
<DialogFooter>
<Button onClick={cancel}>{tc("general:button:cancel")}</Button>
<Button onClick={add} className={"ml-2"}>
<Button onClick={() => dialog.close(false)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close(true)} className={"ml-2"}>
{tc("vpm repositories:button:add repository")}
</Button>
</DialogFooter>

View file

@ -0,0 +1,271 @@
import { queryOptions } from "@tanstack/react-query";
import type React from "react";
import { useEffect, useRef, useState } from "react";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import { DialogFooter } from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { assertNever } from "@/lib/assert-never";
import type {
TauriDownloadRepository,
TauriRepositoryDescriptor,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { callAsyncCommand } from "@/lib/call-async-command";
import { type DialogContext, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { queryClient } from "@/lib/query-client";
import { toastSuccess } from "@/lib/toast";
import { useEffectEvent } from "@/lib/use-effect-event";
type ParsedRepositories = {
repositories: TauriRepositoryDescriptor[];
unparsable_lines: string[];
};
const environmentRepositoriesInfo = queryOptions({
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
});
export async function importRepositories() {
using dialog = showDialog();
const pickResult = await commands.environmentImportRepositoryPick();
switch (pickResult.type) {
case "NoFilePicked":
// no-op
return;
case "ParsedRepositories":
// continue
break;
default:
assertNever(pickResult, "pickResult");
}
console.log("confirmingRepositories", pickResult);
const repositories = await dialog.ask(ConfirmingRepositoryList, {
pickResult,
});
if (repositories == null) return;
const packages = await dialog.ask(LoadingRepositories, {
repositories,
});
if (packages == null) return;
const repositoriesToAdd = await dialog.ask(ConfirmingPackages, {
packages,
});
if (repositoriesToAdd == null) return;
dialog.replace(<AddingRepositories />);
await commands.environmentImportAddRepositories(repositoriesToAdd);
toastSuccess(tt("vpm repositories:toast:repository added"));
dialog.close();
await queryClient.invalidateQueries(environmentRepositoriesInfo);
}
function shortRepositoryDescription(
repo: TauriRepositoryDescriptor,
): React.ReactNode {
if (Object.keys(repo.headers).length > 0) {
return tc("vpm repositories:dialog:repository with headers", {
repoUrl: repo.url,
});
}
return repo.url;
}
function ConfirmingRepositoryList({
pickResult,
dialog,
}: {
pickResult: ParsedRepositories;
dialog: DialogContext<TauriRepositoryDescriptor[] | null>;
}) {
return (
<>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<div className={"max-h-[50vh] overflow-y-auto font-normal"}>
<p className={"font-normal whitespace-normal"}>
{tc("vpm repositories:dialog:confirm repository list")}
</p>
<ul className={"list-disc pl-6"}>
{pickResult.repositories.map((info) => (
<li key={info.url}>{shortRepositoryDescription(info)}</li>
))}
</ul>
{pickResult.unparsable_lines.length > 0 && (
<>
<p className={"font-normal whitespace-normal"}>
{tc("vpm repositories:dialog:unparsable lines list")}
</p>
<ul className={"list-disc pl-6"}>
{pickResult.unparsable_lines.map((line, idx) => (
// biome-ignore lint/suspicious/noArrayIndexKey: unchanged
<li key={idx} className={"whitespace-pre"}>
{line}
</li>
))}
</ul>
</>
)}
</div>
<DialogFooter className={"gap-2"}>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close(pickResult.repositories)}>
{tc("vpm repositories:dialog:button:continue importing repositories")}
</Button>
</DialogFooter>
</>
);
}
function LoadingRepositories({
repositories,
dialog,
}: {
repositories: TauriRepositoryDescriptor[];
dialog: DialogContext<
[TauriRepositoryDescriptor, TauriDownloadRepository][] | null
>;
}) {
const cancelRef = useRef<() => void>(() => {});
const totalCount = repositories.length;
const [downloaded, setDownloaded] = useState(0);
const event = useEffectEvent(() => {
const [cancel, resultPromise] = callAsyncCommand(
commands.environmentImportDownloadRepositories,
[repositories],
(downloaded) => setDownloaded(downloaded),
);
cancelRef.current = cancel;
resultPromise.then((x) => dialog.close(x === "cancelled" ? null : x));
});
useEffect(() => event(), []);
return (
<>
<div>
<p>{tc("vpm repositories:dialog:downloading repositories...")}</p>
<Progress value={downloaded} max={totalCount} />
<div className={"text-center"}>
{tc("vpm repositories:dialog:downloaded n/m", {
downloaded,
totalCount,
})}
</div>
</div>
<DialogFooter>
<Button onClick={() => cancelRef.current?.()}>
{tc("general:button:cancel")}
</Button>
</DialogFooter>
</>
);
}
function ConfirmingPackages({
packages,
dialog,
}: {
packages: [TauriRepositoryDescriptor, TauriDownloadRepository][];
dialog: DialogContext<TauriRepositoryDescriptor[] | null>;
}) {
async function add() {
dialog.close(
packages
.filter(([_, download]) => download.type === "Success")
.map(([repo, _]) => repo),
);
}
return (
<>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<div className={"font-normal"}>
<p className={"whitespace-normal"}>
{tc("vpm repositories:dialog:confirm packages list")}
</p>
<Accordion
type="single"
collapsible
className="max-h-[50vh] overflow-y-auto w-full"
>
{packages.map(([repo, download]) => {
let error: boolean;
let content: React.ReactNode;
switch (download.type) {
case "BadUrl":
throw new Error("BadUrl should not be here");
case "Duplicated":
error = true;
content = tc(
"vpm repositories:dialog:download error:duplicated",
);
break;
case "DownloadError":
error = true;
content = tc(
"vpm repositories:dialog:download error:download error",
);
break;
case "Success":
error = false;
content = (
<ul className={"list-disc pl-6"}>
{download.value.packages.map((info) => (
<li key={info.name}>{info.display_name ?? info.name}</li>
))}
</ul>
);
break;
default:
assertNever(download, "download");
}
const destrucive = error ? "text-destructive" : "";
return (
<AccordionItem value={repo.url} key={repo.url}>
<AccordionTrigger className={`${destrucive} py-2 text-base`}>
{shortRepositoryDescription(repo)}
</AccordionTrigger>
<AccordionContent className={destrucive}>
{content}
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
</div>
<DialogFooter>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={add} className={"ml-2"}>
{tc("vpm repositories:button:add repositories")}
</Button>
</DialogFooter>
</>
);
}
function AddingRepositories() {
return (
<div>
<p>{tc("vpm repositories:dialog:adding repositories...")}</p>
</div>
);
}

View file

@ -0,0 +1,889 @@
"use client";
import {
type CollisionDetection,
closestCenter,
DndContext,
type DragEndEvent,
type DragOverEvent,
DragOverlay,
type DragStartEvent,
defaultDropAnimation,
defaultDropAnimationSideEffects,
type Modifier,
PointerSensor,
useSensor,
useSensors,
} from "@dnd-kit/core";
import {
arrayMove,
SortableContext,
useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import {
queryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { ChevronDown, CircleX, GripVertical } from "lucide-react";
import {
Suspense,
useCallback,
useEffect,
useId,
useMemo,
useRef,
useState,
} from "react";
import { HNavBar, VStack } from "@/components/layout";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { TauriUserRepository } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { type DialogContext, openSingleDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { usePrevPathName } from "@/lib/prev-page";
import { toastThrownError } from "@/lib/toast";
import { useTauriListen } from "@/lib/use-tauri-listen";
import { cn } from "@/lib/utils";
import { HeadingPageName } from "../-tab-selector";
import { addRepository, openAddRepositoryDialog } from "./-use-add-repository";
import { importRepositories } from "./-use-import-repositories";
export const Route = createFileRoute("/_main/packages/repositories/")({
component: Page,
});
type UserRepoWithListId = TauriUserRepository & { listId: string };
function Page() {
return (
<Suspense>
<PageBody />
</Suspense>
);
}
const restrictToVerticalAxis: Modifier = ({ transform }) => ({
...transform,
x: 0,
});
const DRAG_OVERLAY_MODIFIERS = [restrictToVerticalAxis];
const customDropAnimation: typeof defaultDropAnimation = {
...defaultDropAnimation,
sideEffects: defaultDropAnimationSideEffects({
styles: {
active: { opacity: "0" },
},
}),
};
const TABLE_HEAD = [
"", // checkbox
"general:name",
"vpm repositories:url",
"", // actions
"", // grip handle
] as const;
const environmentRepositoriesInfo = queryOptions({
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
});
// Scrolls the given viewport element when the pointer is near the top or bottom
// edge during drag. dnd-kit's built-in autoscroll is disabled because it causes
// jitter with Radix UI ScrollArea (wrong container detection + double-smoothing).
function useDragAutoScroll(
viewportRef: React.RefObject<HTMLElement | null>,
isActive: boolean,
): void {
useEffect(() => {
if (!isActive) return;
const THRESHOLD = 80; // px from edge to begin scrolling
const MAX_SPEED = 15; // px/frame at the very edge
let pointerY = 0;
const onPointerMove = (e: PointerEvent) => {
pointerY = e.clientY;
};
window.addEventListener("pointermove", onPointerMove, { passive: true });
let rafId: number;
const tick = () => {
const viewport = viewportRef.current;
if (viewport) {
const { top, bottom } = viewport.getBoundingClientRect();
const distFromTop = pointerY - top;
const distFromBottom = bottom - pointerY;
let delta = 0;
if (distFromTop >= 0 && distFromTop < THRESHOLD) {
delta = -MAX_SPEED * (1 - distFromTop / THRESHOLD);
} else if (distFromBottom >= 0 && distFromBottom < THRESHOLD) {
delta = MAX_SPEED * (1 - distFromBottom / THRESHOLD);
}
if (delta !== 0) {
viewport.scrollTo({
top: viewport.scrollTop + delta,
behavior: "instant",
});
}
}
rafId = requestAnimationFrame(tick);
};
rafId = requestAnimationFrame(tick);
return () => {
window.removeEventListener("pointermove", onPointerMove);
cancelAnimationFrame(rafId);
};
}, [isActive, viewportRef]);
}
function computeSlotKey(repo: TauriUserRepository, used: Set<string>): string {
const base = `${repo.id} ${repo.url ?? ""}`;
let key = base;
let counter = 0;
while (used.has(key)) {
counter++;
key = `${base} ${counter}`;
}
used.add(key);
return key;
}
function PageBody() {
const result = useQuery(environmentRepositoriesInfo);
const exportRepositories = useMutation({
mutationFn: async () => await commands.environmentExportRepositories(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
});
const importRepositoriesMutation = useMutation({
mutationFn: async () => await importRepositories(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
});
const processDeepLink = useCallback(async function processDeepLink() {
const data = await commands.deepLinkTakeAddRepository();
if (data == null) return;
await addRepository(data.url, data.headers);
}, []);
const hiddenUserRepos = useMemo(
() => new Set(result.data?.hidden_user_repositories),
[result.data?.hidden_user_repositories],
);
useTauriListen<null>("deep-link-add-repository", (_) => {
void processDeepLink();
});
// biome-ignore lint/correctness/useExhaustiveDependencies: we want to do on mount
useEffect(() => {
void processDeepLink();
// Only for initial load
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const guiAnimation = useQuery({
queryKey: ["environmentGuiAnimation"],
queryFn: commands.environmentGuiAnimation,
initialData: true,
}).data;
const userRepos = result.data?.user_repositories;
const listIdMapRef = useRef<Map<string, string>>(new Map());
const augmentedUserRepos = useMemo<UserRepoWithListId[]>(() => {
if (!userRepos) {
listIdMapRef.current = new Map();
return [];
}
const prev = listIdMapRef.current;
const next = new Map<string, string>();
const usedKeys = new Set<string>();
const result: UserRepoWithListId[] = [];
for (const r of userRepos) {
const key = computeSlotKey(r, usedKeys);
const listId = prev.get(key) ?? crypto.randomUUID();
next.set(key, listId);
result.push({ ...r, listId });
}
listIdMapRef.current = next;
return result;
}, [userRepos]);
const [orderedListIds, setOrderedListIds] = useState<string[]>(() =>
augmentedUserRepos.map((r) => r.listId),
);
useEffect(() => {
setOrderedListIds(augmentedUserRepos.map((r) => r.listId));
}, [augmentedUserRepos]);
const userRepoByListId = useMemo(
() => new Map(augmentedUserRepos.map((r) => [r.listId, r])),
[augmentedUserRepos],
);
const userRepoByListIdRef =
useRef<Map<string, UserRepoWithListId>>(userRepoByListId);
useEffect(() => {
userRepoByListIdRef.current = userRepoByListId;
}, [userRepoByListId]);
const [activeId, setActiveId] = useState<string | null>(null);
const [overId, setOverId] = useState<string | null>(null);
const [columnWidths, setColumnWidths] = useState<number[]>([]);
const theadRowRef = useRef<HTMLTableRowElement>(null);
const scrollViewportRef = useRef<HTMLDivElement>(null);
const sensors = useSensors(useSensor(PointerSensor));
const orderedListIdsSet = useMemo(
() => new Set(orderedListIds),
[orderedListIds],
);
const collisionDetection = useCallback<CollisionDetection>(
(args) =>
closestCenter({
...args,
droppableContainers: args.droppableContainers.filter((c) =>
orderedListIdsSet.has(c.id as string),
),
}),
[orderedListIdsSet],
);
const queryClient = useQueryClient();
const reorderMutation = useMutation({
mutationFn: (listIds: string[]) => {
const repos = listIds
.map((lid) => userRepoByListId.get(lid))
.filter((r): r is UserRepoWithListId => r !== undefined)
.map((r) => ({ index: r.index, id: r.id }));
return commands.environmentReorderRepositories(repos);
},
// Pin listIds to the new positions so duplicate-keyed rows don't swap their listIds on refetch.
onMutate: (newListIds: string[]) => {
const prevMap = new Map(listIdMapRef.current);
const rebuilt = new Map<string, string>();
const usedKeys = new Set<string>();
for (const lid of newListIds) {
const repo = userRepoByListIdRef.current.get(lid);
if (!repo) continue;
const key = computeSlotKey(repo, usedKeys);
rebuilt.set(key, lid);
}
listIdMapRef.current = rebuilt;
return { prevMap };
},
onSettled: () => queryClient.invalidateQueries(environmentRepositoriesInfo),
onError: (e, _newListIds, ctx) => {
if (ctx?.prevMap) listIdMapRef.current = ctx.prevMap;
toastThrownError(e);
},
});
const setHideRepository = useMutation({
mutationFn: async ({ id, shown }: { id: string; shown: boolean }) => {
if (shown) {
await commands.environmentShowRepository(id);
} else {
await commands.environmentHideRepository(id);
}
},
onMutate: async ({ id, shown }: { id: string; shown: boolean }) => {
await queryClient.cancelQueries(environmentRepositoriesInfo);
const data = queryClient.getQueryData(
environmentRepositoriesInfo.queryKey,
);
if (data !== undefined) {
let hidden_user_repositories: string[];
if (shown) {
if (data.hidden_user_repositories.includes(id)) {
hidden_user_repositories = data.hidden_user_repositories;
} else {
hidden_user_repositories = [...data.hidden_user_repositories, id];
}
} else {
hidden_user_repositories = data.hidden_user_repositories.filter(
(x) => x !== id,
);
}
queryClient.setQueryData(environmentRepositoriesInfo.queryKey, {
...data,
hidden_user_repositories,
});
}
return data;
},
onError: (e, _, ctx) => {
reportError(e);
console.error(e);
queryClient.setQueryData(environmentRepositoriesInfo.queryKey, ctx);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentRepositoriesInfo);
},
});
const activeVisualIndex = useMemo(() => {
if (!activeId) return 0;
const effectiveId = overId ?? activeId;
return orderedListIds.indexOf(effectiveId) + 2; // +2 for the 2 fixed rows
}, [activeId, overId, orderedListIds]);
function handleDragStart(event: DragStartEvent) {
setActiveId(event.active.id as string);
if (theadRowRef.current) {
const widths = Array.from(
theadRowRef.current.querySelectorAll("th"),
(th) => th.getBoundingClientRect().width,
);
setColumnWidths(widths);
}
}
function handleDragOver(event: DragOverEvent) {
setOverId((event.over?.id as string | null) ?? null);
}
function handleDragEnd(event: DragEndEvent) {
setActiveId(null);
setOverId(null);
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = orderedListIds.indexOf(active.id as string);
const newIndex = orderedListIds.indexOf(over.id as string);
const newListIds = arrayMove(orderedListIds, oldIndex, newIndex);
setOrderedListIds(newListIds);
reorderMutation.mutate(newListIds);
}
}
function handleDragCancel() {
setActiveId(null);
setOverId(null);
}
useDragAutoScroll(scrollViewportRef, activeId !== null);
const bodyAnimation = usePrevPathName().startsWith("/packages")
? "slide-right"
: "";
return (
<DndContext
sensors={sensors}
collisionDetection={collisionDetection}
autoScroll={false}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDragEnd={handleDragEnd}
onDragCancel={handleDragCancel}
>
<VStack>
<div style={activeId !== null ? { pointerEvents: "none" } : undefined}>
<HNavBar
className="shrink-0"
leading={<HeadingPageName pageType={"/packages/repositories"} />}
trailing={
<DropdownMenu>
<div className={"flex divide-x"}>
<Button
className={"rounded-r-none compact:h-10"}
onClick={() => openAddRepositoryDialog()}
>
{tc("vpm repositories:button:add repository")}
</Button>
<DropdownMenuTrigger
asChild
className={"rounded-l-none pl-2 pr-2 compact:h-10"}
>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuItem
onClick={() => importRepositoriesMutation.mutate()}
>
{tc("vpm repositories:button:import repositories")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportRepositories.mutate()}>
{tc("vpm repositories:button:export repositories")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
}
/>
</div>
<main
className={`shrink overflow-hidden flex w-full h-full ${bodyAnimation}`}
>
<ScrollableCardTable
className={"h-full w-full"}
viewportRef={scrollViewportRef}
>
<RepositoryTableBody
orderedListIds={orderedListIds}
userRepoByListId={userRepoByListId}
hiddenUserRepos={hiddenUserRepos}
theadRowRef={theadRowRef}
guiAnimation={guiAnimation}
onToggleVisibility={(id, shown) =>
setHideRepository.mutate({ id, shown })
}
isDragActive={activeId !== null}
/>
</ScrollableCardTable>
</main>
</VStack>
<DragOverlay
modifiers={DRAG_OVERLAY_MODIFIERS}
dropAnimation={guiAnimation ? customDropAnimation : null}
>
{activeId ? (
<RepositoryDragOverlay
repo={userRepoByListId.get(activeId)}
selected={
!hiddenUserRepos.has(userRepoByListId.get(activeId)?.id ?? "")
}
columnWidths={columnWidths}
visualIndex={activeVisualIndex}
guiAnimation={guiAnimation}
/>
) : null}
</DragOverlay>
</DndContext>
);
}
function RepositoryTableBody({
orderedListIds,
userRepoByListId,
hiddenUserRepos,
theadRowRef,
guiAnimation,
onToggleVisibility,
isDragActive,
}: {
orderedListIds: string[];
userRepoByListId: Map<string, UserRepoWithListId>;
hiddenUserRepos: Set<string>;
theadRowRef: React.RefObject<HTMLTableRowElement | null>;
guiAnimation: boolean;
onToggleVisibility: (id: string, shown: boolean) => void;
isDragActive: boolean;
}) {
return (
<>
<thead>
<tr ref={theadRowRef}>
{TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground px-2.5 py-1.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
</tr>
</thead>
<tbody>
<RepositoryRow
repoId={"com.vrchat.repos.official"}
url={"https://packages.vrchat.com/official?download"}
displayName={tt("vpm repositories:source:official")}
hiddenUserRepos={hiddenUserRepos}
canRemove={false}
rowIndex={0}
guiAnimation={guiAnimation}
onToggleVisibility={onToggleVisibility}
isDragActive={isDragActive}
/>
<RepositoryRow
repoId={"com.vrchat.repos.curated"}
url={"https://packages.vrchat.com/curated?download"}
displayName={tt("vpm repositories:source:curated")}
hiddenUserRepos={hiddenUserRepos}
className={"border-b border-primary/10"}
canRemove={false}
rowIndex={1}
guiAnimation={guiAnimation}
onToggleVisibility={onToggleVisibility}
isDragActive={isDragActive}
/>
<SortableContext
items={orderedListIds}
strategy={verticalListSortingStrategy}
>
{orderedListIds.map((listId, index) => {
const repo = userRepoByListId.get(listId);
if (!repo) return null;
return (
<RepositoryRow
key={listId}
listId={listId}
repoId={repo.id}
repoIndex={repo.index}
displayName={repo.display_name}
url={repo.url}
hiddenUserRepos={hiddenUserRepos}
rowIndex={2 + index}
guiAnimation={guiAnimation}
onToggleVisibility={onToggleVisibility}
isDragActive={isDragActive}
/>
);
})}
</SortableContext>
</tbody>
</>
);
}
const CELL_CLASS = "p-2.5 compact:py-1 align-middle";
function RepositoryRowCells({
labelId,
displayName,
url,
canRemove,
selected,
onCheckedChange,
onRemove,
dragListeners,
dragAttributes,
}: {
labelId?: string;
displayName: string;
url: string | null | undefined;
canRemove: boolean;
selected: boolean;
onCheckedChange?: (shown: boolean) => void;
onRemove?: () => void;
dragListeners?: ReturnType<typeof useSortable>["listeners"];
dragAttributes?: ReturnType<typeof useSortable>["attributes"];
}) {
const interactive = onCheckedChange !== undefined;
return (
<>
<td className={CELL_CLASS}>
{interactive ? (
<div className="flex">
<Checkbox
id={labelId}
checked={selected}
onCheckedChange={(x) => onCheckedChange(x === true)}
/>
</div>
) : (
<div className="pointer-events-none flex">
<Checkbox checked={selected} />
</div>
)}
</td>
<td className={CELL_CLASS}>
{interactive ? (
<label htmlFor={labelId}>
<p className="font-normal">{displayName}</p>
</label>
) : (
<p className="font-normal">{displayName}</p>
)}
</td>
<td className={CELL_CLASS}>
<p className="font-normal">{url}</p>
</td>
<td className={`${CELL_CLASS} w-0`}>
{interactive ? (
<Tooltip>
<TooltipTrigger asChild={canRemove}>
<Button
disabled={!canRemove}
onClick={onRemove}
variant={"ghost"}
size={"icon"}
>
<CircleX className={"size-5 text-destructive"} />
</Button>
</TooltipTrigger>
<TooltipContent>
{canRemove
? tc("vpm repositories:remove repository")
: tc(
"vpm repositories:tooltip:remove curated or official repository",
)}
</TooltipContent>
</Tooltip>
) : (
<Button variant={"ghost"} size={"icon"} disabled>
<CircleX className={"size-5 text-destructive"} />
</Button>
)}
</td>
<td
className={cn(
CELL_CLASS,
"w-0",
canRemove ? "cursor-move" : "cursor-not-allowed",
)}
{...(canRemove ? dragListeners : undefined)}
{...(canRemove ? dragAttributes : undefined)}
>
<GripVertical
className={cn(
"size-5 text-muted-foreground",
!canRemove && "opacity-50",
)}
/>
</td>
</>
);
}
function RepositoryRow({
listId,
repoId,
repoIndex,
displayName,
url,
hiddenUserRepos,
className,
canRemove = true,
rowIndex,
guiAnimation,
onToggleVisibility,
isDragActive,
}: {
listId?: string;
repoId: TauriUserRepository["id"];
repoIndex?: number;
displayName: TauriUserRepository["display_name"];
url: TauriUserRepository["url"];
hiddenUserRepos: Set<string>;
className?: string;
canRemove?: boolean;
rowIndex: number;
guiAnimation: boolean;
onToggleVisibility: (id: string, shown: boolean) => void;
isDragActive: boolean;
}) {
const labelId = useId();
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id: listId ?? repoId, disabled: !canRemove });
const visualIndex = useMemo(() => {
if (isDragging) return rowIndex;
const dy = transform?.y ?? 0;
if (dy < 0) return rowIndex - 1;
if (dy > 0) return rowIndex + 1;
return rowIndex;
}, [rowIndex, transform?.y, isDragging]);
const dragStyle = useMemo<React.CSSProperties>(
() => ({
transform: transform ? `translateY(${transform.y}px)` : undefined,
transition: guiAnimation
? [transition, isDragActive ? undefined : "background-color 200ms ease"]
.filter(Boolean)
.join(", ") || undefined
: undefined,
opacity: isDragging ? 0 : 1,
position: "relative",
}),
[transform, transition, isDragging, guiAnimation, isDragActive],
);
const selected = !hiddenUserRepos.has(repoId);
return (
<tr
ref={setNodeRef}
style={dragStyle}
className={cn(visualIndex % 2 === 1 ? "bg-secondary/30" : "", className)}
>
<RepositoryRowCells
labelId={labelId}
displayName={displayName}
url={url}
canRemove={canRemove}
selected={selected}
onCheckedChange={(shown) => onToggleVisibility(repoId, shown)}
onRemove={() =>
void openSingleDialog(RemoveRepositoryDialog, {
displayName,
index: repoIndex ?? 0,
id: repoId,
})
}
dragListeners={listeners}
dragAttributes={attributes}
/>
</tr>
);
}
function RepositoryDragOverlay({
repo,
selected,
columnWidths,
visualIndex,
guiAnimation,
}: {
repo: TauriUserRepository | undefined;
selected: boolean;
columnWidths: number[];
visualIndex: number;
guiAnimation: boolean;
}) {
const style = useMemo<React.CSSProperties>(
() => ({
transition: guiAnimation ? "background-color 200ms ease" : undefined,
}),
[guiAnimation],
);
if (!repo) return null;
return (
<table
className={cn(
"w-full table-fixed text-left",
visualIndex % 2 === 1 ? "bg-secondary/30" : "",
)}
style={style}
>
{columnWidths.length > 0 && (
<colgroup>
{columnWidths.map((w, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: fixed column order
<col key={i} style={{ width: w }} />
))}
</colgroup>
)}
<tbody>
<tr>
<RepositoryRowCells
displayName={repo.display_name}
url={repo.url}
canRemove={true}
selected={selected}
/>
</tr>
</tbody>
</table>
);
}
function RemoveRepositoryDialog({
dialog,
displayName,
index,
id,
}: {
dialog: DialogContext<void>;
displayName: string;
index: number;
id: string;
}) {
const queryClient = useQueryClient();
const removeRepository = useMutation({
mutationFn: async (args: { index: number; id: string }) =>
await commands.environmentRemoveRepository(args.index, args.id),
onMutate: async ({ index }) => {
await queryClient.cancelQueries(environmentRepositoriesInfo);
const data = queryClient.getQueryData(
environmentRepositoriesInfo.queryKey,
);
if (data !== undefined) {
queryClient.setQueryData(environmentRepositoriesInfo.queryKey, {
...data,
user_repositories: data.user_repositories.filter(
(x) => x.index !== index,
),
});
}
return data;
},
onError: (e, _args, ctx) => {
queryClient.setQueryData(environmentRepositoriesInfo.queryKey, ctx);
toastThrownError(e);
},
onSettled: () => queryClient.invalidateQueries(environmentRepositoriesInfo),
});
return (
<>
<DialogTitle>{tc("vpm repositories:remove repository")}</DialogTitle>
<div>
<p className={"whitespace-normal font-normal"}>
{tc("vpm repositories:dialog:confirm remove description", {
name: displayName,
})}
</p>
</div>
<DialogFooter>
<Button onClick={() => dialog.close()}>
{tc("general:button:cancel")}
</Button>
<Button
onClick={() => {
dialog.close();
removeRepository.mutate({ index, id });
}}
className={"ml-2"}
>
{tc("vpm repositories:remove repository")}
</Button>
</DialogFooter>
</>
);
}

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,21 @@
"use client";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import {
queryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { CircleX } from "lucide-react";
import { Suspense, useId } from "react";
import { HNavBar, VStack } from "@/components/layout";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogTitle,
DialogTrigger,
@ -20,15 +28,16 @@ import {
import type { TauriUserPackage } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { usePrevPathName } from "@/lib/prev-page";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { useFilePickerFunction } from "@/lib/use-file-picker-dialog";
import { toVersionString } from "@/lib/version";
import { useQuery } from "@tanstack/react-query";
import { CircleX } from "lucide-react";
import { Suspense, useCallback, useId } from "react";
import { HeadingPageName } from "../tab-selector";
import { HeadingPageName } from "../-tab-selector";
export default function Page() {
export const Route = createFileRoute("/_main/packages/user-packages/")({
component: Page,
});
function Page() {
return (
<Suspense>
<PageBody />
@ -36,80 +45,101 @@ export default function Page() {
);
}
const environmentGetUserPackages = queryOptions({
queryKey: ["environmentGetUserPackages"],
queryFn: commands.environmentGetUserPackages,
});
function PageBody() {
const result = useQuery({
queryKey: ["environmentGetUserPackages"],
queryFn: commands.environmentGetUserPackages,
const result = useQuery(environmentGetUserPackages);
const queryClient = useQueryClient();
const addUserPackageWithPicker = useMutation({
mutationFn: async () =>
await commands.environmentAddUserPackageWithPicker(),
onSuccess: async (result) => {
switch (result) {
case "NoFolderSelected":
break;
case "InvalidSelection":
toastError(tc("user packages:toast:invalid selection"));
break;
case "AlreadyAdded":
toastSuccess(tc("user packages:toast:package already added"));
break;
case "Successful":
toastSuccess(tc("user packages:toast:package added"));
await queryClient.invalidateQueries(environmentGetUserPackages);
break;
}
},
onError: (error) => {
console.error(error);
toastThrownError(error);
},
});
const [envAddUserPackage, dialog] = useFilePickerFunction(
commands.environmentAddUserPackageWithPicker,
);
const addUserPackage = useCallback(
async function addUserPackage() {
try {
switch (await envAddUserPackage()) {
case "NoFolderSelected":
break;
case "InvalidSelection":
toastError(tc("user packages:toast:invalid selection"));
break;
case "AlreadyAdded":
toastSuccess(tc("user packages:toast:package already added"));
break;
case "Successful":
toastSuccess(tc("user packages:toast:package added"));
await result.refetch();
break;
}
} catch (e) {
toastThrownError(e);
}
},
[envAddUserPackage, result],
);
const removeUserPackage = useCallback(
async function removeUserPackage(path: string) {
try {
await commands.environmentRemoveUserPackages(path);
toastSuccess(tc("user packages:toast:package removed"));
await result.refetch();
} catch (e) {
toastThrownError(e);
}
},
[result],
);
const bodyAnimation = usePrevPathName().startsWith("/packages")
? "slide-left"
: "";
return (
<VStack>
<HNavBar className={"flex-shrink-0"}>
<HeadingPageName pageType={"/packages/user-packages"} />
<div className={"flex-grow"} />
<Button onClick={addUserPackage}>
{tc("user packages:button:add package")}
</Button>
</HNavBar>
<ScrollableCardTable>
<RepositoryTableBody
userPackages={result.data || []}
removeUserPackage={removeUserPackage}
/>
</ScrollableCardTable>
{dialog}
<HNavBar
className="shrink-0"
leading={<HeadingPageName pageType={"/packages/user-packages"} />}
trailing={
<Button
className={"compact:h-10"}
onClick={() => addUserPackageWithPicker.mutate()}
>
{tc("user packages:button:add package")}
</Button>
}
/>
<main
className={`shrink overflow-hidden flex w-full h-full ${bodyAnimation}`}
>
<ScrollableCardTable className={"h-full w-full"}>
<RepositoryTableBody userPackages={result.data || []} />
</ScrollableCardTable>
</main>
</VStack>
);
}
function RepositoryTableBody({
userPackages,
removeUserPackage,
}: {
userPackages: TauriUserPackage[];
removeUserPackage: (path: string) => void;
}) {
const queryClient = useQueryClient();
const removeUserPackages = useMutation({
mutationFn: async (path: string) =>
await commands.environmentRemoveUserPackages(path),
onMutate: async (path) => {
await queryClient.invalidateQueries(environmentGetUserPackages);
const data = queryClient.getQueryData(
environmentGetUserPackages.queryKey,
);
if (data !== undefined) {
queryClient.setQueryData(
environmentGetUserPackages.queryKey,
data.filter((x) => x.path === path),
);
}
return data;
},
onError: (error, _, ctx) => {
console.error(error);
toastThrownError(error);
queryClient.setQueryData(environmentGetUserPackages.queryKey, ctx);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetUserPackages);
},
});
const TABLE_HEAD = [
"general:name",
"user packages:path",
@ -126,7 +156,7 @@ function RepositoryTableBody({
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground px-2.5 py-1.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
@ -139,7 +169,7 @@ function RepositoryTableBody({
<PackageRow
key={pkg.path}
pkg={pkg}
remove={() => removeUserPackage(pkg.path)}
remove={() => removeUserPackages.mutate(pkg.path)}
/>
))}
</tbody>
@ -154,7 +184,7 @@ function PackageRow({
pkg: TauriUserPackage;
remove: () => void;
}) {
const cellClass = "p-2.5";
const cellClass = "p-2.5 compact:py-1";
const id = useId();
const pkgDisplayNames = pkg.package.display_name ?? pkg.package.name;
@ -189,14 +219,14 @@ function PackageRow({
<DialogTitle>
{tc("user packages:dialog:remove package")}
</DialogTitle>
<DialogDescription>
<div>
<p className={"whitespace-normal font-normal"}>
{tc("user packages:dialog:confirm remove description", {
name: pkgDisplayNames,
path: pkg.path,
})}
</p>
</DialogDescription>
</div>
<DialogFooter>
<DialogClose asChild>
<Button>{tc("general:button:cancel")}</Button>

View file

@ -0,0 +1,325 @@
import { useMutation } from "@tanstack/react-query";
import { RefreshCw } from "lucide-react";
import type React from "react";
import { useEffect, useId, useMemo, useState } from "react";
import { VStack } from "@/components/layout";
import { TemplateSelect } from "@/components/TemplateSelect";
import { Button } from "@/components/ui/button";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { assertNever } from "@/lib/assert-never";
import type { TauriProjectTemplateInfo } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { type DialogContext, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { router } from "@/lib/main";
import { pathSeparator } from "@/lib/os";
import {
ProjectNameCheckResult,
useProjectNameCheck,
} from "@/lib/project-name-check";
import { queryClient } from "@/lib/query-client";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
export async function createProject() {
const information = await commands.environmentProjectCreationInformation();
using dialog = showDialog();
const result = await dialog.ask(EnteringInformation, {
templates: information.templates,
favoriteTemplates: information.favorite_templates,
lastUsedTemplate: information.last_used_template,
projectLocation: information.default_path,
recentProjectLocations: information.recent_project_locations,
});
if (result == null) return;
dialog.replace(<CreatingProject />);
await commands.environmentCreateProject(
result.projectLocation,
result.projectName,
result.templateId,
information.templates_version,
result.unityVersion,
);
dialog.close();
toastSuccess(tt("projects:toast:project created"));
await queryClient.invalidateQueries({
queryKey: ["environmentProjects"],
});
const projectPath = `${result.projectLocation}${pathSeparator()}${result.projectName}`;
router.navigate({
to: "/projects/manage",
search: { projectPath },
});
}
function DialogBase({
children,
close,
createProject,
}: {
children: React.ReactNode;
close?: () => void;
createProject?: () => void;
}) {
return (
<>
<DialogTitle>{tc("projects:create new project")}</DialogTitle>
<div>{children}</div>
<DialogFooter className={"gap-2"}>
<Button onClick={close} disabled={!close}>
{tc("general:button:cancel")}
</Button>
<Button onClick={createProject} disabled={!createProject}>
{tc("projects:button:create")}
</Button>
</DialogFooter>
</>
);
}
interface ProjectCreationInformation {
templateId: string;
unityVersion: string;
projectLocation: string;
projectName: string;
}
function EnteringInformation({
templates,
projectLocation: projectLocationFirst,
recentProjectLocations: recentProjectLocationsReversed,
favoriteTemplates,
lastUsedTemplate,
dialog,
}: {
templates: TauriProjectTemplateInfo[];
projectLocation: string;
favoriteTemplates: string[];
lastUsedTemplate: string | null;
recentProjectLocations: string[];
dialog: DialogContext<null | ProjectCreationInformation>;
}) {
const templateById = useMemo(
() => new Map(templates.map((t) => [t.id, t])),
[templates],
);
const [templateId, setTemplateId] = useState<string>(() => {
const template = lastUsedTemplate
? templateById.get(lastUsedTemplate)
: undefined;
return template?.available &&
template.unity_versions.length !== 0 &&
lastUsedTemplate != null
? lastUsedTemplate
: templates[0].id;
});
const [unityVersion, setUnityVersion] = useState<string>(
() =>
templateById.get(templateId)?.unity_versions?.[0] ??
templates[0].unity_versions[0],
);
const [projectNameRaw, setProjectName] = useState("New Project");
const projectName = projectNameRaw.trim();
const [projectLocation, setProjectLocation] = useState(projectLocationFirst);
const [lastPickedLocation, setLastPickedLocation] =
useState(projectLocationFirst);
const projectNameCheckState = useProjectNameCheck(
projectLocation,
projectName,
);
const usePickProjectDefaultPath = useMutation({
mutationFn: () => commands.environmentPickProjectDefaultPath(),
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("general:toast:invalid directory"));
break;
case "Successful":
setProjectLocation(result.new_path);
setLastPickedLocation(result.new_path);
break;
default:
assertNever(result);
}
},
onError: (e) => {
console.error(e);
toastThrownError(e);
},
});
const createProject = async () => {
dialog.close({
templateId,
unityVersion,
projectLocation,
projectName,
});
};
const templateInputId = useId();
const unityInputId = useId();
const unityVersions = templateById.get(templateId)?.unity_versions ?? [];
const badProjectName = ["AlreadyExists", "InvalidNameForFolderName"].includes(
projectNameCheckState,
);
const canCreateProject =
projectNameCheckState !== "checking" && !badProjectName;
useEffect(() => {
setUnityVersion(unityVersions[0]);
}, [unityVersions]);
const recentProjectLocations = useMemo(() => {
const copied = [...recentProjectLocationsReversed];
copied.reverse();
return copied;
}, [recentProjectLocationsReversed]);
return (
<DialogBase
close={() => dialog.close(null)}
createProject={canCreateProject ? createProject : undefined}
>
<VStack>
<div className={"flex gap-1"}>
<div className={"flex items-center whitespace-nowrap"}>
<label htmlFor={templateInputId}>{tc("projects:template")}</label>
</div>
<TemplateSelect
value={templateId}
onValueChange={setTemplateId}
templates={templates}
favoriteTemplates={favoriteTemplates}
selectTriggerId={templateInputId}
/>
</div>
<div className={"flex items-center gap-1 whitespace-nowrap"}>
<label htmlFor={unityInputId}>
{tc("projects:template:unity version")}
</label>
<Select
value={unityVersion}
onValueChange={(value) => setUnityVersion(value)}
disabled={unityVersions.length === 1}
>
<SelectTrigger id={unityInputId}>
<SelectValue />
</SelectTrigger>
<SelectContent>
{unityVersions.map((unityVersion) => (
<SelectItem value={unityVersion} key={unityVersion}>
<UnityVersion
unityVersion={unityVersion}
latestUnityVersion={
unityVersions.length === 1 ? "" : unityVersions[0]
}
/>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Input
value={projectNameRaw}
onChange={(e) => setProjectName(e.target.value)}
/>
<div className={"flex gap-1 items-center"}>
{/*Note that this is an abuse of Select*/}
<Select value={""} onValueChange={(v) => setProjectLocation(v)}>
<SelectTrigger>
<SelectValue placeholder={projectLocation} />
</SelectTrigger>
<SelectContent>
{!recentProjectLocations.includes(lastPickedLocation) && (
<SelectItem value={lastPickedLocation}>
{lastPickedLocation}
</SelectItem>
)}
{recentProjectLocations.map((path) => (
<SelectItem value={path} key={path}>
{path}
</SelectItem>
))}
</SelectContent>
</Select>
<Button
className="flex-none px-4"
onClick={() => usePickProjectDefaultPath.mutate()}
>
{tc("general:button:select")}
</Button>
</div>
<small className={"whitespace-normal"}>
{tc(
"projects:hint:path of creating project",
{ path: `${projectLocation}${pathSeparator()}${projectName}` },
{
components: {
path: (
<span
className={
"p-0.5 font-path whitespace-pre bg-secondary text-secondary-foreground"
}
/>
),
},
},
)}
</small>
<ProjectNameCheckResult projectNameCheckState={projectNameCheckState} />
</VStack>
</DialogBase>
);
}
function UnityVersion({
unityVersion,
latestUnityVersion,
}: {
unityVersion: string;
latestUnityVersion: string;
}) {
if (unityVersion === latestUnityVersion) {
return (
<>
{unityVersion}{" "}
<span className={"text-success"}>{tc("projects:latest")}</span>
</>
);
} else {
return unityVersion;
}
}
function CreatingProject() {
return (
<DialogBase>
<div className={"flex items-center gap-2"}>
<RefreshCw className={"w-5 h-5 animate-spin"} />
<p>{tc("projects:creating project...")}</p>
</div>
</DialogBase>
);
}

View file

@ -0,0 +1,235 @@
import { CircleHelp, CircleUserRound, Ellipsis, Globe } from "lucide-react";
import {
ButtonDisabledIfInvalid,
getProjectDisplayInfo,
ManageOrMigrateButton,
ProjectContext,
TooltipTriggerIfInvalid,
TooltipTriggerIfValid,
useSetProjectFavoriteMutation,
} from "@/app/_main/projects/-project-row";
import { copyProject } from "@/app/_main/projects/manage/-copy-project";
import { BackupProjectDialog } from "@/components/BackupProjectDialog";
import { FavoriteStarToggleButton } from "@/components/FavoriteStarButton";
import { OpenUnityButton } from "@/components/OpenUnityButton";
import { RemoveProjectDialog } from "@/components/RemoveProjectDialog";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipPortal,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { TauriProject } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import {
dateToString,
dayToString,
formatDateOffset,
} from "@/lib/dateToString";
import { openSingleDialog } from "@/lib/dialog";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
export function ProjectGridItem({
project,
loading,
}: {
project: TauriProject;
loading?: boolean;
}) {
const setProjectFavorite = useSetProjectFavoriteMutation();
const typeIconClass = "w-5 h-5";
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
getProjectDisplayInfo(project);
const removed = !project.is_exists;
const is_valid = project.is_valid;
return (
<ProjectContext.Provider
value={{ removed, is_valid, loading: Boolean(loading) }}
>
<Card className="relative p-4 bg-card flex flex-col gap-2 group compact:p-2 compact:pl-3 compact:gap-1">
<div className={"absolute top-2 right-2 gap-2 flex"}>
<div className="relative content-center">
<FavoriteStarToggleButton
favorite={project.favorite}
disabled={removed || loading}
onToggle={() =>
setProjectFavorite.mutate({
...project,
favorite: !project.favorite,
})
}
/>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<Ellipsis className="size-5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={() =>
commands.utilOpen(project.path, "ErrorIfNotExists")
}
disabled={!project.is_exists || loading}
>
{tc("projects:menuitem:open directory")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={async () => {
try {
await copyProject(project.path);
} catch (e) {
console.error(e);
toastThrownError(e);
}
}}
disabled={!project.is_valid}
>
{tc("projects:menuitem:copy project")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
openSingleDialog(RemoveProjectDialog, { project })
}
disabled={loading}
className="text-destructive focus:text-destructive"
>
{tc("projects:remove project")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<Tooltip>
<TooltipTriggerIfInvalid
className={"text-left select-text cursor-auto w-full"}
>
<div className="flex flex-col">
<Tooltip>
<TooltipTriggerIfValid
className={"text-left select-text cursor-auto w-full"}
>
<p className="font-normal whitespace-pre overflow-ellipsis overflow-hidden">
{project.name}
</p>
<p className="font-normal opacity-50 text-sm whitespace-pre overflow-ellipsis overflow-hidden compact:hidden">
{project.path}
</p>
</TooltipTriggerIfValid>
<TooltipContent>{project.path}</TooltipContent>
</Tooltip>
</div>
</TooltipTriggerIfInvalid>
<TooltipPortal>
<TooltipContent>
{removed
? tc("projects:tooltip:no directory")
: tc("projects:tooltip:invalid project")}
</TooltipContent>
</TooltipPortal>
</Tooltip>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{projectTypeKind === "avatars" ? (
<CircleUserRound className={typeIconClass} />
) : projectTypeKind === "worlds" ? (
<Globe className={typeIconClass} />
) : (
<CircleHelp className={typeIconClass} />
)}
</div>
<div className="flex flex-col justify-center">
<p className="font-normal">{displayType}</p>
{isLegacy && (
<p className="font-normal opacity-50 dark:opacity-80 text-sm text-destructive">
{tc("projects:type:legacy")}
</p>
)}
</div>
<p className="text-sm flex flex-col justify-center">·</p>
<div className="flex flex-col justify-center">
<p className={"text-sm"}>{project.unity}</p>
</div>
</div>
<div className="flex flex-row gap-1">
<div className="text-xs text-muted-foreground">
{tc("general:created at")}:{" "}
<Tooltip>
<TooltipTrigger>
<time dateTime={createdAt.toISOString()}>
<time className="font-normal">
{dayToString(project.created_at)}
</time>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{dateToString(project.created_at)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>
<p className="text-xs text-muted-foreground">/</p>
<div className="text-xs text-muted-foreground">
{tc("general:last modified")}:{" "}
<Tooltip>
<TooltipTrigger>
<time dateTime={lastModified.toISOString()}>
<time className="font-normal">
{formatDateOffset(project.last_modified)}
</time>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{dateToString(project.last_modified)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>
</div>
<div className="mt-2 flex flex-wrap gap-2 justify-end compact:gap-1">
<ButtonDisabledIfInvalid asChild>
<OpenUnityButton
projectPath={project.path}
unityVersion={project.unity}
unityRevision={project.unity_revision}
/>
</ButtonDisabledIfInvalid>
<ManageOrMigrateButton project={project} />
<ButtonDisabledIfInvalid
onClick={() =>
openSingleDialog(BackupProjectDialog, {
projectPath: project.path,
})
}
variant="success"
>
{tc("projects:backup")}
</ButtonDisabledIfInvalid>
</div>
</Card>
</ProjectContext.Provider>
);
}

View file

@ -0,0 +1,572 @@
import {
queryOptions,
useMutation,
useQueryClient,
} from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import { CircleHelp, CircleUserRound, Ellipsis, Globe } from "lucide-react";
import React, { type ComponentProps, useContext } from "react";
import { copyProject } from "@/app/_main/projects/manage/-copy-project";
import { MigrationCopyingDialog } from "@/app/_main/projects/manage/-unity-migration";
import { BackupProjectDialog } from "@/components/BackupProjectDialog";
import { FavoriteStarToggleButton } from "@/components/FavoriteStarButton";
import { OpenUnityButton } from "@/components/OpenUnityButton";
import { RemoveProjectDialog } from "@/components/RemoveProjectDialog";
import { Button } from "@/components/ui/button";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipPortal,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { assertNever } from "@/lib/assert-never";
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import {
dateToString,
dayToString,
formatDateOffset,
} from "@/lib/dateToString";
import { type DialogContext, openSingleDialog, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { router } from "@/lib/main";
import { queryClient } from "@/lib/query-client";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { compareUnityVersionString } from "@/lib/version";
export const ProjectDisplayType: Record<
TauriProjectType,
"avatars" | "worlds" | "sdk2" | "unknown"
> = {
Unknown: "unknown",
LegacySdk2: "sdk2",
LegacyWorlds: "worlds",
LegacyAvatars: "avatars",
UpmWorlds: "worlds",
UpmAvatars: "avatars",
UpmStarter: "unknown",
Worlds: "worlds",
Avatars: "avatars",
VpmStarter: "unknown",
};
export const LegacyProjectTypes = [
"LegacySdk2",
"LegacyWorlds",
"LegacyAvatars",
"UpmWorlds",
"UpmAvatars",
"UpmStarter",
];
const environmentProjects = queryOptions({
queryKey: ["environmentProjects"],
queryFn: commands.environmentProjects,
});
export function ProjectRow({
project,
loading,
}: {
project: TauriProject;
loading?: boolean;
}) {
const cellClass = "p-2.5 compact:py-1";
const noGrowCellClass = `${cellClass} w-1`;
const typeIconClass = "w-5 h-5";
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
getProjectDisplayInfo(project);
const openProjectFolder = () =>
commands.utilOpen(project.path, "ErrorIfNotExists");
const onCopyProject = async () => {
try {
await copyProject(project.path);
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const setProjectFavorite = useSetProjectFavoriteMutation();
const removed = !project.is_exists;
const is_valid = project.is_valid;
return (
<ProjectContext.Provider
value={{ removed, is_valid, loading: Boolean(loading) }}
>
<tr
className={`group even:bg-secondary/30 ${removed || loading || !(project.is_valid ?? true) ? "opacity-50" : ""}`}
>
<td className={noGrowCellClass}>
<div className={"relative flex"}>
<FavoriteStarToggleButton
favorite={project.favorite}
disabled={removed || loading}
onToggle={() =>
setProjectFavorite.mutate({
...project,
favorite: !project.favorite,
})
}
/>
</div>
</td>
<td className={`${cellClass} max-w-64 overflow-hidden`}>
<Tooltip>
<TooltipTriggerIfInvalid
className={"text-left select-text cursor-auto w-full"}
>
<div className="flex flex-col">
<Tooltip>
<TooltipTriggerIfValid
className={"text-left select-text cursor-auto w-full"}
>
<p className="font-normal whitespace-pre">{project.name}</p>
<p className="font-normal opacity-50 text-sm whitespace-pre compact:hidden">
{project.path}
</p>
</TooltipTriggerIfValid>
<TooltipContent>{project.path}</TooltipContent>
</Tooltip>
</div>
</TooltipTriggerIfInvalid>
<TooltipPortal>
<TooltipContent>
{removed
? tc("projects:tooltip:no directory")
: tc("projects:tooltip:invalid project")}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</td>
<td className={noGrowCellClass}>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{projectTypeKind === "avatars" ? (
<CircleUserRound className={typeIconClass} />
) : projectTypeKind === "worlds" ? (
<Globe className={typeIconClass} />
) : (
<CircleHelp className={typeIconClass} />
)}
</div>
<div className="flex flex-col justify-center">
<p className="font-normal">{displayType}</p>
{isLegacy && (
<p className="font-normal opacity-50 dark:opacity-80 text-sm text-destructive">
{tc("projects:type:legacy")}
</p>
)}
</div>
</div>
</td>
<td className={noGrowCellClass}>
<p className="font-normal">{project.unity}</p>
</td>
<td className={noGrowCellClass}>
<Tooltip>
<TooltipTrigger>
<time dateTime={createdAt.toISOString()}>
<time className="font-normal">
{dayToString(project.created_at)}
</time>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{dateToString(project.created_at)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</td>
<td className={noGrowCellClass}>
<Tooltip>
<TooltipTrigger>
<time dateTime={lastModified.toISOString()}>
<time className="font-normal">
{formatDateOffset(project.last_modified)}
</time>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{dateToString(project.last_modified)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</td>
<td className={noGrowCellClass}>
<div className="flex flex-row gap-2 max-w-min items-center">
<ButtonDisabledIfInvalid asChild>
<OpenUnityButton
projectPath={project.path}
unityVersion={project.unity}
unityRevision={project.unity_revision}
/>
</ButtonDisabledIfInvalid>
<ManageOrMigrateButton project={project} />
<ButtonDisabledIfInvalid
onClick={async () => {
try {
await openSingleDialog(BackupProjectDialog, {
projectPath: project.path,
});
} catch (e) {
console.error(e);
toastThrownError(e);
}
}}
variant={"success"}
>
{tc("projects:backup")}
</ButtonDisabledIfInvalid>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size={"icon"}
className={
"hover:bg-primary/10 text-primary hover:text-primary"
}
>
<Ellipsis className={"size-5"} />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={openProjectFolder}
disabled={removed || loading}
>
{tc("projects:menuitem:open directory")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={onCopyProject}
disabled={removed || !(is_valid ?? true)}
>
{tc("projects:menuitem:copy project")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
openSingleDialog(RemoveProjectDialog, { project })
}
disabled={loading}
className={"text-destructive focus:text-destructive"}
>
{tc("projects:remove project")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</td>
</tr>
</ProjectContext.Provider>
);
}
export function ManageOrMigrateButton({ project }: { project: TauriProject }) {
const navigate = useNavigate();
if (compareUnityVersionString(project.unity, "2018.0.0f0") < 0) {
// No UPM is supported in unity 2017 or older
return (
<Tooltip>
<TooltipTriggerIfValid asChild>
<ButtonDisabledIfInvalid variant="success" disabled>
{tc("projects:button:manage")}
</ButtonDisabledIfInvalid>
</TooltipTriggerIfValid>
<TooltipContent>
{tc("projects:tooltip:no upm in unity")}
</TooltipContent>
</Tooltip>
);
}
switch (project.project_type) {
case "LegacySdk2":
return (
<Tooltip>
<TooltipTriggerIfValid asChild>
<ButtonDisabledIfInvalid variant="success" disabled>
{tc("projects:button:migrate")}
</ButtonDisabledIfInvalid>
</TooltipTriggerIfValid>
<TooltipContent>
{tc("projects:tooltip:sdk2 migration hint")}
</TooltipContent>
</Tooltip>
);
case "LegacyWorlds":
case "LegacyAvatars":
return (
<ButtonDisabledIfInvalid
variant={"success"}
onClick={() => void migrateVpm(project.path)}
>
{tc("projects:button:migrate")}
</ButtonDisabledIfInvalid>
);
case "UpmWorlds":
case "UpmAvatars":
case "UpmStarter":
return (
<Tooltip>
<TooltipTriggerIfValid asChild>
<ButtonDisabledIfInvalid variant="info" disabled>
{tc("projects:button:manage")}
</ButtonDisabledIfInvalid>
</TooltipTriggerIfValid>
<TooltipContent>
{tc("projects:tooltip:git-vcc not supported")}
</TooltipContent>
</Tooltip>
);
case "Unknown":
case "Worlds":
case "Avatars":
case "VpmStarter":
return (
<ButtonDisabledIfInvalid
onClick={() =>
navigate({
to: "/projects/manage",
search: { projectPath: project.path },
})
}
variant="info"
>
{tc("projects:button:manage")}
</ButtonDisabledIfInvalid>
);
}
}
type MigrationProjectBackupType = "none" | "copy" | "backupArchive";
async function migrateVpm(projectPath: string) {
if (await commands.projectIsUnityLaunching(projectPath)) {
toastError(tt("projects:toast:close unity before migration"));
return;
}
using dialog = showDialog();
const backupType = await dialog.ask(ConfirmVpmMigrationDialog, {});
if (backupType == null) return "";
let migrateProjectPath: string;
switch (backupType) {
case "none":
migrateProjectPath = projectPath;
break;
case "copy": {
migrateProjectPath = await dialog.ask(MigrationCopyingDialog, {
header: tc("projects:dialog:vpm migrate header"),
projectPath,
});
break;
}
case "backupArchive": {
const result = await dialog.ask(BackupProjectDialog, {
projectPath,
});
if (result === "cancelled") {
return;
}
migrateProjectPath = projectPath;
break;
}
default:
assertNever(backupType);
}
dialog.replace(<VpmMigrationUpdating />);
await commands.projectMigrateProjectToVpm(migrateProjectPath);
toastSuccess(tt("projects:toast:project migrated"));
await queryClient.invalidateQueries({
queryKey: ["environmentProjects"],
});
router.navigate({
to: "/projects/manage",
search: {
projectPath: migrateProjectPath,
},
});
}
function ConfirmVpmMigrationDialog({
dialog,
}: {
dialog: DialogContext<MigrationProjectBackupType | null>;
}) {
return (
<div className={"contents whitespace-normal"}>
<DialogTitle>{tc("projects:dialog:vpm migrate header")}</DialogTitle>
<div>
<p>{tc("projects:dialog:vpm migrate description")}</p>
</div>
<DialogFooter className={"gap-1"}>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close("backupArchive")}>
{tc("projects:button:backup and migrate")}
</Button>
<Button onClick={() => dialog.close("copy")}>
{tc("projects:button:migrate copy")}
</Button>
<Button onClick={() => dialog.close("none")} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</div>
);
}
function VpmMigrationUpdating() {
return (
<div className={"contents whitespace-normal"}>
<DialogTitle>{tc("projects:dialog:vpm migrate header")}</DialogTitle>
<div>
<p>{tc("projects:migrating...")}</p>
</div>
</div>
);
}
// region utilities
export const ProjectContext = React.createContext<{
removed: boolean;
is_valid: boolean | null;
loading: boolean;
}>({
removed: false,
is_valid: null,
loading: false,
});
export const ButtonDisabledIfInvalid = function RemovedButton(
props: React.ComponentProps<typeof Button>,
) {
const rowContext = useContext(ProjectContext);
if (rowContext.removed || !(rowContext.is_valid ?? true)) {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button
{...props}
className={`disabled:pointer-events-auto ${props.className}`}
disabled
/>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{rowContext.removed
? tc("projects:tooltip:no directory")
: tc("projects:tooltip:invalid project")}
</TooltipContent>
</TooltipPortal>
</Tooltip>
);
} else {
return (
<Button
{...props}
className={`disabled:pointer-events-auto ${props.className}`}
disabled={props.disabled || rowContext.loading || rowContext.removed}
/>
);
}
};
export const TooltipTriggerIfInvalid = ({
children,
...props
}: ComponentProps<typeof TooltipTrigger>) => {
const rowContext = useContext(ProjectContext);
if (rowContext.removed || !(rowContext.is_valid ?? true)) {
return <TooltipTrigger {...props}>{children}</TooltipTrigger>;
} else {
return children;
}
};
export const TooltipTriggerIfValid = ({
children,
...props
}: ComponentProps<typeof TooltipTrigger>) => {
const rowContext = useContext(ProjectContext);
if (rowContext.removed || !(rowContext.is_valid ?? true)) {
return children;
} else {
return <TooltipTrigger {...props}>{children}</TooltipTrigger>;
}
};
export function getProjectDisplayInfo(project: TauriProject) {
const projectTypeKind = ProjectDisplayType[project.project_type] ?? "unknown";
const displayType = tc(`projects:type:${projectTypeKind}`);
const isLegacy = LegacyProjectTypes.includes(project.project_type);
const createdAt = new Date(project.created_at);
const lastModified = new Date(project.last_modified);
return {
projectTypeKind,
displayType,
isLegacy,
createdAt,
lastModified,
};
}
export function useSetProjectFavoriteMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (project: Pick<TauriProject, "path" | "favorite">) =>
commands.environmentSetFavoriteProject(project.path, project.favorite),
onMutate: async (project) => {
await queryClient.cancelQueries(environmentProjects);
const previousData = queryClient.getQueryData<TauriProject[]>(
environmentProjects.queryKey,
);
if (previousData !== undefined) {
queryClient.setQueryData<TauriProject[]>(
environmentProjects.queryKey,
previousData.map((v) =>
v.path === project.path ? { ...v, favorite: project.favorite } : v,
),
);
}
return previousData;
},
onError: (error, _, context) => {
console.error("Error migrating project", error);
toastThrownError(error);
if (context) {
queryClient.setQueryData(environmentProjects.queryKey, context);
}
},
});
}
// endregion

View file

@ -0,0 +1,131 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { ArrowDown, ArrowUp } from "lucide-react";
import { useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import type { TauriProject } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { ProjectGridItem } from "./-project-grid-item";
import {
isSorting,
type sortings,
sortSearchProjects,
useSetProjectSortingMutation,
} from "./-projects-list-card";
type SimpleSorting = (typeof sortings)[number];
type Sorting = SimpleSorting | `${SimpleSorting}Reversed`;
const sortingOptions: { key: SimpleSorting; label: string }[] = [
{ key: "name", label: "general:name" },
{ key: "type", label: "projects:type" },
{ key: "unity", label: "projects:unity" },
{ key: "createdAt", label: "general:created at" },
{ key: "lastModified", label: "general:last modified" },
];
export function ProjectsGridCard({
projects,
search,
loading,
}: {
projects: TauriProject[];
search?: string;
loading?: boolean;
}) {
const sortingQuery = useQuery({
initialData: "lastModified" as Sorting,
queryKey: ["environmentGetProjectSorting"],
queryFn: async () => {
const newSorting = await commands.environmentGetProjectSorting();
return !isSorting(newSorting) ? "lastModified" : newSorting;
},
});
const setSortingStateMutation = useSetProjectSortingMutation();
const currentKey = sortingQuery.data.replace(
/Reversed$/,
"",
) as SimpleSorting;
const isReversed = sortingQuery.data.endsWith("Reversed");
const handleChangeSortingKey = (key: SimpleSorting) => {
const newSorting = isReversed ? `${key}Reversed` : key;
setSortingStateMutation.mutate({ sorting: newSorting as Sorting });
};
const toggleOrder = () => {
const newSorting: Sorting = isReversed
? currentKey
: `${currentKey}Reversed`;
setSortingStateMutation.mutate({ sorting: newSorting });
};
const projectsShown = useMemo(() => {
return sortSearchProjects(projects, search ?? "", sortingQuery.data);
}, [projects, search, sortingQuery.data]);
return (
<div className="flex flex-col h-full w-full overflow-hidden">
<Card className="flex items-center mb-3 flex-wrap p-2 gap-2 compact:p-1 compact:gap-1">
<p className="grow-0 whitespace-pre pl-2 leading-tight">
{tc("projects:sort by")}
</p>
<Select
value={currentKey}
onValueChange={(value) =>
handleChangeSortingKey(value as SimpleSorting)
}
>
<SelectTrigger className="w-40">
<SelectValue />
</SelectTrigger>
<SelectContent>
{sortingOptions.map((option) => (
<SelectItem key={option.key} value={option.key}>
{tc(option.label)}
</SelectItem>
))}
</SelectContent>
</Select>
<Button variant="ghost" size="icon" onClick={toggleOrder}>
{isReversed ? (
<ArrowUp className="size-4" />
) : (
<ArrowDown className="size-4" />
)}
</Button>
</Card>
<ScrollArea
type="auto"
className="h-full w-full vrc-get-scrollable-card rounded-l-xl"
scrollBarClassName="bg-background rounded-full border-l-0 p-[1.5px]"
>
<div
className="grid grid-cols-1 md:grid-cols-2 2xl:grid-cols-3 gap-3 overflow-x-hidden mr-4
compact:grid-cols-2 compact:lg:grid-cols-3 compact:2xl:grid-cols-4 compact:gap-1.5"
>
{projectsShown.map((project) => (
<ProjectGridItem
key={project.path}
project={project}
loading={loading}
/>
))}
</div>
</ScrollArea>
</div>
);
}

View file

@ -0,0 +1,280 @@
"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ChevronDown, ChevronsUpDown, ChevronUp, Star } from "lucide-react";
import { useMemo } from "react";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { assertNever } from "@/lib/assert-never";
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
import { compareUnityVersionString } from "@/lib/version";
import { ProjectRow } from "./-project-row";
export const sortings = [
"createdAt",
"lastModified",
"name",
"unity",
"type",
] as const;
type SimpleSorting = (typeof sortings)[number];
type Sorting = SimpleSorting | `${SimpleSorting}Reversed`;
export function isSorting(s: string | unknown): s is Sorting {
return sortings.some(
(sorting) => sorting === s || `${sorting}Reversed` === s,
);
}
export function compareProjectType(
a: TauriProjectType,
b: TauriProjectType,
): 0 | -1 | 1 {
if (a === b) return 0;
// legacy unknown
if (a === "LegacySdk2") return 1;
if (b === "LegacySdk2") return -1;
if (a === "UpmStarter") return 1;
if (b === "UpmStarter") return -1;
// legacy worlds
if (a === "LegacyWorlds") return 1;
if (b === "LegacyWorlds") return -1;
if (a === "UpmWorlds") return 1;
if (b === "UpmWorlds") return -1;
// legacy avatars
if (a === "LegacyAvatars") return 1;
if (b === "LegacyAvatars") return -1;
if (a === "UpmAvatars") return 1;
if (b === "UpmAvatars") return -1;
// unknown
if (a === "Unknown") return 1;
if (b === "Unknown") return -1;
if (a === "VpmStarter") return 1;
if (b === "VpmStarter") return -1;
// worlds
if (a === "Worlds") return 1;
if (b === "Worlds") return -1;
// avatars
if (a === "Avatars") return 1;
if (b === "Avatars") return -1;
assertNever(a, "project type");
}
export function ProjectsTableCard({
projects,
search,
loading,
}: {
projects: TauriProject[];
search?: string;
loading?: boolean;
}) {
const sortingQuery = useQuery({
initialData: "lastModified" as Sorting,
queryKey: ["environmentGetProjectSorting"],
queryFn: async () => {
const newSorting = await commands.environmentGetProjectSorting();
return !isSorting(newSorting) ? "lastModified" : newSorting;
},
});
const setSortingStateMutation = useSetProjectSortingMutation();
const projectsShown = useMemo(() => {
return sortSearchProjects(projects, search ?? "", sortingQuery.data);
}, [projects, search, sortingQuery.data]);
const thClass = "sticky top-0 z-10 border-b border-primary p-2.5";
const iconClass = "size-3 invisible project-table-header-chevron-up-down";
const setSorting = async (simpleSorting: SimpleSorting) => {
let newSorting: Sorting;
if (sortingQuery.data === simpleSorting) {
newSorting = `${simpleSorting}Reversed`;
} else if (sortingQuery.data === `${simpleSorting}Reversed`) {
newSorting = simpleSorting;
} else {
newSorting = simpleSorting;
}
setSortingStateMutation.mutate({ sorting: newSorting });
};
const headerBg = (target: SimpleSorting) =>
sortingQuery.data === target || sortingQuery.data === `${target}Reversed`
? "bg-primary text-primary-foreground"
: "bg-secondary text-secondary-foreground";
const icon = (target: SimpleSorting) =>
sortingQuery.data === target ? (
<ChevronDown className={"size-3"} />
) : sortingQuery.data === `${target}Reversed` ? (
<ChevronUp className={"size-3"} />
) : (
<ChevronsUpDown className={iconClass} />
);
return (
<ScrollableCardTable className={"h-full w-full"}>
<thead>
<tr>
<th className={`${thClass} bg-secondary text-secondary-foreground`}>
<Star className={"size-4"} />
</th>
<th className={`${thClass} ${headerBg("name")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("name")}
>
{icon("name")}
<small className="font-normal leading-none">
{tc("general:name")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("type")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("type")}
>
{icon("type")}
<small className="font-normal leading-none">
{tc("projects:type")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("unity")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("unity")}
>
{icon("unity")}
<small className="font-normal leading-none">
{tc("projects:unity")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("createdAt")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("createdAt")}
>
{icon("createdAt")}
<small className="font-normal leading-none">
{tc("general:created at")}
</small>
</button>
</th>
<th className={`${thClass} ${headerBg("lastModified")}`}>
<button
type="button"
className={"flex w-full project-table-button"}
onClick={() => setSorting("lastModified")}
>
{icon("lastModified")}
<small className="font-normal leading-none">
{tc("general:last modified")}
</small>
</button>
</th>
<th className={`${thClass} bg-secondary text-secondary-foreground`} />
</tr>
</thead>
<tbody>
{projectsShown.map((project) => (
<ProjectRow key={project.path} project={project} loading={loading} />
))}
</tbody>
</ScrollableCardTable>
);
}
export function sortSearchProjects(
projects: TauriProject[],
search: string,
sorting: Sorting,
): TauriProject[] {
const searched = projects.filter((project) =>
project.name.toLowerCase().includes(search?.toLowerCase() ?? ""),
);
searched.sort((a, b) => b.last_modified - a.last_modified);
switch (sorting) {
case "createdAt":
searched.sort((a, b) => b.created_at - a.created_at);
break;
case "createdAtReversed":
searched.sort((a, b) => a.created_at - b.created_at);
break;
case "lastModified":
searched.sort((a, b) => b.last_modified - a.last_modified);
break;
case "lastModifiedReversed":
searched.sort((a, b) => a.last_modified - b.last_modified);
break;
case "name":
searched.sort((a, b) => a.name.localeCompare(b.name));
break;
case "nameReversed":
searched.sort((a, b) => b.name.localeCompare(a.name));
break;
case "type":
searched.sort((a, b) =>
compareProjectType(a.project_type, b.project_type),
);
break;
case "typeReversed":
searched.sort((a, b) =>
compareProjectType(b.project_type, a.project_type),
);
break;
case "unity":
searched.sort((a, b) => compareUnityVersionString(a.unity, b.unity));
break;
case "unityReversed":
searched.sort((a, b) => compareUnityVersionString(b.unity, a.unity));
break;
default:
assertNever(sorting);
}
searched.sort((a, b) => {
if (a.favorite && !b.favorite) return -1;
if (!a.favorite && b.favorite) return 1;
return 0;
});
return searched;
}
export function useSetProjectSortingMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ sorting }: { sorting: Sorting }) => {
await commands.environmentSetProjectSorting(sorting);
},
onMutate: async ({ sorting }) => {
await queryClient.cancelQueries({
queryKey: ["environmentGetProjectSorting"],
});
queryClient.setQueryData(["environmentGetProjectSorting"], () => sorting);
},
onError: (error) => {
console.error("Error setting project sorting", error);
toastThrownError(error);
},
});
}

View file

@ -0,0 +1,280 @@
"use client";
import {
queryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { ChevronDown, LayoutGrid, LayoutList, RefreshCw } from "lucide-react";
import { useRef, useState } from "react";
import { createProject } from "@/app/_main/projects/-create-project";
import { ProjectsGridCard } from "@/app/_main/projects/-projects-grid-card";
import Loading from "@/app/-loading";
import { HNavBar, HNavBarText, VStack } from "@/components/layout";
import { SearchBox } from "@/components/SearchBox";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { assertNever } from "@/lib/assert-never";
import { commands } from "@/lib/bindings";
import { isFindKey, useDocumentEvent } from "@/lib/events";
import { useProjectUpdateInProgress } from "@/lib/global-events";
import { tc, tt } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { ProjectsTableCard } from "./-projects-list-card";
export const Route = createFileRoute("/_main/projects/")({
component: Page,
});
const environmentProjects = queryOptions({
queryKey: ["environmentProjects"],
queryFn: commands.environmentProjects,
});
function Page() {
const result = useQuery(environmentProjects);
const [search, setSearch] = useState("");
const viewModeQuery = useQuery({
initialData: "List",
queryKey: ["environmentGetProjectViewMode"],
queryFn: async () => {
return await commands.environmentProjectViewMode();
},
});
const queryClient = useQueryClient();
const setViewModeMutation = useMutation({
mutationFn: async (value: string) => {
await commands.environmentSetProjectViewMode(value);
},
onMutate: async (value: string) => {
await queryClient.setQueryData(["environmentGetProjectViewMode"], value);
},
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ["environmentGetProjectViewMode"],
});
},
});
const viewMode = viewModeQuery.data ?? true;
const setViewMode = (value: string) => {
setViewModeMutation.mutate(value);
};
const startCreateProject = () => void createProject();
const loading = result.isFetching;
return (
<VStack>
<ProjectViewHeader
startCreateProject={startCreateProject}
isLoading={loading}
search={search}
setSearch={setSearch}
viewMode={viewMode}
setViewMode={setViewMode}
/>
<main className="shrink overflow-hidden flex w-full h-full">
{result.status === "pending" ? (
<Card className="w-full shadow-none overflow-hidden p-4">
<Loading loadingText={tc("general:loading...")} />
</Card>
) : result.status === "error" ? (
<Card className="w-full shadow-none overflow-hidden p-4">
{tc("projects:error:load error", { msg: result.error.message })}
</Card>
) : viewMode === "List" ? (
<ProjectsTableCard
projects={result.data}
search={search}
loading={loading}
/>
) : viewMode === "Grid" ? (
<ProjectsGridCard
projects={result.data}
search={search}
loading={loading}
/>
) : (
<ProjectsTableCard
projects={result.data}
search={search}
loading={loading}
/>
)}
</main>
</VStack>
);
}
function ProjectViewHeader({
startCreateProject,
isLoading,
search,
setSearch,
viewMode,
setViewMode,
}: {
startCreateProject?: () => void;
isLoading?: boolean;
search: string;
setSearch: (search: string) => void;
viewMode: string;
setViewMode: (viewMode: string) => void;
}) {
const queryClient = useQueryClient();
const addProjectWithPicker = useMutation({
mutationFn: async () => await commands.environmentAddProjectWithPicker(),
onSuccess: (result) => {
switch (result) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tt("projects:toast:project added"));
break;
case "AlreadyAdded":
toastError(tt("projects:toast:project already exists"));
break;
default:
assertNever(result);
}
},
onError: (e) => {
console.error("Error adding project", e);
toastThrownError(e);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentProjects);
},
});
const inProgress = useProjectUpdateInProgress();
const searchRef = useRef<HTMLInputElement>(null);
useDocumentEvent(
"keydown",
(e) => {
if (isFindKey(e)) {
searchRef.current?.focus();
}
},
[],
);
isLoading = isLoading || inProgress;
return (
<HNavBar
className="shrink-0"
leading={
<>
<HNavBarText>{tc("projects")}</HNavBarText>
<Tooltip>
<TooltipTrigger asChild>
<Button
className={"compact:h-10 compact:w-10"}
variant={"ghost"}
size={"icon"}
onClick={() =>
queryClient.invalidateQueries(environmentProjects)
}
disabled={isLoading}
>
{isLoading ? (
<RefreshCw className="w-5 h-5 animate-spin" />
) : (
<RefreshCw className={"w-5 h-5"} />
)}
</Button>
</TooltipTrigger>
<TooltipContent>{tc("projects:tooltip:refresh")}</TooltipContent>
</Tooltip>
<SearchBox
className={"w-max grow compact:h-10"}
value={search}
onChange={(e) => setSearch(e.target.value)}
ref={searchRef}
/>
<Button
className={"compact:h-10"}
variant={"ghost"}
onClick={() => {
if (viewMode === "List") {
setViewMode("Grid");
} else {
setViewMode("List");
}
}}
>
{viewMode === "List" ? (
<>
<LayoutList className={"w-5 h-5"} />
<p className="ml-2">{tc("projects:list view")}</p>
</>
) : viewMode === "Grid" ? (
<>
<LayoutGrid className={"w-5 h-5"} />
<p className="ml-2">{tc("projects:grid view")}</p>
</>
) : (
<>
<LayoutList className={"w-5 h-5"} />
<p className="ml-2">{tc("projects:list view")}</p>
</>
)}
</Button>
</>
}
trailing={
<DropdownMenu>
<div className={"flex divide-x"}>
<Button
className={"rounded-r-none pl-4 pr-3 compact:h-10"}
onClick={startCreateProject}
>
{tc("projects:create new project")}
</Button>
<DropdownMenuTrigger
asChild
className={"rounded-l-none pl-2 pr-2 compact:h-10"}
>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => addProjectWithPicker.mutate()}>
{tc("projects:add existing project")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
}
/>
);
}

View file

@ -6,6 +6,7 @@ import type {
TauriUserRepository,
TauriVersion,
} from "@/lib/bindings";
import { VRCSDK_PACKAGES } from "@/lib/constants";
import {
compareUnityVersion,
compareVersion,
@ -27,30 +28,33 @@ export type PackageLatestInfo =
hasUnityIncompatibleLatest: boolean;
};
type UrlInfo = {
// null source means URL comes from installed one which has the highest priority
url: string;
source: TauriVersion | null;
};
export interface PackageRowInfo {
id: string;
infoSource: TauriVersion;
displayName: string;
description: string;
aliases: string[];
keywords: string[];
unityCompatible: Map<string, TauriPackage>;
unityIncompatible: Map<string, TauriPackage>;
sources: Set<string>;
isThereSource: boolean; // this will be true even if all sources are hidden
visibleSources: Set<string>;
installed: null | {
version: TauriVersion;
yanked: boolean;
};
latest: PackageLatestInfo;
stableLatest: PackageLatestInfo;
changelogUrl: null | UrlInfo;
documentationUrl: null | UrlInfo;
}
export const VRCSDK_PACKAGES = [
"com.vrchat.avatars",
"com.vrchat.worlds",
"com.vrchat.base",
];
export function combinePackagesAndProjectDetails(
packages: TauriPackage[],
project: TauriProjectDetails | null,
@ -89,7 +93,9 @@ export function combinePackagesAndProjectDetails(
const yankedVersions = new Set<`${string}:${string}`>();
const knownPackages = new Set<string>();
const packagesPerRepository = new Map<string, TauriPackage[]>();
const hiddenPackagesPerRepository = new Map<string, TauriPackage[]>();
const userPackages: TauriPackage[] = [];
const hiddenUserPackages: TauriPackage[] = [];
for (const pkg of packages) {
if (!showPrereleasePackages && pkg.version.pre) continue;
@ -104,13 +110,19 @@ export function combinePackagesAndProjectDetails(
let packages: TauriPackage[];
// check the repository is visible
if (pkg.source === "LocalUser") {
if (hideLocalUserPackages) continue;
packages = userPackages;
if (hideLocalUserPackages) {
packages = hiddenUserPackages;
} else {
packages = userPackages;
}
} else if ("Remote" in pkg.source) {
if (hiddenRepositoriesSet.has(pkg.source.Remote.id)) continue;
packages = packagesPerRepository.get(pkg.source.Remote.id) ?? [];
packagesPerRepository.set(pkg.source.Remote.id, packages);
if (hiddenRepositoriesSet.has(pkg.source.Remote.id)) {
packages = hiddenPackagesPerRepository.get(pkg.source.Remote.id) ?? [];
hiddenPackagesPerRepository.set(pkg.source.Remote.id, packages);
} else {
packages = packagesPerRepository.get(pkg.source.Remote.id) ?? [];
packagesPerRepository.set(pkg.source.Remote.id, packages);
}
} else {
assertNever(pkg.source);
}
@ -129,15 +141,18 @@ export function combinePackagesAndProjectDetails(
id: pkg.name,
displayName: pkg.display_name ?? pkg.name,
description: pkg.description ?? "",
aliases: pkg.aliases,
keywords: pkg.keywords,
infoSource: pkg.version,
unityCompatible: new Map(),
unityIncompatible: new Map(),
sources: new Set(),
isThereSource: false,
visibleSources: new Set(),
installed: null,
latest: { status: "none" },
stableLatest: { status: "none" },
changelogUrl: null,
documentationUrl: null,
}),
);
}
@ -148,13 +163,21 @@ export function combinePackagesAndProjectDetails(
const packageRowInfo = getRowInfo(pkg);
packageRowInfo.isThereSource = true;
setUrlInfo(packageRowInfo, "changelogUrl", pkg.changelog_url, pkg.version);
setUrlInfo(
packageRowInfo,
"documentationUrl",
pkg.documentation_url,
pkg.version,
);
if (compareVersion(pkg.version, packageRowInfo.infoSource) > 0) {
// use display name from the latest version
packageRowInfo.infoSource = pkg.version;
packageRowInfo.displayName = pkg.display_name ?? pkg.name;
packageRowInfo.description =
pkg.description || packageRowInfo.description;
packageRowInfo.aliases = pkg.aliases;
packageRowInfo.keywords = pkg.keywords;
}
if (project == null || isUnityCompatible(pkg, project.unity)) {
@ -165,8 +188,14 @@ export function combinePackagesAndProjectDetails(
if (pkg.source === "LocalUser") {
packageRowInfo.sources.add("User");
if (!hideLocalUserPackages) {
packageRowInfo.visibleSources.add("User");
}
} else if ("Remote" in pkg.source) {
packageRowInfo.sources.add(pkg.source.Remote.display_name);
if (!hiddenRepositoriesSet.has(pkg.source.Remote.id)) {
packageRowInfo.visibleSources.add(pkg.source.Remote.display_name);
}
}
}
@ -174,6 +203,13 @@ export function combinePackagesAndProjectDetails(
packagesPerRepository.get("com.vrchat.repos.official")?.forEach(addPackage);
packagesPerRepository.get("com.vrchat.repos.curated")?.forEach(addPackage);
userPackages.forEach(addPackage);
hiddenUserPackages.forEach((pkg) => {
const packageRowInfo = getRowInfo(pkg);
packageRowInfo.isThereSource = true;
if (pkg.source === "LocalUser") {
packageRowInfo.sources.add("User");
}
});
packagesPerRepository.delete("com.vrchat.repos.official");
packagesPerRepository.delete("com.vrchat.repos.curated");
@ -188,6 +224,17 @@ export function combinePackagesAndProjectDetails(
packages.forEach(addPackage);
}
// process hidden repositories - only add to sources, not to version calculations
for (const packages of hiddenPackagesPerRepository.values()) {
packages.forEach((pkg) => {
const packageRowInfo = getRowInfo(pkg);
packageRowInfo.isThereSource = true;
if (pkg.source !== "LocalUser") {
packageRowInfo.sources.add(pkg.source.Remote.display_name);
}
});
}
// sort versions
for (const value of packagesTable.values()) {
value.unityCompatible = new Map(
@ -269,16 +316,24 @@ export function combinePackagesAndProjectDetails(
for (const [_, pkg] of project.installed_packages) {
const packageRowInfo = getRowInfo(pkg);
setUrlInfo(packageRowInfo, "changelogUrl", pkg.changelog_url, null);
setUrlInfo(
packageRowInfo,
"documentationUrl",
pkg.documentation_url,
null,
);
// if installed, use the installed version to get the display name
packageRowInfo.displayName = pkg.display_name ?? pkg.name;
packageRowInfo.aliases = [...pkg.aliases, ...packageRowInfo.aliases];
packageRowInfo.keywords = [...pkg.keywords, ...packageRowInfo.keywords];
packageRowInfo.installed = {
version: pkg.version,
yanked:
pkg.is_yanked ||
yankedVersions.has(`${pkg.name}:${toVersionString(pkg.version)}`),
};
packageRowInfo.isThereSource = knownPackages.has(pkg.name);
packageRowInfo.isThereSource = true;
// if we have the latest version, check if it's upgradable
if (packageRowInfo.latest.status !== "none") {
@ -375,3 +430,25 @@ export function combinePackagesAndProjectDetails(
return asArray;
}
function setUrlInfo<K extends string>(
obj: { [P in K]: null | UrlInfo },
key: K,
url: string | null,
version: TauriVersion | null,
) {
if (url == null) return;
const current = obj[key];
if (current == null) {
obj[key] = { url, source: version };
} else {
if (version == null) {
obj[key] = { url, source: version };
} else if (current.source == null) {
// do not update
} else if (compareVersion(current.source, version) < 0) {
// if this version is newer than current, update
obj[key] = { url, source: version };
}
}
}

View file

@ -0,0 +1,214 @@
import { useMutation } from "@tanstack/react-query";
import type { NavigateFn } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { VStack } from "@/components/layout";
import { Button } from "@/components/ui/button";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Progress } from "@/components/ui/progress";
import { assertNever } from "@/lib/assert-never";
import { commands, type TauriCopyProjectProgress } from "@/lib/bindings";
import { callAsyncCommand } from "@/lib/call-async-command";
import { type DialogContext, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { directoryFromPath, nameFromPath, pathSeparator } from "@/lib/os";
import {
ProjectNameCheckResult,
useProjectNameCheck,
} from "@/lib/project-name-check";
import { queryClient } from "@/lib/query-client";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
export async function copyProject(existingPath: string, navigate?: NavigateFn) {
using dialog = showDialog();
const newPath = await dialog.ask(CopyProjectNameDialog, {
projectPath: existingPath,
});
if (newPath == null) return; // cancelled
await dialog.ask(CopyingDialog, {
projectPath: existingPath,
newProjectPath: newPath,
});
dialog.close();
toastSuccess(
tc("projects:toast:successfully copied project", {
name: nameFromPath(existingPath),
}),
);
await Promise.all([
queryClient.invalidateQueries({
queryKey: ["projectDetails", existingPath],
}),
queryClient.invalidateQueries({
queryKey: ["environmentProjects"],
}),
]);
await navigate?.({
replace: true,
to: "/projects/manage",
search: { projectPath: newPath },
});
}
function CopyProjectNameDialog({
dialog,
projectPath,
}: {
dialog: DialogContext<string | null>;
projectPath: string;
}) {
const oldName = nameFromPath(projectPath);
const [projectNameRaw, setProjectName] = useState(`${oldName}-Copy`);
const projectName = projectNameRaw.trim();
const [projectLocation, setProjectLocation] = useState(
directoryFromPath(projectPath),
);
const projectNameCheckState = useProjectNameCheck(
projectLocation,
projectName,
);
const usePickProjectLocationPath = useMutation({
mutationFn: () => commands.utilPickDirectory(projectLocation),
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("general:toast:invalid directory"));
break;
case "Successful":
setProjectLocation(result.new_path);
break;
default:
assertNever(result);
}
},
onError: (e) => {
console.error(e);
toastThrownError(e);
},
});
const createProject = async () => {
dialog.close(`${projectLocation}${pathSeparator()}${projectName}`);
};
const badProjectName = ["AlreadyExists", "InvalidNameForFolderName"].includes(
projectNameCheckState,
);
const canCreateProject =
projectNameCheckState !== "checking" && !badProjectName;
return (
<>
<DialogTitle>
{tc("projects:dialog:copy project", { name: oldName })}
</DialogTitle>
<div>
<VStack>
<Input
value={projectNameRaw}
onChange={(e) => setProjectName(e.target.value)}
/>
<div className={"flex gap-1 items-center"}>
<Input className="flex-auto" value={projectLocation} disabled />
<Button
className="flex-none px-4"
onClick={() => usePickProjectLocationPath.mutate()}
>
{tc("general:button:select")}
</Button>
</div>
<small className={"whitespace-normal"}>
{tc(
"projects:hint:path of creating project",
{ path: `${projectLocation}${pathSeparator()}${projectName}` },
{
components: {
path: (
<span
className={
"p-0.5 font-path whitespace-pre bg-secondary text-secondary-foreground"
}
/>
),
},
},
)}
</small>
<ProjectNameCheckResult
projectNameCheckState={projectNameCheckState}
/>
</VStack>
</div>
<DialogFooter className={"gap-2"}>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={createProject} disabled={!canCreateProject}>
{tc("projects:button:create")}
</Button>
</DialogFooter>
</>
);
}
export function CopyingDialog({
projectPath,
newProjectPath,
dialog,
}: {
projectPath: string;
newProjectPath: string;
dialog: DialogContext<string>;
}) {
const oldName = nameFromPath(projectPath);
const [progress, setProgress] = useState<TauriCopyProjectProgress>({
proceed: 0,
total: 1,
last_proceed: "Collecting files...",
});
useEffect(() => {
const [_, promise] = callAsyncCommand(
commands.environmentCopyProject,
[projectPath, newProjectPath],
(progress) => {
setProgress((prev) => {
if (prev.proceed > progress.proceed) return prev;
return progress;
});
},
);
promise.then(dialog.close, dialog.error);
}, [projectPath, newProjectPath, dialog.close, dialog.error]);
return (
<>
<DialogTitle>
{tc("projects:dialog:copy project", { name: oldName })}
</DialogTitle>
<div>
<p>{tc("projects:dialog:copying...")}</p>
<p>
{tc("projects:dialog:proceed k/n", {
count: progress.proceed,
total: progress.total,
})}
</p>
<Progress value={progress.proceed} max={progress.total} />
<p>{tc("projects:do not close")}</p>
</div>
<DialogFooter className={"gap-2"}>
<Button disabled>{tc("general:button:cancel")}</Button>
</DialogFooter>
</>
);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
import { type ComponentProps, createContext, useContext } from "react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
interface PageContext {
isLoading: boolean;
}
export const PageContext = createContext<PageContext>({
isLoading: false,
});
PageContext.displayName = "PageContext";
export const PageContextProvider = PageContext.Provider;
export function usePageContext() {
return useContext(PageContext);
}
export const ButtonDisabledIfLoading = function ButtonDisabledIfLoading({
disabled,
...props
}: ComponentProps<typeof Button>) {
const { isLoading } = usePageContext();
return <Button disabled={isLoading || disabled} {...props} />;
};
export const DropdownMenuItemDisabledIfLoading =
function ButtonDisabledIfLoading({
disabled,
...props
}: ComponentProps<typeof DropdownMenuItem>) {
const { isLoading } = usePageContext();
return <DropdownMenuItem disabled={isLoading || disabled} {...props} />;
};
export const CheckboxDisabledIfLoading = function CheckboxDisabledIfLoading({
disabled,
...props
}: ComponentProps<typeof Checkbox>) {
const { isLoading } = usePageContext();
return <Checkbox disabled={isLoading || disabled} {...props} />;
};

View file

@ -0,0 +1,583 @@
import type { NavigateFn } from "@tanstack/react-router";
import React, { Fragment, useEffect, useState } from "react";
import { BackupProjectDialog } from "@/components/BackupProjectDialog";
import { Button } from "@/components/ui/button";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { UnitySelectorDialog } from "@/components/unity-selector-dialog";
import { assertNever } from "@/lib/assert-never";
import type {
TauriCallUnityForMigrationResult,
TauriCopyProjectProgress,
TauriUnityVersions,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { callAsyncCommand } from "@/lib/call-async-command";
import { VRCSDK_UNITY_VERSIONS } from "@/lib/constants";
import { type DialogContext, openSingleDialog, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { queryClient } from "@/lib/query-client";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { compareUnityVersionString, parseUnityVersion } from "@/lib/version";
export async function unityVersionChange({
version: targetUnityVersion,
currentUnityVersion,
isVRCProject,
mayUseChinaVariant = false,
projectPath,
navigate,
}: {
version: string;
currentUnityVersion: string;
isVRCProject: boolean;
mayUseChinaVariant?: boolean;
projectPath: string;
navigate: NavigateFn;
}) {
try {
const data = detectChangeUnityKind(
currentUnityVersion,
targetUnityVersion,
isVRCProject,
);
if (await commands.projectIsUnityLaunching(projectPath)) {
toastError(tt("projects:toast:close unity before migration"));
return;
}
const header = headerText(data);
const unityVersions = await commands.environmentUnityVersions();
const findResult = findUnityForUnityChange(
unityVersions,
targetUnityVersion,
mayUseChinaVariant,
);
if (!findResult.found) {
await openSingleDialog(NoExactUnity2022Dialog, {
expectedVersion: targetUnityVersion,
installWithUnityHubLink: findResult.installLink,
header,
});
return;
}
using dialog = showDialog();
let backupTypePromise: Promise<ProjectBackupType | null>;
if (data.isVRC && data.isTargetVersionSupportedByVRC) {
// for supported migrations, show dialog same as migration
switch (data.kind) {
case "upgradePatchOrMinor":
backupTypePromise = dialog.ask(MigrationConfirmMigrationPatchDialog, {
header,
unity: targetUnityVersion,
});
break;
case "upgradeMajor":
backupTypePromise = dialog.ask(MigrationConfirmMigrationDialog, {
header,
});
}
}
backupTypePromise ??= dialog.ask(UnityVersionChange, {
data,
header,
});
const backupType = await backupTypePromise;
if (backupType == null) return;
let unityPath: string;
if (findResult.installations.length === 1) {
unityPath = findResult.installations[0][0];
} else {
const selected = await dialog.ask(UnitySelectorDialog, {
unityVersions: findResult.installations,
});
if (selected == null) return;
unityPath = selected.unityPath;
}
let migrateProjectPath: string;
switch (backupType) {
case "none":
migrateProjectPath = projectPath;
break;
case "copy": {
migrateProjectPath = await dialog.ask(MigrationCopyingDialog, {
projectPath,
header,
});
break;
}
case "backupArchive": {
const result = await dialog.ask(BackupProjectDialog, {
projectPath,
header,
});
if (result === "cancelled") return;
migrateProjectPath = projectPath;
break;
}
default:
assertNever(backupType);
}
dialog.replace(<MigrationMigratingDialog header={header} />);
if (
data.isVRC &&
data.kind === "upgradeMajor" &&
targetUnityVersion.startsWith("2022.")
) {
await commands.projectMigrateProjectTo2022(migrateProjectPath);
}
const finalizeResult = await dialog.askClosing(
MigrationCallingUnityForMigrationDialog,
{
unityPath,
migrateProjectPath,
header,
},
);
if (finalizeResult === "cancelled") {
throw new Error("unexpectedly cancelled");
}
switch (finalizeResult.type) {
case "ExistsWithNonZero":
toastError(tt("projects:toast:unity exits with non-zero"));
break;
case "FinishedSuccessfully":
toastSuccess(tt("projects:toast:unity migrated"));
break;
default:
assertNever(finalizeResult);
}
await Promise.all([
queryClient.invalidateQueries({
queryKey: ["projectDetails", projectPath],
}),
queryClient.invalidateQueries({
queryKey: ["environmentProjects"],
}),
]);
if (migrateProjectPath !== projectPath) {
await navigate({
replace: true,
to: "/projects/manage",
search: { projectPath: migrateProjectPath },
});
}
} catch (e) {
console.error(e);
toastThrownError(e);
}
}
function headerText(data: ChangeUnityData) {
if (data.isVRC && data.isTargetVersionSupportedByVRC) {
switch (data.kind) {
case "upgradePatchOrMinor":
case "upgradeMajor":
return tc("projects:manage:dialog:unity migrate header");
}
}
return tc("projects:manage:dialog:unity change version header");
}
function NoExactUnity2022Dialog({
expectedVersion,
installWithUnityHubLink,
dialog,
header,
}: {
expectedVersion: string;
installWithUnityHubLink?: string;
dialog: DialogContext<void>;
header: React.ReactNode;
}) {
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p>
{tc(
"projects:manage:dialog:exact version unity not found for patch migration description",
{ unity: expectedVersion },
)}
</p>
</div>
<DialogFooter className={"gap-2"}>
{installWithUnityHubLink && (
<Button
onClick={() => void commands.utilOpenUrl(installWithUnityHubLink)}
>
{tc("projects:dialog:open unity hub")}
</Button>
)}
<Button onClick={() => dialog.close()} className="mr-1">
{tc("general:button:close")}
</Button>
</DialogFooter>
</>
);
}
function MigrationConfirmMigrationPatchDialog({
unity,
dialog,
header,
}: {
unity: string;
dialog: DialogContext<ProjectBackupType | null>;
header: React.ReactNode;
}) {
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p className={"text-destructive"}>
{tc("projects:dialog:migrate unity2022 patch description", { unity })}
</p>
</div>
<DialogFooter>
<Button onClick={() => dialog.close(null)} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close("none")} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</>
);
}
function MigrationConfirmMigrationDialog({
dialog,
header,
}: {
dialog: DialogContext<ProjectBackupType | null>;
header: React.ReactNode;
}) {
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p>{tc("projects:dialog:vpm migrate description")}</p>
</div>
<DialogFooter className={"gap-1"}>
<Button onClick={() => dialog.close(null)}>
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close("backupArchive")}>
{tc("projects:button:backup and migrate")}
</Button>
<Button onClick={() => dialog.close("copy")}>
{tc("projects:button:migrate copy")}
</Button>
<Button onClick={() => dialog.close("none")} variant={"destructive"}>
{tc("projects:button:migrate in-place")}
</Button>
</DialogFooter>
</>
);
}
function UnityVersionChange({
data,
dialog,
header,
}: {
data: ChangeUnityData;
dialog: DialogContext<ProjectBackupType | null>;
header: React.ReactNode;
}) {
let mainMessage: React.ReactNode;
if (data.kind === "changeChina") {
mainMessage = tc("projects:manage:dialog:changing china releases");
} else {
const category = {
downgradeMajor: "downgrade major",
downgradePatchOrMinor: "downgrade minor",
upgradePatchOrMinor: "upgrade minor",
upgradeMajor: "upgrade major",
}[data.kind];
if (data.isVRC) {
if (data.isTargetVersionSupportedByVRC) {
mainMessage = tc([
`projects:manage:dialog:${category} vrchat supported`,
`projects:manage:dialog:${category}`,
]);
} else {
mainMessage = tc([
`projects:manage:dialog:${category} vrchat unsupported`,
`projects:manage:dialog:${category}`,
]);
}
} else {
mainMessage = tc(`projects:manage:dialog:${category}`);
}
}
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p className={"text-destructive"}>{mainMessage}</p>
</div>
<DialogFooter>
<Button onClick={() => dialog.close(null)} className="mr-1">
{tc("general:button:cancel")}
</Button>
<Button onClick={() => dialog.close("none")} variant={"destructive"}>
{tc("projects:button:change unity version")}
</Button>
</DialogFooter>
</>
);
}
export function MigrationCopyingDialog({
projectPath,
dialog,
header,
}: {
projectPath: string;
dialog: DialogContext<string>;
header: React.ReactNode;
}) {
const [progress, setProgress] = useState<TauriCopyProjectProgress>({
proceed: 0,
total: 1,
last_proceed: "Collecting files...",
});
useEffect(() => {
const [_, promise] = callAsyncCommand(
commands.environmentCopyProjectForMigration,
[projectPath],
(progress) => {
setProgress((prev) => {
if (prev.proceed > progress.proceed) return prev;
return progress;
});
},
);
promise.then(dialog.close, dialog.error);
}, [projectPath, dialog.close, dialog.error]);
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p>{tc("projects:pre-migrate copying...")}</p>
<p>
{tc("projects:dialog:proceed k/n", {
count: progress.proceed,
total: progress.total,
})}
</p>
<Progress value={progress.proceed} max={progress.total} />
<p>{tc("projects:do not close")}</p>
</div>
</>
);
}
function MigrationMigratingDialog({ header }: { header: React.ReactNode }) {
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p>{tc("projects:migrating...")}</p>
<p>{tc("projects:do not close")}</p>
</div>
</>
);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type UnityInstallation = [path: string, version: string, fromHub: boolean];
type FindUnityResult = FindUnityFoundResult | FindUnityNotFoundResult;
type ProjectBackupType = "none" | "copy" | "backupArchive";
interface FindUnityFoundResult {
found: true;
installations: UnityInstallation[];
}
interface FindUnityNotFoundResult {
installLink?: string;
found: false;
}
type ChangeUnityKind =
| "changeChina" // Changing between 'c' releases and non 'c' releases
| "downgradeMajor"
| "downgradePatchOrMinor"
| "upgradePatchOrMinor"
| "upgradeMajor";
type ChangeUnityData =
| {
kind: ChangeUnityKind;
isVRC: false;
}
| {
kind: ChangeUnityKind;
isVRC: true;
isTargetVersionSupportedByVRC: boolean;
};
function detectChangeUnityKind(
currentVersion: string,
targetUnityVersion: string,
isVRCProject: boolean,
): ChangeUnityData {
// biome-ignore lint/style/noNonNullAssertion: the version is known to be valid
const parsedCurrent = parseUnityVersion(currentVersion)!;
// biome-ignore lint/style/noNonNullAssertion: the version is known to be valid
const parsedTarget = parseUnityVersion(targetUnityVersion)!;
const cmp = compareUnityVersionString(currentVersion, targetUnityVersion);
const majorOrMinor =
parsedCurrent.major === parsedTarget.major ? "PatchOrMinor" : "Major";
const kind: ChangeUnityData["kind"] =
cmp === 0
? "changeChina"
: cmp > 0
? `downgrade${majorOrMinor}`
: `upgrade${majorOrMinor}`;
if (isVRCProject) {
return {
kind,
isVRC: true,
isTargetVersionSupportedByVRC:
VRCSDK_UNITY_VERSIONS.includes(targetUnityVersion),
};
} else {
return {
kind,
isVRC: false,
};
}
}
function findUnityForUnityChange(
unityVersions: TauriUnityVersions,
targetUnityVersion: string,
mayUseChinaVariant: boolean,
): FindUnityResult {
let foundVersions = unityVersions.unity_paths.filter(
([_p, v, _]) => v === targetUnityVersion,
);
// if international version not found, try to find china version
if (
foundVersions.length === 0 &&
mayUseChinaVariant &&
parseUnityVersion(targetUnityVersion)?.chinaIncrement == null
) {
const chinaVersion = `${targetUnityVersion}c1`;
foundVersions = unityVersions.unity_paths.filter(
([_p, v, _]) => v === chinaVersion,
);
}
if (foundVersions.length === 0) {
if (
compareUnityVersionString(
targetUnityVersion,
unityVersions.recommended_version,
) === 0
) {
return {
// This is using link to international version but china version of hub will handle international to china conversion
installLink: unityVersions.install_recommended_version_link,
found: false,
};
} else {
return {
found: false,
};
}
}
return {
found: true,
installations: foundVersions,
};
}
function MigrationCallingUnityForMigrationDialog({
unityPath,
migrateProjectPath,
dialog,
header,
}: {
unityPath: string;
migrateProjectPath: string;
dialog: DialogContext<"cancelled" | TauriCallUnityForMigrationResult>;
header: React.ReactNode;
}) {
const [lines, setLines] = useState<[number, string][]>([]);
useEffect(() => {
let lineNumber = 0;
const [, promise] = callAsyncCommand(
commands.projectCallUnityForMigration,
[migrateProjectPath, unityPath],
(lineString) => {
setLines((prev) => {
lineNumber++;
const line: [number, string] = [lineNumber, lineString];
if (prev.length > 200) {
return [...prev.slice(1), line];
} else {
return [...prev, line];
}
});
},
);
promise.then(dialog.close, dialog.error);
}, [migrateProjectPath, unityPath, dialog]);
const ref = React.useRef<HTMLDivElement>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: we want to scroll to bottom on lines changed
React.useEffect(() => {
ref.current?.scrollIntoView({ behavior: "auto" });
}, [lines]);
return (
<>
<DialogTitle>{header}</DialogTitle>
<div>
<p>{tc("projects:manage:dialog:unity migrate finalizing...")}</p>
<p>{tc("projects:do not close")}</p>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<pre
className={
"overflow-y-auto h-[50vh] bg-secondary text-secondary-foreground text-sm"
}
>
{lines.map(([lineNumber, line]) => (
<Fragment key={lineNumber}>
{line}
{"\n"}
</Fragment>
))}
<div ref={ref} />
</pre>
</div>
</>
);
}

View file

@ -0,0 +1,796 @@
import type { DefaultError } from "@tanstack/query-core";
import { queryOptions, type UseMutationOptions } from "@tanstack/react-query";
import { CircleAlert } from "lucide-react";
import type React from "react";
import { Fragment } from "react";
import { DelayedButton } from "@/components/DelayedButton";
import { ExternalLink } from "@/components/ExternalLink";
import { Button } from "@/components/ui/button";
import {
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { assertNever } from "@/lib/assert-never";
import type {
TauriBasePackageInfo,
TauriPackage,
TauriPackageChange,
TauriPendingProjectChanges,
TauriVersion,
} from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { type DialogContext, openSingleDialog } from "@/lib/dialog";
import { isHandleable } from "@/lib/errors";
import { tc, tt } from "@/lib/i18n";
import { queryClient } from "@/lib/query-client";
import { toastInfo, toastSuccess, toastThrownError } from "@/lib/toast";
import { groupBy, keyComparator } from "@/lib/utils";
import { compareVersion, toVersionString } from "@/lib/version";
export type RequestedOperation =
| {
type: "install";
pkg: TauriPackage;
hasUnityIncompatibleLatest?: boolean;
}
| {
type: "upgradeAll";
hasUnityIncompatibleLatest: boolean;
packages: TauriPackage[];
}
| {
type: "resolve";
}
| {
type: "reinstallAll";
}
| {
type: "remove";
displayName: string;
packageId: string;
}
| {
type: "bulkInstalled";
hasUnityIncompatibleLatest: boolean;
packages: TauriPackage[];
}
| {
type: "bulkReinstalled";
packageIds: string[];
}
| {
type: "bulkRemoved";
packageIds: string[];
};
function environmentPackages(projectPath: string) {
return queryOptions({
queryKey: ["projectDetails", projectPath],
queryFn: () => commands.projectDetails(projectPath),
refetchOnWindowFocus: false,
});
}
function mutationOptions<
TOptions extends UseMutationOptions<TData, TError, TVariables, TContext>,
TData = unknown,
TError = DefaultError,
TVariables = void,
TContext = unknown,
>(
options: TOptions & UseMutationOptions<TData, TError, TVariables, TContext>,
): TOptions {
return options;
}
export function applyChangesMutation(projectPath: string) {
return mutationOptions({
mutationKey: ["projectApplyChanges", projectPath],
mutationFn: async (operation: RequestedOperation) =>
await applyChanges(projectPath, operation),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSettled: async () => {
document.dispatchEvent(new Event("post-package-changes"));
await queryClient.invalidateQueries({
queryKey: ["projectDetails", projectPath],
});
await queryClient.invalidateQueries({
queryKey: ["environmentPackages"],
});
},
});
}
export async function applyChanges(
projectPath: string,
operation: RequestedOperation,
) {
try {
const existingPackages = queryClient.getQueryData(
environmentPackages(projectPath).queryKey,
)?.installed_packages;
const changes = await createChanges(projectPath, operation);
if (
!(await openSingleDialog(ProjectChangesDialog, {
changes,
existingPackages,
}))
) {
// close window
return;
}
await commands.projectApplyPendingChanges(
projectPath,
changes.changes_version,
);
showToast(operation);
} catch (e) {
if (isHandleable(e) && e.body.type === "MissingDependencies") {
await openSingleDialog(MissingDependenciesDialog, {
dependencies: e.body.dependencies,
});
} else {
throw e;
}
}
}
function createChanges(
projectPath: string,
operation: RequestedOperation,
): Promise<TauriPendingProjectChanges> {
switch (operation.type) {
case "install":
return commands.projectInstallPackages(projectPath, [
[operation.pkg.name, toVersionString(operation.pkg.version)],
]);
case "upgradeAll":
return commands.projectInstallPackages(
projectPath,
operation.packages.map((pkg) => [
pkg.name,
toVersionString(pkg.version),
]),
);
case "resolve":
case "reinstallAll":
return commands.projectResolve(projectPath);
case "remove":
return commands.projectRemovePackages(projectPath, [operation.packageId]);
case "bulkInstalled":
return commands.projectInstallPackages(
projectPath,
operation.packages.map((pkg) => [
pkg.name,
toVersionString(pkg.version),
]),
);
case "bulkReinstalled":
return commands.projectReinstallPackages(
projectPath,
operation.packageIds,
);
case "bulkRemoved":
return commands.projectRemovePackages(projectPath, operation.packageIds);
default:
assertNever(operation);
}
}
function showToast(requested: RequestedOperation) {
switch (requested.type) {
case "install":
toastSuccess(
tt("projects:manage:toast:package installed", {
name: requested.pkg.display_name ?? requested.pkg.name,
version: toVersionString(requested.pkg.version),
}),
);
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:the package has newer latest with incompatible unity",
),
);
}
break;
case "remove":
toastSuccess(
tt("projects:manage:toast:package removed", {
name: requested.displayName,
}),
);
break;
case "resolve":
toastSuccess(tt("projects:manage:toast:resolved"));
break;
case "reinstallAll":
toastSuccess(tt("projects:manage:toast:all packages reinstalled"));
break;
case "upgradeAll":
toastSuccess(tt("projects:manage:toast:all packages upgraded"));
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:some package has newer latest with incompatible unity",
),
);
}
break;
case "bulkInstalled":
toastSuccess(tt("projects:manage:toast:selected packages installed"));
if (requested.hasUnityIncompatibleLatest) {
toastInfo(
tt(
"projects:manage:toast:some package has newer latest with incompatible unity",
),
);
}
break;
case "bulkRemoved":
toastSuccess(tt("projects:manage:toast:selected packages removed"));
break;
case "bulkReinstalled":
toastSuccess(tt("projects:manage:toast:selected packages reinstalled"));
break;
default:
assertNever(requested);
}
}
const TypographyItem = ({ children }: { children: React.ReactNode }) => (
<div className={"p-3"}>
<p className={"font-normal"}>{children}</p>
</div>
);
function ProjectChangesDialog({
changes,
existingPackages,
dialog,
}: {
changes: TauriPendingProjectChanges;
existingPackages?: [string, TauriBasePackageInfo][];
dialog: DialogContext<boolean>;
}) {
const versionConflicts = changes.conflicts.filter(
([_, c]) => c.packages.length > 0,
);
const unityConflicts = changes.conflicts.filter(([_, c]) => c.unity_conflict);
const unlockedConflicts = changes.conflicts.flatMap(
([_, c]) => c.unlocked_names,
);
const existingPackageMap = new Map(existingPackages ?? []);
const categorizedChanges = changes.package_changes.map(([pkgId, change]) =>
categorizeChange(pkgId, change, existingPackageMap),
);
categorizedChanges.sort(keyComparator("packageId"));
const groupedChanges = Array.from(groupBy(categorizedChanges, (c) => c.type));
groupedChanges.sort(keyComparator(0));
const installingPackageById = new Map(
changes.package_changes
.map(([id, change]) =>
"InstallNew" in change ? ([id, change.InstallNew] as const) : undefined,
)
.filter((x) => x != null),
);
function getPackageDisplayName(id: string) {
return (
installingPackageById.get(id)?.display_name ??
existingPackageMap.get(id)?.display_name ??
id
);
}
const breakingChanges = groupedChanges.some(
([a]) => a === PackageChangeCategory.UpgradeMajor,
);
const incompatibility = changes.conflicts.length !== 0;
const needsCare = breakingChanges || incompatibility;
return (
<div className={"contents whitespace-normal"}>
<DialogHeader>
<DialogTitle>{tc("projects:manage:button:apply changes")}</DialogTitle>
<DialogDescription>
<p>{tc("projects:manage:dialog:confirm changes description")}</p>
{breakingChanges && (
<div
className={
"flex border border-solid border-warning mt-3 py-2 me-1.5"
}
>
<CircleAlert
className={"text-warning self-center mx-2 shrink-0"}
/>
<p>{tc("projects:manage:dialog:note breaking changes")}</p>
</div>
)}
{incompatibility && (
<div
className={
"flex border border-solid border-warning mt-3 py-2 me-1.5"
}
>
<CircleAlert
className={"text-warning self-center mx-2 shrink-0"}
/>
<p>{tc("projects:manage:dialog:note incompatibility")}</p>
</div>
)}
</DialogDescription>
</DialogHeader>
<div className="overflow-hidden flex">
<ScrollArea
type="always"
className={"w-full"}
scrollBarClassName={"bg-background pb-2.5"}
>
<div className="pr-2 overflow-x-hidden">
<div className={"flex flex-col gap-1 p-2"}>
{groupedChanges.map(([category, changes], index) => {
return (
<Fragment key={category}>
{index !== 0 && <hr />}
{changes.map((change) => (
<PackageChange key={change.packageId} change={change} />
))}
</Fragment>
);
})}
</div>
{versionConflicts.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc("projects:manage:dialog:package version conflicts", {
count: versionConflicts.length,
})}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{versionConflicts.map(([pkgId, conflict]) => {
return (
<TypographyItem key={pkgId}>
{tc("projects:manage:dialog:conflicts with", {
pkg: getPackageDisplayName(pkgId),
other: conflict.packages
.map((p) => getPackageDisplayName(p))
.join(", "),
})}
</TypographyItem>
);
})}
</div>
</>
) : null}
{unityConflicts.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc("projects:manage:dialog:unity version conflicts", {
count: unityConflicts.length,
})}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{unityConflicts.map(([pkgId, _]) => (
<TypographyItem key={pkgId}>
{tc(
"projects:manage:dialog:package not supported your unity",
{
pkg: getPackageDisplayName(pkgId),
},
)}
</TypographyItem>
))}
</div>
</>
) : null}
{changes.remove_legacy_files.length > 0 ||
changes.remove_legacy_folders.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc(
"projects:manage:dialog:files and directories are removed as legacy",
)}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{changes.remove_legacy_files.map((f) => (
<TypographyItem key={f}>{f}</TypographyItem>
))}
{changes.remove_legacy_folders.map((f) => (
<TypographyItem key={f}>{f}</TypographyItem>
))}
</div>
</>
) : null}
{unlockedConflicts.length > 0 ? (
<>
<p className={"text-destructive"}>
{tc(
"projects:manage:dialog:packages installed in the following directories will be removed",
)}
</p>
<div className={"flex flex-col gap-1 p-2"}>
{unlockedConflicts.map((f) => (
<TypographyItem key={f}>{f}</TypographyItem>
))}
</div>
</>
) : null}
</div>
</ScrollArea>
</div>
<DialogFooter>
<Button onClick={() => dialog.close(false)} className="mr-1">
{tc("general:button:cancel")}
</Button>
<DelayedButton
onClick={() => dialog.close(true)}
variant={needsCare ? "destructive" : "warning"}
delay={needsCare ? 1000 : 0}
>
{tc("projects:manage:button:apply")}
</DelayedButton>
</DialogFooter>
</div>
);
}
function PackageChange({
change,
}: {
change: PackageChangeDisplayInformation;
}) {
switch (change.type) {
case PackageChangeCategory.UpgradeMajor:
return (
<div className={"flex items-center p-3 justify-between bg-warning/10"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:upgrade package", {
name: change.displayName,
previousVersion: toVersionString(change.previousVersion),
version: toVersionString(change.version),
})}
<span className={"text-warning"}>
{"\u200B"}
<CircleAlert
className={
"inline px-1 size-5 -mt-0.5 box-content align-middle"
}
/>
{tc("projects:manage:dialog:breaking changes")}
</span>
</p>
<ChangelogButton url={change.changelogUrl} />
</div>
);
case PackageChangeCategory.Upgrade:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:upgrade package", {
name: change.displayName,
previousVersion: toVersionString(change.previousVersion),
version: toVersionString(change.version),
})}
</p>
<ChangelogButton url={change.changelogUrl} />
</div>
);
case PackageChangeCategory.Downgrade:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:downgrade package", {
name: change.displayName,
previousVersion: toVersionString(change.previousVersion),
version: toVersionString(change.version),
})}
</p>
<ChangelogButton url={change.changelogUrl} />
</div>
);
case PackageChangeCategory.InstallNew:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:install package", {
name: change.displayName,
version: toVersionString(change.version),
})}
</p>
<ChangelogButton url={change.changelogUrl} />
</div>
);
case PackageChangeCategory.UninstallRequested:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:uninstall package as requested", {
name: change.displayName,
})}
</p>
</div>
);
case PackageChangeCategory.UninstallUnused:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:uninstall package as unused", {
name: change.displayName,
})}
</p>
</div>
);
case PackageChangeCategory.UninstallLegacy:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal"}>
{tc("projects:manage:dialog:uninstall package as legacy", {
name: change.displayName,
})}
</p>
</div>
);
case PackageChangeCategory.Reinstall:
return (
<div className={"flex items-center p-3 justify-between"}>
<p className={"font-normal select-text"}>
{tc("projects:manage:dialog:reinstall package", {
name: change.displayName,
version: toVersionString(change.version),
})}
</p>
<ChangelogButton url={change.changelogUrl} />
</div>
);
}
}
enum PackageChangeCategory {
InstallNew = 0,
UpgradeMajor = 1,
Upgrade = 2,
Downgrade = 3,
UninstallRequested = 4,
UninstallUnused = 5,
UninstallLegacy = 6,
Reinstall = 7,
}
type PackageChangeDisplayInformation = {
packageId: string;
displayName: string;
} & (
| {
type: PackageChangeCategory.UpgradeMajor;
version: TauriVersion;
previousVersion: TauriVersion;
changelogUrl: string | null;
}
| {
type: PackageChangeCategory.Upgrade;
version: TauriVersion;
previousVersion: TauriVersion;
changelogUrl: string | null;
}
| {
type: PackageChangeCategory.Downgrade;
version: TauriVersion;
previousVersion: TauriVersion;
changelogUrl: string | null;
}
| {
type: PackageChangeCategory.Reinstall;
version: TauriVersion;
changelogUrl: string | null;
}
| {
type: PackageChangeCategory.InstallNew;
version: TauriVersion;
changelogUrl: string | null;
}
| {
type: PackageChangeCategory.UninstallRequested;
}
| {
type: PackageChangeCategory.UninstallUnused;
}
| {
type: PackageChangeCategory.UninstallLegacy;
}
);
function categorizeChange(
pkgId: string,
change: TauriPackageChange,
installedPackages: Map<string, TauriBasePackageInfo>,
): PackageChangeDisplayInformation {
if (change.InstallNew !== undefined) {
const name = change.InstallNew.display_name ?? change.InstallNew.name;
const installed = installedPackages.get(pkgId);
if (installed == null) {
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.InstallNew,
version: change.InstallNew.version,
changelogUrl: change.InstallNew.changelog_url,
};
} else {
const compare = compareVersion(
installed.version,
change.InstallNew.version,
);
switch (compare) {
case 1:
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.Downgrade,
version: change.InstallNew.version,
previousVersion: installed.version,
changelogUrl: change.InstallNew.changelog_url,
};
case 0:
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.Reinstall,
version: change.InstallNew.version,
changelogUrl: change.InstallNew.changelog_url,
};
case -1:
if (
isUpgradingMajorly(
pkgId,
installed.version,
change.InstallNew.version,
)
) {
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.UpgradeMajor,
version: change.InstallNew.version,
previousVersion: installed.version,
changelogUrl: change.InstallNew.changelog_url,
};
} else {
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.Upgrade,
version: change.InstallNew.version,
previousVersion: installed.version,
changelogUrl: change.InstallNew.changelog_url,
};
}
}
}
} else {
const name = installedPackages.get(pkgId)?.display_name ?? pkgId;
switch (change.Remove) {
case "Requested":
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.UninstallRequested,
};
case "Legacy":
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.UninstallLegacy,
};
case "Unused":
return {
packageId: pkgId,
displayName: name,
type: PackageChangeCategory.UninstallUnused,
};
}
}
}
function isUpgradingMajorly(
pkgId: string,
prevVersion: TauriVersion,
newVersion: TauriVersion,
): boolean {
function firstNonZeroVersionNum(version: TauriVersion): number {
if (version.major !== 0) return version.major;
if (version.minor !== 0) return version.minor;
return version.patch;
}
// generic case: non-zero first version number will be the major version
if (
firstNonZeroVersionNum(prevVersion) !== firstNonZeroVersionNum(newVersion)
) {
return true;
}
// Special case: VRChat SDK uses Branding.Breaking.Bumps.
// Therefore the second number bump means major version bump.
// See https://vcc.docs.vrchat.com/vpm/packages/#brandingbreakingbumps
// See https://feedback.vrchat.com/sdk-bug-reports/p/feedback-please-dont-make-vrcsdk-to-4x-unless-as-big-breaking-changes-as-2-to-3
if (
pkgId === "com.vrchat.avatars" ||
pkgId === "com.vrchat.worlds" ||
pkgId === "com.vrchat.base"
) {
if (prevVersion.minor !== newVersion.minor) {
return true;
}
}
// No conditions met so it's not major bump
return false;
}
function ChangelogButton({ url }: { url?: string | null }) {
if (url == null) return null;
try {
const parsed = new URL(url);
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
return (
<Button
className={"ml-1 px-2"}
size={"sm"}
onClick={() => commands.utilOpenUrl(url)}
>
<ExternalLink>
{tc("projects:manage:button:see changelog")}
</ExternalLink>
</Button>
);
}
} catch {}
return null;
}
function MissingDependenciesDialog({
dependencies,
dialog,
}: {
dependencies: [pkg: string, range: string][];
dialog: DialogContext<void>;
}) {
return (
<div>
<DialogTitle className={"text-destructive"}>
<CircleAlert className="size-6 inline" />{" "}
{tc("projects:manage:dialog:missing dependencies")}
</DialogTitle>
<div>
<p className={"whitespace-normal"}>
{tc("projects:manage:dialog:missing dependencies description")}
</p>
<ul className={"list-disc ml-4 mt-2"}>
{dependencies.map(([dep, range]) => (
<li key={dep}>
{dep} version {range}
</li>
))}
</ul>
</div>
<DialogFooter>
<Button onClick={() => dialog.close()}>
{tc("general:button:close")}
</Button>
</DialogFooter>
</div>
);
}

View file

@ -0,0 +1,771 @@
"use client";
import {
queryOptions,
type UseQueryResult,
useIsMutating,
useMutation,
useQueries,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import {
createFileRoute,
useNavigate,
useRouter,
} from "@tanstack/react-router";
import { ArrowLeft, ChevronDown } from "lucide-react";
import type React from "react";
import { Suspense, useMemo } from "react";
import { copyProject } from "@/app/_main/projects/manage/-copy-project";
import { BackupProjectDialog } from "@/components/BackupProjectDialog";
import { HNavBar, VStack } from "@/components/layout";
import { OpenUnityButton } from "@/components/OpenUnityButton";
import { RemoveProjectDialog } from "@/components/RemoveProjectDialog";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
UnityArgumentsSettings,
useUnityArgumentsSettings,
} from "@/components/unity-arguments-settings";
import type { TauriProjectDetails, TauriUnityVersions } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { VRCSDK_PACKAGES, VRCSDK_UNITY_VERSIONS } from "@/lib/constants";
import { type DialogContext, openSingleDialog } from "@/lib/dialog";
import { tc } from "@/lib/i18n";
import { nameFromPath } from "@/lib/os";
import { toastSuccess, toastThrownError } from "@/lib/toast";
import { compareUnityVersionString, parseUnityVersion } from "@/lib/version";
import { combinePackagesAndProjectDetails } from "./-collect-package-row-info";
import { PackageListCard } from "./-package-list-card";
import { PageContextProvider } from "./-page-context";
import { unityVersionChange } from "./-unity-migration";
import { applyChangesMutation } from "./-use-package-change";
interface SearchParams {
projectPath: string;
}
export const Route = createFileRoute("/_main/projects/manage/")({
component: Page,
validateSearch: (a): SearchParams => ({
projectPath: a.projectPath == null ? "" : `${a.projectPath}`,
}),
});
function Page() {
return (
<Suspense>
<PageBody />
</Suspense>
);
}
function PageBody() {
const { projectPath } = Route.useSearch();
const router = useRouter();
// repositoriesInfo: list of repositories and their visibility
// packagesResult: list of packages
// detailsResult: project details including installed packages
// unityVersionsResult: list of unity versions installed
const [repositoriesInfo, packagesResult, detailsResult, unityVersionsResult] =
useQueries({
queries: [
{
queryKey: ["environmentRepositoriesInfo"],
queryFn: commands.environmentRepositoriesInfo,
refetchOnWindowFocus: false,
},
{
queryKey: ["environmentPackages"],
queryFn: commands.environmentPackages,
refetchOnWindowFocus: false,
},
{
queryKey: ["projectDetails", projectPath],
queryFn: () => commands.projectDetails(projectPath),
refetchOnWindowFocus: false,
},
{
queryKey: ["environmentUnityVersions"],
queryFn: () => commands.environmentUnityVersions(),
},
],
});
const packageRowsData = useMemo(() => {
const packages = packagesResult.data ?? [];
const details = detailsResult.data ?? null;
const hiddenRepositories =
repositoriesInfo.data?.hidden_user_repositories ?? [];
const hideUserPackages =
repositoriesInfo.data?.hide_local_user_packages ?? false;
const definedRepositories = repositoriesInfo.data?.user_repositories ?? [];
const showPrereleasePackages =
repositoriesInfo.data?.show_prerelease_packages ?? false;
return combinePackagesAndProjectDetails(
packages,
details,
hiddenRepositories,
hideUserPackages,
definedRepositories,
showPrereleasePackages,
);
}, [repositoriesInfo.data, packagesResult.data, detailsResult.data]);
const queryClient = useQueryClient();
const refetchPackages = useMutation({
mutationFn: async () => await commands.environmentRefetchPackages(),
onError: (e) => {
reportError(e);
console.error(e);
},
onSettled: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: ["environmentRepositoriesInfo"],
}),
queryClient.invalidateQueries({ queryKey: ["environmentPackages"] }),
queryClient.invalidateQueries({
queryKey: ["projectDetails", projectPath],
}),
queryClient.invalidateQueries({
queryKey: ["environmentUnityVersions"],
}),
]);
},
});
const fetchingMutation = useIsMutating({
mutationKey: applyChangesMutation(projectPath).mutationKey,
});
const requestChangeUnityVersion = (
version: string,
mayUseChinaVariant?: boolean,
) => {
if (detailsResult.data == null)
throw new Error("Project details not ready");
const isVRCProject = detailsResult.data.installed_packages.some(([id, _]) =>
VRCSDK_PACKAGES.includes(id),
);
void unityVersionChange({
projectPath,
version,
isVRCProject,
currentUnityVersion: detailsResult.data.unity_str ?? "unknown",
mayUseChinaVariant,
navigate: router.navigate,
});
};
const isLoading =
packagesResult.isFetching ||
detailsResult.isFetching ||
repositoriesInfo.isFetching ||
unityVersionsResult.isLoading ||
fetchingMutation !== 0 ||
refetchPackages.isPending;
console.log(`rerender: isloading: ${isLoading}`);
const pageContext = useMemo(() => ({ isLoading }), [isLoading]);
return (
<PageContextProvider value={pageContext}>
<VStack>
<ProjectViewHeader
className="shrink-0"
isLoading={isLoading}
detailsResult={detailsResult}
unityVersionsResult={unityVersionsResult}
requestChangeUnityVersion={requestChangeUnityVersion}
/>
{detailsResult?.data?.should_resolve && (
<SuggestResolveProjectCard disabled={isLoading} />
)}
<MigrationCards
isLoading={isLoading}
detailsResult={detailsResult.data}
unityVersionsResult={unityVersionsResult.data}
requestChangeUnityVersion={requestChangeUnityVersion}
/>
<main className="shrink overflow-hidden flex w-full h-full">
<PackageListCard
packageRowsData={packageRowsData}
repositoriesInfo={repositoriesInfo.data}
onRefresh={() => refetchPackages.mutate()}
/>
</main>
</VStack>
</PageContextProvider>
);
}
function UnityVersionSelector({
disabled,
detailsResult,
requestChangeUnityVersion,
unityVersions,
}: {
disabled?: boolean;
detailsResult: UseQueryResult<TauriProjectDetails>;
requestChangeUnityVersion: (version: string) => void;
unityVersions?: TauriUnityVersions;
}) {
const unityVersionNames = useMemo(() => {
if (unityVersions == null) return null;
const versionNames = [
...new Set<string>(unityVersions.unity_paths.map(([, path]) => path)),
];
versionNames.sort((a, b) => compareUnityVersionString(b, a));
return versionNames;
}, [unityVersions]);
const isVRCProject =
detailsResult.data?.installed_packages.some(([id, _]) =>
VRCSDK_PACKAGES.includes(id),
) ?? false;
let unityVersionList: React.ReactNode;
if (unityVersionNames == null) {
unityVersionList = <SelectLabel>Loading...</SelectLabel>;
} else if (isVRCProject) {
const vrcSupportedVersions = unityVersionNames.filter((v) =>
VRCSDK_UNITY_VERSIONS.includes(v),
);
const vrcUnsupportedVersions = unityVersionNames.filter(
(v) => !VRCSDK_UNITY_VERSIONS.includes(v),
);
if (
vrcUnsupportedVersions.length === 0 ||
vrcUnsupportedVersions.length === 0
) {
unityVersionList = unityVersionNames.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
));
} else {
// if there are both supported and unsupported versions, show them separately
unityVersionList = (
<>
{vrcSupportedVersions.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
))}
<SelectLabel>
<Separator className={"-ml-6 mr-0 w-auto"} />
</SelectLabel>
{vrcUnsupportedVersions.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
))}
</>
);
}
} else {
unityVersionList = unityVersionNames.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
));
}
return (
<Select
disabled={disabled}
value={detailsResult.data?.unity_str ?? undefined}
onValueChange={requestChangeUnityVersion}
>
<SelectTrigger className={"compact:h-10"}>
{detailsResult.status === "success" ? (
(detailsResult.data.unity_str ?? "unknown")
) : (
<span className={"text-primary"}>Loading...</span>
)}
</SelectTrigger>
<SelectContent>
<SelectGroup>{unityVersionList}</SelectGroup>
</SelectContent>
</Select>
);
}
function SuggestResolveProjectCard({ disabled }: { disabled?: boolean }) {
const { projectPath } = Route.useSearch();
const packageChange = useMutation(applyChangesMutation(projectPath));
return (
<Card className={"shrink-0 p-2 flex flex-row items-center compact:p-1"}>
<p className="cursor-pointer py-1.5 font-bold grow-0 shrink overflow-hidden whitespace-normal text-sm pl-2">
{tc("projects:manage:suggest resolve")}
</p>
<div className={"grow shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={() => packageChange.mutate({ type: "resolve" })}
disabled={disabled}
>
{tc("projects:manage:button:resolve")}
</Button>
</Card>
);
}
function MigrationCards({
isLoading,
detailsResult,
unityVersionsResult,
requestChangeUnityVersion,
}: {
isLoading: boolean;
detailsResult?: TauriProjectDetails;
unityVersionsResult?: TauriUnityVersions;
requestChangeUnityVersion: (
version: string,
keepChinaVariant?: boolean,
) => void;
}) {
if (detailsResult == null) return null;
if (unityVersionsResult == null) return null;
if (detailsResult.unity == null) return false;
if (detailsResult.unity_str == null) return false;
const currentUnity = detailsResult.unity_str;
const isVRChatProject = detailsResult.installed_packages.some(([id, _]) =>
VRCSDK_PACKAGES.includes(id),
);
// we only migrate VRChat project (for now)
if (!isVRChatProject) return null;
// for 2019 projects, VRChat recommends migrating to 2022
const isMigrationTo2022Recommended = detailsResult.unity[0] === 2019;
const is2022PatchMigrationRecommended =
detailsResult.unity[0] === 2022 &&
compareUnityVersionString(
detailsResult.unity_str,
unityVersionsResult.recommended_version,
) !== 0;
const isChinaToInternationalMigrationRecommended =
parseUnityVersion(detailsResult.unity_str)?.chinaIncrement != null;
return (
<>
{isMigrationTo2022Recommended && (
<SuggestMigrateTo2022Card
disabled={isLoading}
onMigrateRequested={() =>
requestChangeUnityVersion(
unityVersionsResult.recommended_version,
true,
)
}
/>
)}
{is2022PatchMigrationRecommended && (
<Suggest2022PatchMigrationCard
disabled={isLoading}
onMigrateRequested={() =>
requestChangeUnityVersion(
unityVersionsResult.recommended_version,
true,
)
}
/>
)}
{isChinaToInternationalMigrationRecommended && (
<SuggestChinaToInternationalMigrationCard
disabled={isLoading}
onMigrateRequested={() => {
const internationalVersion = currentUnity.slice(
0,
currentUnity.indexOf("c"),
);
requestChangeUnityVersion(internationalVersion);
}}
/>
)}
</>
);
}
function SuggestMigrateTo2022Card({
disabled,
onMigrateRequested,
}: {
disabled?: boolean;
onMigrateRequested: () => void;
}) {
return (
<Card className={"shrink-0 p-2 flex flex-row items-center compact:p-1"}>
<p className="cursor-pointer py-1.5 font-bold grow-0 shrink overflow-hidden whitespace-normal text-sm pl-2">
{tc("projects:manage:suggest unity migration")}
</p>
<div className={"grow shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onMigrateRequested}
disabled={disabled}
>
{tc("projects:manage:button:unity migrate")}
</Button>
</Card>
);
}
function Suggest2022PatchMigrationCard({
disabled,
onMigrateRequested,
}: {
disabled?: boolean;
onMigrateRequested: () => void;
}) {
return (
<Card className={"shrink-0 p-2 flex flex-row items-center compact:p-1"}>
<p className="cursor-pointer py-1.5 font-bold grow-0 shrink overflow-hidden whitespace-normal text-sm pl-2">
{tc("projects:manage:suggest unity patch migration")}
</p>
<div className={"grow shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onMigrateRequested}
disabled={disabled}
>
{tc("projects:manage:button:unity migrate")}
</Button>
</Card>
);
}
function SuggestChinaToInternationalMigrationCard({
disabled,
onMigrateRequested,
}: {
disabled?: boolean;
onMigrateRequested: () => void;
}) {
return (
<Card className={"shrink-0 p-2 flex flex-row items-center compact:p-1"}>
<p className="cursor-pointer py-1.5 font-bold grow-0 shrink overflow-hidden whitespace-normal text-sm pl-2">
{tc("projects:manage:suggest unity china to international migration")}
</p>
<div className={"grow shrink-0 w-2"} />
<Button
variant={"ghost-destructive"}
onClick={onMigrateRequested}
disabled={disabled}
>
{tc("projects:manage:button:unity migrate")}
</Button>
</Card>
);
}
function ProjectViewHeader({
className,
isLoading,
detailsResult,
unityVersionsResult,
requestChangeUnityVersion,
}: {
className?: string;
isLoading: boolean | undefined;
detailsResult: UseQueryResult<TauriProjectDetails, Error>;
unityVersionsResult: UseQueryResult<TauriUnityVersions, Error>;
requestChangeUnityVersion: (
version: string,
mayUseChinaVariant?: boolean,
) => void;
}) {
const { projectPath } = Route.useSearch();
const projectName = nameFromPath(projectPath);
return (
<HNavBar
className={className}
leading={
<>
<Tooltip>
<TooltipTrigger asChild>
<Button
className={"compact:h-10"}
variant={"ghost"}
size={"sm"}
onClick={() => history.back()}
>
<ArrowLeft className={"w-5 h-5"} />
</Button>
</TooltipTrigger>
<TooltipContent>
{tc("projects:manage:tooltip:back to projects")}
</TooltipContent>
</Tooltip>
<div className={"pl-2 space-y-0 shrink min-w-0 compact:pl-0"}>
<p className="cursor-pointer font-bold grow-0 whitespace-pre mb-0 leading-tight">
{projectName}
</p>
<p className="cursor-pointer text-sm leading-tight mt-0">
{tc(
"projects:manage:project location",
{ path: projectPath },
{
components: {
path: (
<span
className={
"p-0.5 font-path whitespace-pre bg-secondary text-secondary-foreground"
}
/>
),
},
},
)}
</p>
</div>
</>
}
trailing={
<>
<div className="flex items-center gap-1">
<p className="cursor-pointer py-1.5 font-bold">
{tc("projects:manage:unity version")}
</p>
<div className={"flex"}>
<UnityVersionSelector
disabled={isLoading}
detailsResult={detailsResult}
unityVersions={unityVersionsResult.data}
requestChangeUnityVersion={requestChangeUnityVersion}
/>
</div>
</div>
<div className={"grow-0 shrink-0 w-max"}>
<ProjectButton
projectPath={projectPath}
unityVersion={detailsResult.data?.unity_str ?? null}
unityRevision={detailsResult.data?.unity_revision ?? null}
/>
</div>
</>
}
/>
);
}
function LaunchSettings({
defaultUnityArgs,
initialValue,
dialog,
}: {
defaultUnityArgs: string[];
initialValue: string[] | null;
dialog: DialogContext<string[] | null | false>;
}) {
const context = useUnityArgumentsSettings(initialValue, defaultUnityArgs);
const saveAndClose = async () => {
dialog.close(context.currentValue);
};
return (
<>
<DialogTitle>{tc("projects:dialog:launch options")}</DialogTitle>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<div className={"max-h-[50dvh] overflow-y-auto"}>
<h3 className={"text-lg"}>
{tc("projects:dialog:command-line arguments")}
</h3>
<UnityArgumentsSettings context={context} />
</div>
<DialogFooter>
<Button onClick={() => dialog.close(false)} variant={"destructive"}>
{tc("general:button:cancel")}
</Button>
<Button onClick={saveAndClose} disabled={context.hasError}>
{tc("general:button:save")}
</Button>
</DialogFooter>
</>
);
}
function projectGetUnityPath(projectPath: string) {
return queryOptions({
queryFn: () => commands.projectGetUnityPath(projectPath),
queryKey: ["projectGetUnityPath", projectPath],
refetchOnWindowFocus: false,
});
}
function DropdownMenuContentBody({
projectPath,
removeProject,
onChangeLaunchOptions,
}: {
projectPath: string;
removeProject?: () => void;
onChangeLaunchOptions?: () => void;
}) {
const openProjectFolder = () =>
commands.utilOpen(projectPath, "ErrorIfNotExists");
const queryClient = useQueryClient();
const setUnityPath = useMutation({
mutationFn: async (unityPath: string | null) =>
await commands.projectSetUnityPath(projectPath, unityPath),
onMutate: async (unityPath) => {
const getUnityPath = projectGetUnityPath(projectPath);
await queryClient.invalidateQueries(getUnityPath);
const data = queryClient.getQueryData(getUnityPath.queryKey);
queryClient.setQueryData(getUnityPath.queryKey, unityPath);
return data;
},
onError: (e, _, data) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(projectGetUnityPath(projectPath).queryKey, data);
},
onSuccess: () => {
toastSuccess(tc("projects:toast:forgot unity path"));
},
});
const unityPathQuery = useQuery(projectGetUnityPath(projectPath));
const navigate = useNavigate();
const onCopyProject = async () => {
try {
await copyProject(projectPath, navigate);
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const onBackup = async () => {
try {
await openSingleDialog(BackupProjectDialog, {
projectPath,
});
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
const unityPath = unityPathQuery.data;
return (
<>
<DropdownMenuItem onClick={onChangeLaunchOptions}>
{tc("projects:menuitem:change launch options")}
</DropdownMenuItem>
{unityPath && (
<DropdownMenuItem onClick={() => setUnityPath.mutate(null)}>
{tc("projects:menuitem:forget unity path")}
</DropdownMenuItem>
)}
<DropdownMenuItem onClick={openProjectFolder}>
{tc("projects:menuitem:open directory")}
</DropdownMenuItem>
<DropdownMenuItem onClick={onCopyProject}>
{tc("projects:menuitem:copy project")}
</DropdownMenuItem>
<DropdownMenuItem onClick={onBackup}>
{tc("projects:menuitem:backup")}
</DropdownMenuItem>
<DropdownMenuItem
onClick={removeProject}
className={"text-destructive focus:text-destructive"}
>
{tc("projects:remove project")}
</DropdownMenuItem>
</>
);
}
function ProjectButton({
projectPath,
unityVersion,
unityRevision,
}: {
projectPath: string;
unityVersion: string | null;
unityRevision: string | null;
}) {
const onChangeLaunchOptions = async () => {
const initialArgs = await commands.projectGetCustomUnityArgs(projectPath);
const defaultArgs = await commands.environmentGetDefaultUnityArguments();
const settings = await openSingleDialog(LaunchSettings, {
initialValue: initialArgs,
defaultUnityArgs: defaultArgs,
});
if (settings === false) return;
await commands.projectSetCustomUnityArgs(projectPath, settings);
};
return (
<DropdownMenu>
<div className={"flex divide-x"}>
<OpenUnityButton
projectPath={projectPath}
unityVersion={unityVersion}
unityRevision={unityRevision}
className={"rounded-r-none pl-4 pr-3 compact:h-10"}
/>
<DropdownMenuTrigger
asChild
className={"rounded-l-none pl-2 pr-2 compact:h-10"}
>
<Button>
<ChevronDown className={"w-4 h-4"} />
</Button>
</DropdownMenuTrigger>
</div>
<DropdownMenuContent>
<DropdownMenuContentBody
projectPath={projectPath}
removeProject={() => {
void openSingleDialog(RemoveProjectDialog, {
project: {
path: projectPath,
is_exists: true,
},
});
}}
onChangeLaunchOptions={onChangeLaunchOptions}
/>
</DropdownMenuContent>
</DropdownMenu>
);
}

View file

@ -0,0 +1,83 @@
"use client";
import { createFileRoute, Outlet, useLocation } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { SideBar } from "@/components/SideBar";
import { commands } from "@/lib/bindings";
import { useDocumentEvent } from "@/lib/events";
import { updateCurrentPath, usePrevPathName } from "@/lib/prev-page";
import { useEffectEvent } from "@/lib/use-effect-event";
export const Route = createFileRoute("/_main")({
component: MainLayout,
});
function MainLayout() {
const [animationState, setAnimationState] = useState("");
const [isVisible, setIsVisible] = useState(false);
const [guiAnimation, setGuiAnimation] = useState(false);
const previousPathName = usePrevPathName();
const pathName = useLocation().pathname;
useDocumentEvent(
"gui-animation",
(event) => {
setGuiAnimation(event.detail);
},
[],
);
const onPathChange = useEffectEvent((pathName: string) => {
updateCurrentPath(pathName);
(async () => {
setGuiAnimation(await commands.environmentGuiAnimation());
})();
if (!guiAnimation) return;
if (pathName === previousPathName) return;
const pageCategory = pathName.split("/")[1];
const previousPageCategory = previousPathName.split("/")[1];
if (pageCategory !== previousPageCategory) {
// category change is always fade-in
setAnimationState("fade-in");
} else {
// go deeper is slide-left, go back is slide-right, and no animation if not child-parent relation
if (pathName.startsWith(previousPathName)) {
setAnimationState("slide-left");
} else if (previousPathName.startsWith(pathName)) {
setAnimationState("slide-right");
}
}
});
useEffect(() => {
onPathChange(pathName);
}, [pathName]);
useEffect(() => {
(async () => {
if (await commands.environmentGuiCompact()) {
document.documentElement.setAttribute("compact", "");
} else {
document.documentElement.removeAttribute("compact");
}
setIsVisible(true);
})();
}, []);
return (
<>
<SideBar
className={`grow-0 ${isVisible ? "slide-right" : "invisible"}`}
/>
<div
className={`h-screen grow overflow-hidden flex p-4 compact:p-2 ${animationState}`}
onAnimationEnd={() => setAnimationState("")}
>
<Outlet />
</div>
</>
);
}

View file

@ -0,0 +1,962 @@
"use client";
import {
queryOptions,
useMutation,
useQueryClient,
useSuspenseQuery,
} from "@tanstack/react-query";
import { createFileRoute, Link } from "@tanstack/react-router";
import { RefreshCw } from "lucide-react";
import type React from "react";
import { Suspense, useEffect, useTransition } from "react";
import Loading from "@/app/-loading";
import { CheckForUpdateMessage } from "@/components/CheckForUpdateMessage";
import {
BackupFormatSelect,
BackupPathWarnings,
FilePathRow,
GuiAnimationSwitch,
GuiCompactSwitch,
LanguageSelector,
ProjectPathWarnings,
ThemeSelector,
} from "@/components/common-setting-parts";
import { HNavBar, HNavBarText, VStack } from "@/components/layout";
import { ScrollableCardTable } from "@/components/ScrollableCardTable";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { DialogFooter, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
UnityArgumentsSettings,
useUnityArgumentsSettings,
} from "@/components/unity-arguments-settings";
import { assertNever } from "@/lib/assert-never";
import type { OpenOptions, UnityHubAccessMethod } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { type DialogContext, openSingleDialog } from "@/lib/dialog";
import globalInfo, { useGlobalInfo } from "@/lib/global-info";
import { tc, tt } from "@/lib/i18n";
import {
toastError,
toastNormal,
toastSuccess,
toastThrownError,
} from "@/lib/toast";
import { useEffectEvent } from "@/lib/use-effect-event";
import { cn } from "@/lib/utils";
export const Route = createFileRoute("/_main/settings/")({
component: Page,
});
const environmentGetSettings = queryOptions({
queryKey: ["environmentGetSettings"],
queryFn: commands.environmentGetSettings,
});
function Page() {
return (
<VStack>
<HNavBar
className="shrink-0"
leading={<HNavBarText>{tc("settings")}</HNavBarText>}
/>
<Suspense
fallback={
<Card className={"p-4"}>
<Loading loadingText={tc("general:loading...")} />
</Card>
}
>
<Settings />
</Suspense>
</VStack>
);
}
function Settings() {
const [updatingUnityPaths, updateUnityPathsTransition] = useTransition();
const queryClient = useQueryClient();
const updateUnityPaths = async () => {
updateUnityPathsTransition(async () => {
await commands.environmentUpdateUnityPathsFromUnityHub();
await queryClient.invalidateQueries(environmentGetSettings);
});
};
// at the time settings page is opened, unity hub path update might be in progress so we wait for it
const waitForHubUpdate = useEffectEvent(async () => {
updateUnityPathsTransition(async () => {
await commands.environmentWaitForUnityHubUpdate();
await queryClient.invalidateQueries(environmentGetSettings);
});
});
useEffect(() => void waitForHubUpdate(), []);
return (
<ScrollPageContainer viewportClassName={"rounded-xl shadow-xl h-full"}>
<main className="flex flex-col gap-2 shrink grow">
<UnityHubPathCard updateUnityPaths={updateUnityPaths} />
<UnityInstallationsCard
updatingUnityPaths={updatingUnityPaths}
updateUnityPaths={updateUnityPaths}
/>
<UnityLaunchArgumentsCard />
<DefaultProjectPathCard />
<BackupCard />
<PackagesCard />
<AppearanceCard />
<FilesAndFoldersCard />
<AlcomCard />
<SystemInformationCard />
</main>
</ScrollPageContainer>
);
}
function SettingsCard({
className,
children,
...props
}: React.ComponentProps<typeof Card>) {
return (
<Card className={cn("shrink-0 p-4 compact:p-3", className)} {...props}>
{children}
</Card>
);
}
function UnityHubPathCard({
updateUnityPaths,
}: {
updateUnityPaths: () => Promise<void>;
}) {
const queryClient = useQueryClient();
const {
data: { unityHub },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
unityHub: data.unity_hub,
}),
});
const pickUnityHub = useMutation({
mutationFn: async () => await commands.environmentPickUnityHub(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:unity hub path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
await updateUnityPaths();
},
});
return (
<SettingsCard>
<h2 className={"pb-2"}>{tc("settings:unity hub path")}</h2>
<FilePathRow
path={unityHub}
pick={pickUnityHub.mutate}
notFoundMessage={"Unity Hub Not Found"}
withOpen={false}
/>
</SettingsCard>
);
}
function UnityInstallationsCard({
updatingUnityPaths,
updateUnityPaths,
}: {
updatingUnityPaths: boolean;
updateUnityPaths: () => void;
}) {
const queryClient = useQueryClient();
const {
data: { unityPaths, unityHubAccessMethod },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
unityPaths: data.unity_paths,
unityHubAccessMethod: data.unity_hub_access_method,
}),
});
const addUnity = useMutation({
mutationFn: async () => await commands.environmentPickUnity(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tt("settings:toast:not unity"));
break;
case "AlreadyAdded":
toastError(tt("settings:toast:unity already added"));
break;
case "Successful":
toastSuccess(tt("settings:toast:unity added"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const setAccessMethod = useMutation({
mutationFn: async (method: UnityHubAccessMethod) =>
await commands.environmentSetUnityHubAccessMethod(method),
onMutate: async (method) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
unity_hub_access_method: method,
});
}
return current;
},
onError: (e, _, prev) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const UNITY_TABLE_HEAD = [
"settings:unity:version",
"settings:unity:path",
"general:source",
];
return (
<SettingsCard className={"flex flex-col gap-2"}>
<div className={"flex align-middle"}>
<div className={"grow flex items-center"}>
<h2>{tc("settings:unity installations")}</h2>
</div>
{updatingUnityPaths && (
<div className={"flex items-center m-1"}>
<Tooltip>
<TooltipTrigger>
<RefreshCw className="w-5 h-5 animate-spin" />
</TooltipTrigger>
<TooltipContent>
{tc("settings:tooltip:reload unity from unity hub")}
</TooltipContent>
</Tooltip>
</div>
)}
<Tooltip>
<TooltipTrigger asChild>
<Button
disabled={updatingUnityPaths}
onClick={updateUnityPaths}
size={"sm"}
className={"m-1"}
>
{tc("settings:button:reload unity from unity hub")}
</Button>
</TooltipTrigger>
<TooltipContent>
{tc("settings:tooltip:reload unity from unity hub")}
</TooltipContent>
</Tooltip>
<Button
disabled={updatingUnityPaths}
onClick={() => addUnity.mutate()}
size={"sm"}
className={"m-1"}
>
{tc("settings:button:add unity")}
</Button>
</div>
<ScrollableCardTable
className={`w-full min-h-[20vh] ${updatingUnityPaths ? "opacity-50" : ""}`}
>
<thead>
<tr>
{UNITY_TABLE_HEAD.map((head, index) => (
<th
// biome-ignore lint/suspicious/noArrayIndexKey: static array
key={index}
className={
"sticky top-0 z-10 border-b border-primary bg-secondary text-secondary-foreground p-2.5"
}
>
<small className="font-normal leading-none">{tc(head)}</small>
</th>
))}
</tr>
</thead>
<tbody>
{unityPaths.map(([path, version, isFromHub]) => (
<tr key={path} className="even:bg-secondary/30">
<td className={"p-2.5"}>{version}</td>
<td className={"p-2.5"}>{path}</td>
<td className={"p-2.5"}>
{isFromHub
? tc("settings:unity:source:unity hub")
: tc("settings:unity:source:manual")}
</td>
</tr>
))}
</tbody>
</ScrollableCardTable>
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={unityHubAccessMethod === "CallHub"}
onCheckedChange={(e) =>
setAccessMethod.mutate(e === true ? "CallHub" : "ReadConfig")
}
/>
{tc("settings:use legacy unity hub loading")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:use legacy unity hub loading description")}
</p>
</div>
</SettingsCard>
);
}
function UnityLaunchArgumentsCard() {
const { data: unityArgs } = useSuspenseQuery({
...environmentGetSettings,
select: (d) => d.default_unity_arguments,
});
const defaultUnityArgs = useGlobalInfo().defaultUnityArguments;
const realUnityArgs = unityArgs ?? defaultUnityArgs;
return (
<SettingsCard>
<div className={"mb-2 flex align-middle"}>
<div className={"grow flex items-center"}>
<h2>{tc("settings:default unity arguments")}</h2>
</div>
<Button
onClick={async () => {
try {
await openSingleDialog(LaunchArgumentsEditDialogBody, {
unityArgs,
});
} catch (e) {
console.log(e);
toastThrownError(e);
}
}}
size={"sm"}
className={"m-1"}
>
{tc("general:button:edit")}
</Button>
</div>
<p className={"whitespace-normal"}>
{tc("settings:default unity arguments description")}
</p>
<ol className={"flex flex-col"}>
{realUnityArgs.map((v, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: unity args are ordered list
<Input disabled key={i + v} value={v} className={"w-full"} />
))}
</ol>
</SettingsCard>
);
}
function LaunchArgumentsEditDialogBody({
unityArgs,
dialog,
}: {
unityArgs: string[] | null;
dialog: DialogContext<boolean>;
}) {
const queryClient = useQueryClient();
const setDefaultArgs = useMutation({
mutationFn: async ({ value }: { value: string[] | null }) => {
return await commands.environmentSetDefaultUnityArguments(value);
},
onMutate: async ({ value }) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
default_unity_arguments: value,
});
}
return current;
},
onError: (e, _, prev) => {
dialog.error(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSuccess: () => {
dialog.close(true);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const context = useUnityArgumentsSettings(
unityArgs,
globalInfo.defaultUnityArguments,
);
return (
<>
<DialogTitle>
{tc("settings:dialog:default launch arguments")}
</DialogTitle>
{/* TODO: use ScrollArea (I failed to use it inside dialog) */}
<div className={"max-h-[50dvh] overflow-y-auto"}>
<UnityArgumentsSettings context={context} />
</div>
<DialogFooter>
<Button onClick={() => dialog.close(false)} variant={"destructive"}>
{tc("general:button:cancel")}
</Button>
<Button
onClick={() =>
void setDefaultArgs.mutate({ value: context.currentValue })
}
disabled={context.hasError}
>
{tc("general:button:save")}
</Button>
</DialogFooter>
</>
);
}
function DefaultProjectPathCard() {
const queryClient = useQueryClient();
const {
data: { defaultProjectPath },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
defaultProjectPath: data.default_project_path,
}),
});
const pickProjectDefaultPath = useMutation({
mutationFn: async () => await commands.environmentPickProjectDefaultPath(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:default project path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
return (
<SettingsCard>
<h2 className={"mb-2"}>{tc("settings:default project path")}</h2>
<p className={"whitespace-normal"}>
{tc("settings:default project path description")}
</p>
<FilePathRow
path={defaultProjectPath}
pick={pickProjectDefaultPath.mutate}
/>
<ProjectPathWarnings projectPath={defaultProjectPath} />
</SettingsCard>
);
}
function BackupCard() {
const queryClient = useQueryClient();
const {
data: { projectBackupPath, backupFormat, excludeVpmPackagesFromBackup },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
projectBackupPath: data.project_backup_path,
backupFormat: data.backup_format,
excludeVpmPackagesFromBackup: data.exclude_vpm_packages_from_backup,
}),
});
const pickProjectBackupPath = useMutation({
mutationFn: async () => await commands.environmentPickProjectBackupPath(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:backup path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const setExcludeVpmPackagesFromBackup = useMutation({
mutationFn: async (flag: boolean) =>
await commands.environmentSetExcludeVpmPackagesFromBackup(flag),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (_, flag) => {
queryClient.setQueryData(environmentGetSettings.queryKey, (old) => {
if (old == null) return old;
return { ...old, excludeVpmPackagesFromBackup: flag };
});
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
return (
<SettingsCard>
<h2>{tc("projects:backup")}</h2>
<div className="mt-2">
<h3>{tc("settings:backup:path")}</h3>
<p className={"whitespace-normal text-sm"}>
{tc("settings:backup:path description")}
</p>
<FilePathRow
path={projectBackupPath}
pick={pickProjectBackupPath.mutate}
/>
<BackupPathWarnings backupPath={projectBackupPath} />
</div>
<div className="mt-2">
<h3>{tc("settings:backup:format")}</h3>
<p className={"whitespace-normal text-sm"}>
{tc("settings:backup:format description")}
</p>
<label className={"flex items-center"}>
<BackupFormatSelect backupFormat={backupFormat} />
</label>
</div>
<div className="mt-2">
<label className={"flex items-center gap-2"}>
<Checkbox
checked={excludeVpmPackagesFromBackup}
onCheckedChange={(e) =>
setExcludeVpmPackagesFromBackup.mutate(e === true)
}
/>
{tc("settings:backup:exclude vpm packages from backup")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:backup:exclude vpm packages from backup description")}
</p>
</div>
</SettingsCard>
);
}
function PackagesCard() {
const queryClient = useQueryClient();
const {
data: { showPrereleasePackages },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
showPrereleasePackages: data.show_prerelease_packages,
}),
});
const clearPackageCache = useMutation({
mutationFn: async () => await commands.environmentClearPackageCache(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: async () => {
toastSuccess(tc("settings:toast:package cache cleared"));
},
onSettled: async () => {
await queryClient.invalidateQueries({
queryKey: ["environmentPackages"],
});
},
});
const setShowPrerelease = useMutation({
mutationFn: async (showPrerelease: boolean) =>
await commands.environmentSetShowPrereleasePackages(showPrerelease),
onMutate: async (showPrerelease) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
show_prerelease_packages: showPrerelease,
});
}
return current;
},
onError: (e, _, prev) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
return (
<SettingsCard className={"flex flex-col gap-4"}>
<h2>{tc("settings:packages")}</h2>
<div className={"flex flex-row flex-wrap gap-2"}>
<Button onClick={() => clearPackageCache.mutate()}>
{tc("settings:clear package cache")}
</Button>
</div>
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={showPrereleasePackages}
onCheckedChange={(e) => setShowPrerelease.mutate(e === true)}
/>
{tc("settings:show prerelease")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:show prerelease description")}
</p>
</div>
</SettingsCard>
);
}
function AppearanceCard() {
return (
<SettingsCard className={"flex flex-col gap-2"}>
<h2>{tc("settings:appearance")}</h2>
<LanguageSelector />
<ThemeSelector />
<GuiAnimationSwitch />
<GuiCompactSwitch />
</SettingsCard>
);
}
function FilesAndFoldersCard() {
const openVpmFolderContent = (
subPath: string,
ifNotExists: OpenOptions = "ErrorIfNotExists",
) => {
return async () => {
try {
await commands.utilOpen(
`${globalInfo.vpmHomeFolder}/${subPath}`,
ifNotExists,
);
} catch (e) {
console.error(e);
toastThrownError(e);
}
};
};
return (
<SettingsCard>
<h2>{tc("settings:files and directories")}</h2>
<p className={"mt-2"}>
{tc("settings:files and directories:description")}
</p>
<div className={"flex flex-row flex-wrap gap-2"}>
<Button
className={"normal-case"}
onClick={openVpmFolderContent("settings.json")}
>
{tc("settings:button:open settings.json")}
</Button>
<Button
className={"normal-case"}
onClick={openVpmFolderContent("vrc-get/gui-config.json")}
>
{tc("settings:button:open gui config.json")}
</Button>
<Button onClick={openVpmFolderContent("vrc-get/gui-logs")}>
{tc("settings:button:open logs")}
</Button>
<Button
onClick={openVpmFolderContent("Templates", "CreateFolderIfNotExists")}
>
{tc("settings:button:open vcc templates")}
</Button>
</div>
</SettingsCard>
);
}
function AlcomCard() {
const globalInfo = useGlobalInfo();
const queryClient = useQueryClient();
const {
data: { releaseChannel, useAlcomForVccProtocol },
} = useSuspenseQuery({
...environmentGetSettings,
select: (data) => ({
releaseChannel: data.release_channel,
useAlcomForVccProtocol: data.use_alcom_for_vcc_protocol,
}),
});
const setShowPrerelease = useMutation({
mutationFn: async (releaseChannel: string) =>
await commands.environmentSetReleaseChannel(releaseChannel),
onMutate: async (releaseChannel) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
release_channel: releaseChannel,
});
}
return current;
},
onError: (e, _, prev) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const setUseAlcomForVccProtocol = useMutation({
mutationFn: async (use: boolean) =>
await commands.environmentSetUseAlcomForVccProtocol(use),
onMutate: async (use) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
use_alcom_for_vcc_protocol: use,
});
}
return current;
},
onError: (e, _, prev) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const installVccProtocol = useMutation({
mutationFn: async () => await commands.deepLinkInstallVcc(),
onSuccess: () => {
toastSuccess(tc("settings:toast:vcc scheme installed"));
},
onError: (e) => {
console.error(e);
toastThrownError(e);
},
});
const checkForUpdate = async () => {
try {
const checkVersion = await commands.utilCheckForUpdate();
if (checkVersion) {
await openSingleDialog(CheckForUpdateMessage, {
response: checkVersion,
});
} else {
toastNormal(tc("check update:toast:no updates"));
}
} catch (e) {
toastThrownError(e);
console.error(e);
}
};
const reportIssue = async () => {
const url = new URL("https://github.com/vrc-get/vrc-get/issues/new");
url.searchParams.append("labels", "bug,vrc-get-gui");
url.searchParams.append("template", "01_gui_bug-report.yml");
url.searchParams.append("os", `${globalInfo.osInfo} - ${globalInfo.arch}`);
url.searchParams.append("webview-version", `${globalInfo.webviewVersion}`);
let version = globalInfo.version ?? "unknown";
if (globalInfo.commitHash) {
version += ` (${globalInfo.commitHash})`;
} else {
version += " (unknown commit)";
}
url.searchParams.append("version", version);
void commands.utilOpenUrl(url.toString());
};
return (
<SettingsCard className={"flex flex-col gap-4"}>
<h2>ALCOM</h2>
<div className={"flex flex-row flex-wrap gap-2"}>
{globalInfo.checkForUpdates && (
<Button onClick={checkForUpdate}>
{tc("settings:check update")}
</Button>
)}
<Button onClick={reportIssue}>
{tc("settings:button:open issue")}
</Button>
</div>
{globalInfo.checkForUpdates && (
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={releaseChannel === "beta"}
onCheckedChange={(value) =>
setShowPrerelease.mutate(value === true ? "beta" : "stable")
}
/>
{tc("settings:receive beta updates")}
</label>
<p className={"text-sm whitespace-normal"}>
{tc("settings:beta updates description")}
</p>
</div>
)}
{globalInfo.shouldInstallDeepLink && (
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={useAlcomForVccProtocol}
onCheckedChange={(value) =>
setUseAlcomForVccProtocol.mutate(value === true)
}
/>
{tc("settings:use alcom for vcc scheme")}
</label>
<Button
className={"my-1"}
disabled={!useAlcomForVccProtocol}
onClick={() => installVccProtocol.mutate()}
>
{tc("settings:register vcc scheme now")}
</Button>
<p className={"text-sm whitespace-normal"}>
{tc([
"settings:use vcc scheme description",
"settings:vcc scheme description",
])}
</p>
</div>
)}
<p className={"whitespace-normal"}>
{tc(
"settings:licenses description",
{},
{
components: {
l: <Link to={"/settings/licenses"} className={"underline"} />,
},
},
)}
</p>
</SettingsCard>
);
}
function SystemInformationCard() {
const info = useGlobalInfo();
return (
<SettingsCard className={"flex flex-col gap-4"}>
<h2>{tc("settings:system information")}</h2>
<dl>
<dt>{tc("settings:os")}</dt>
<dd className={"opacity-50 mb-2"}>{info.osInfo}</dd>
<dt>{tc("settings:architecture")}</dt>
<dd className={"opacity-50 mb-2"}>{info.arch}</dd>
<dt>{tc("settings:webview version")}</dt>
<dd className={"opacity-50 mb-2"}>{info.webviewVersion}</dd>
<dt>{tc("settings:alcom version")}</dt>
<dd className={"opacity-50 mb-2"}>{info.version}</dd>
<dt>{tc("settings:alcom commit hash")}</dt>
<dd className={"opacity-50 mb-2"}>{info.commitHash}</dd>
</dl>
</SettingsCard>
);
}

View file

@ -1,23 +1,13 @@
"use client";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { ScrollableCard } from "@/components/ScrollableCard";
import licenses from "build:licenses.json";
import { VStack } from "@/components/layout";
import { ScrollableCard } from "@/components/ScrollableCard";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { Card } from "@/components/ui/card";
import { commands } from "@/lib/bindings";
import type { Licenses } from "@/lib/licenses";
export default function RenderPage({
licenses,
}: { licenses: Licenses | null }) {
if (licenses === null) {
return (
<div className={"whitespace-normal"}>
<p>Failed to load licenses.</p>
</div>
);
}
export default function RenderPage() {
return (
<ScrollPageContainer>
<VStack>
@ -30,7 +20,7 @@ export default function RenderPage({
<ul />
</Card>
{licenses.map((license, idx) => (
{licenses.map((license) => (
<Card className={"p-4"} key={license.text}>
<h3>{license.name}</h3>
<h4>Used by:</h4>

View file

@ -0,0 +1,50 @@
import licenses from "build:licenses.json";
import { createFileRoute } from "@tanstack/react-router";
import { VStack } from "@/components/layout";
import { ScrollableCard } from "@/components/ScrollableCard";
import { ScrollPageContainer } from "@/components/ScrollPageContainer";
import { Card } from "@/components/ui/card";
import { commands } from "@/lib/bindings";
export const Route = createFileRoute("/_main/settings/licenses/")({
component: Page,
});
function Page() {
return (
<ScrollPageContainer>
<VStack>
<Card className={"p-4"}>
<p>
This project is built on top of many open-source projects.
<br />
Here are the licenses of the projects used in this project:
</p>
<ul />
</Card>
{licenses.map((license) => (
<Card className={"p-4"} key={license.text}>
<h3>{license.name}</h3>
<h4>Used by:</h4>
<ul className={"ml-2"}>
{license.packages.map((pkg) => (
<li key={`${pkg.name}@${pkg.version}`}>
<button
type="button"
onClick={() => commands.utilOpenUrl(pkg.url)}
>
{pkg.name} ({pkg.version})
</button>
</li>
))}
</ul>
<ScrollableCard className="max-h-52">
<pre className={"whitespace-pre-wrap"}>{license.text}</pre>
</ScrollableCard>
</Card>
))}
</VStack>
</ScrollPageContainer>
);
}

View file

@ -0,0 +1,44 @@
"use client";
import {
createFileRoute,
Outlet,
useNavigate,
useRouter,
} from "@tanstack/react-router";
export const Route = createFileRoute("/_setup")({
component: SetupLayout,
});
function SetupLayout() {
const isDev = import.meta.env.DEV;
return (
<>
<div className={"h-screen grow overflow-hidden flex p-4"}>
<Outlet />
</div>
{isDev && <DevTools />}
</>
);
}
function DevTools() {
const router = useRouter();
const navigate = useNavigate();
return (
<div className={"absolute bottom-0 left-0 p-4 flex flex-col gap-3"}>
<p>debug tools</p>
<div className={"flex gap-3"}>
<button type="button" onClick={() => router.history.back()}>
Go Back
</button>
<button type="button" onClick={() => navigate({ to: "/settings" })}>
Go Settings
</button>
</div>
</div>
);
}

View file

@ -1,17 +1,16 @@
import { useQuery } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import { Circle, CircleCheck, CircleChevronRight } from "lucide-react";
import type React from "react";
import { Button } from "@/components/ui/button";
import { Card, CardFooter, CardHeader } from "@/components/ui/card";
import type { SetupPages, TauriEnvironmentSettings } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { useQuery } from "@tanstack/react-query";
import { Circle, CircleCheck, CircleChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
import type React from "react";
export type BodyProps = Readonly<{
environment: TauriEnvironmentSettings;
refetch: () => void;
}>;
export function SetupPageBase({
@ -19,6 +18,7 @@ export function SetupPageBase({
Body,
nextPage,
prevPage,
onFinish,
backContent = tc("setup:back"),
nextContent = tc("setup:next"),
pageId,
@ -28,12 +28,13 @@ export function SetupPageBase({
Body: React.ComponentType<BodyProps>;
nextPage: string;
prevPage: string | null;
onFinish?: () => void;
backContent?: React.ReactNode;
nextContent?: React.ReactNode;
pageId: SetupPages | null;
withoutSteps?: boolean;
}) {
const router = useRouter();
const navigate = useNavigate();
const result = useQuery({
queryKey: ["environmentGetSettings"],
@ -42,7 +43,8 @@ export function SetupPageBase({
const onNext = async () => {
if (pageId) await commands.environmentFinishedSetupPage(pageId);
router.push(nextPage);
navigate({ to: nextPage });
onFinish?.();
};
return (
@ -50,9 +52,9 @@ export function SetupPageBase({
<div className={"flex gap-4"}>
{!withoutSteps && <StepCard current={pageId} />}
<Card
className={`${withoutSteps ? "w-[30rem]" : "w-96"} min-w-[50vw] min-h-[max(50dvh,20rem)] p-4 flex gap-3`}
className={`${withoutSteps ? "w-[30rem]" : "w-96"} min-w-[50vw] min-h-[max(50dvh,20rem)] p-4 flex gap-3 compact:min-h-[max(40dvh,20rem)]`}
>
<div className={"flex flex-col flex-grow"}>
<div className={"flex flex-col grow gap-3 compact:gap-2"}>
<CardHeader>
<h1 className={"text-center"}>{heading}</h1>
</CardHeader>
@ -60,15 +62,12 @@ export function SetupPageBase({
{!result.data ? (
<p>{tc("setup:loading")}</p>
) : (
<Body
environment={result.data}
refetch={() => result.refetch()}
/>
<Body environment={result.data} />
)}
<div className={"flex-grow"} />
<CardFooter className="p-0 pt-3 items-end flex-row gap-2 justify-end">
<div className={"grow"} />
<CardFooter className="p-0 pt-3 items-end flex-row gap-2 justify-end compact:-m-2">
{prevPage && (
<Button onClick={() => router.push(prevPage)}>
<Button onClick={() => navigate({ to: prevPage })}>
{backContent}
</Button>
)}
@ -81,11 +80,7 @@ export function SetupPageBase({
);
}
function StepCard({
current,
}: {
current: SetupPages | null;
}) {
function StepCard({ current }: { current: SetupPages | null }) {
// TODO: get progress from backend
const finisheds = useQuery({
queryKey: ["environmentGetFinishedSetupPages"],
@ -93,7 +88,7 @@ function StepCard({
initialData: [],
}).data;
const isMac = useGlobalInfo().osType === "Darwin";
const shouldInstallDeepLink = useGlobalInfo().shouldInstallDeepLink;
return (
<Card className={"w-48 p-4"}>
@ -118,7 +113,7 @@ function StepCard({
finisheds={finisheds}
pageId={"Backups"}
/>
{!isMac && (
{shouldInstallDeepLink && (
<StepElement
current={current}
finisheds={finisheds}

View file

@ -1,14 +1,21 @@
"use client";
import { createFileRoute } from "@tanstack/react-router";
import {
GuiAnimationSwitch,
GuiCompactSwitch,
LanguageSelector,
ThemeSelector,
} from "@/components/common-setting-parts";
import { CardDescription } from "@/components/ui/card";
import { tc } from "@/lib/i18n";
import { SetupPageBase } from "../setup-page-base";
import { SetupPageBase } from "../-setup-page-base";
export default function Page() {
export const Route = createFileRoute("/_setup/setup/appearance/")({
component: Page,
});
function Page() {
return (
<SetupPageBase
heading={tc("setup:entry:welcome")}
@ -33,6 +40,8 @@ function Body() {
</CardDescription>
<LanguageSelector />
<ThemeSelector />
<GuiAnimationSwitch />
<GuiCompactSwitch />
</>
);
}

View file

@ -0,0 +1,92 @@
"use client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import {
BackupFormatSelect,
BackupPathWarnings,
FilePathRow,
} from "@/components/common-setting-parts";
import { CardDescription } from "@/components/ui/card";
import { assertNever } from "@/lib/assert-never";
import { commands } from "@/lib/bindings";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { type BodyProps, SetupPageBase } from "../-setup-page-base";
export const Route = createFileRoute("/_setup/setup/backups/")({
component: Page,
});
function Page() {
const shouldInstallDeepLink = useGlobalInfo().shouldInstallDeepLink;
return (
<SetupPageBase
heading={tc("setup:backups:heading")}
Body={Body}
nextPage={
shouldInstallDeepLink ? "/setup/system-setting" : "/setup/finish"
}
prevPage={"/setup/project-path"}
pageId={"Backups"}
/>
);
}
function Body({ environment }: BodyProps) {
const projectBackupPath = environment.project_backup_path;
const backupFormat = environment.backup_format;
const queryClient = useQueryClient();
const pickProjectBackupPath = useMutation({
mutationFn: async () => await commands.environmentPickProjectBackupPath(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:backup path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries({
queryKey: ["environmentGetSettings"],
});
},
});
return (
<>
<h3>{tc("setup:backups:location")}</h3>
<CardDescription className={"whitespace-normal"}>
{tc("setup:backups:location description")}
</CardDescription>
<FilePathRow
path={projectBackupPath}
pick={pickProjectBackupPath.mutate}
withOpen={false}
/>
<BackupPathWarnings backupPath={projectBackupPath} />
<div className={"pb-3"} />
<h3>{tc("setup:backups:archive")}</h3>
<CardDescription className={"whitespace-normal"}>
{tc("settings:backup:format description")}
</CardDescription>
<BackupFormatSelect backupFormat={backupFormat} />
</>
);
}

View file

@ -1,19 +1,26 @@
"use client";
import { createFileRoute } from "@tanstack/react-router";
import { CardDescription } from "@/components/ui/card";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { SetupPageBase } from "../setup-page-base";
import { SetupPageBase } from "../-setup-page-base";
export default function Page() {
const isMac = useGlobalInfo().osType === "Darwin";
export const Route = createFileRoute("/_setup/setup/finish/")({
component: Page,
});
function Page() {
const shouldInstallDeepLink = useGlobalInfo().shouldInstallDeepLink;
return (
<SetupPageBase
heading={tc("setup:finish:heading")}
Body={Body}
nextPage={"/projects"}
prevPage={isMac ? "/setup/backups" : "/setup/system-setting"}
prevPage={
shouldInstallDeepLink ? "/setup/system-setting" : "/setup/backups"
}
nextContent={tc("setup:finish:next")}
pageId={null}
/>

View file

@ -0,0 +1,76 @@
"use client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import {
FilePathRow,
ProjectPathWarnings,
} from "@/components/common-setting-parts";
import { CardDescription } from "@/components/ui/card";
import { assertNever } from "@/lib/assert-never";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { type BodyProps, SetupPageBase } from "../-setup-page-base";
export const Route = createFileRoute("/_setup/setup/project-path/")({
component: Page,
});
function Page() {
return (
<SetupPageBase
heading={tc("setup:project-path:heading")}
Body={Body}
nextPage={"/setup/backups"}
prevPage={"/setup/unity-hub"}
pageId={"ProjectPath"}
/>
);
}
function Body({ environment }: BodyProps) {
const queryClient = useQueryClient();
const pickProjectDefaultPath = useMutation({
mutationFn: async () => await commands.environmentPickProjectDefaultPath(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:default project path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries({
queryKey: ["environmentGetSettings"],
});
},
});
return (
<>
<CardDescription className={"whitespace-normal"}>
{tc("setup:project-path:description")}
</CardDescription>
<FilePathRow
path={environment.default_project_path}
pick={pickProjectDefaultPath.mutate}
withOpen={false}
/>
<ProjectPathWarnings projectPath={environment.default_project_path} />
</>
);
}

View file

@ -0,0 +1,107 @@
"use client";
import {
queryOptions,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { Checkbox } from "@/components/ui/checkbox";
import { commands } from "@/lib/bindings";
import { useGlobalInfo } from "@/lib/global-info";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
import { type BodyProps, SetupPageBase } from "../-setup-page-base";
export const Route = createFileRoute("/_setup/setup/system-setting/")({
component: Page,
});
function Page() {
return (
<SetupPageBase
heading={tc("setup:system-setting:heading")}
Body={Body}
nextPage={"/setup/finish"}
prevPage={"/setup/backups"}
pageId={"SystemSetting"}
/>
);
}
const environmentGetSettings = queryOptions({
queryKey: ["environmentGetSettings"],
queryFn: commands.environmentGetSettings,
});
function Body({ environment }: BodyProps) {
const useAlcomForVccProtocol = environment.use_alcom_for_vcc_protocol;
const isBadHostName = useQuery({
queryKey: ["util_is_bad_hostname"],
queryFn: commands.utilIsBadHostname,
initialData: false,
});
const queryClient = useQueryClient();
const setUseAlcomForVccProtocol = useMutation({
mutationFn: async (use: boolean) =>
await commands.environmentSetUseAlcomForVccProtocol(use),
onMutate: async (use) => {
await queryClient.cancelQueries(environmentGetSettings);
const current = queryClient.getQueryData(environmentGetSettings.queryKey);
if (current != null) {
queryClient.setQueryData(environmentGetSettings.queryKey, {
...current,
use_alcom_for_vcc_protocol: use,
});
}
return current;
},
onError: (e, _, prev) => {
console.error(e);
toastThrownError(e);
queryClient.setQueryData(environmentGetSettings.queryKey, prev);
},
onSettled: async () => {
await queryClient.invalidateQueries(environmentGetSettings);
},
});
const isMac = useGlobalInfo().osType === "Darwin";
return (
<>
{!isMac ? (
<div>
<label className={"flex items-center gap-2"}>
<Checkbox
checked={useAlcomForVccProtocol}
onCheckedChange={(e) =>
setUseAlcomForVccProtocol.mutate(e === true)
}
/>
{tc("settings:use alcom for vcc scheme")}
</label>
<p className={"text-sm whitespace-normal text-muted-foreground"}>
{tc("setup:system-setting:vcc scheme description")}
</p>
</div>
) : (
<div>
<p className={"text-sm whitespace-normal text-muted-foreground"}>
{tc("setup:system-setting:macos bug message")}
</p>
</div>
)}
{isBadHostName.data && (
<div className={"mt-3"}>
<p className={"text-sm whitespace-normal text-warning"}>
{tc("setup:system-setting:hostname-with-non-ascii")}
</p>
</div>
)}
</>
);
}

View file

@ -1,5 +1,7 @@
"use client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { FilePathRow } from "@/components/common-setting-parts";
import {
Accordion,
@ -9,15 +11,23 @@ import {
} from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import { CardDescription } from "@/components/ui/card";
import { assertNever } from "@/lib/assert-never";
import { commands } from "@/lib/bindings";
import { tc } from "@/lib/i18n";
import { type BodyProps, SetupPageBase } from "../setup-page-base";
import { tc, tt } from "@/lib/i18n";
import { toastError, toastSuccess, toastThrownError } from "@/lib/toast";
import { type BodyProps, SetupPageBase } from "../-setup-page-base";
export default function Page() {
export const Route = createFileRoute("/_setup/setup/unity-hub/")({
component: Page,
});
function Page() {
return (
<SetupPageBase
heading={tc("setup:unity-hub:heading")}
Body={Body}
// user should set unity hub path so we re-update unity paths
onFinish={() => commands.environmentUpdateUnityPathsFromUnityHub()}
nextPage={"/setup/project-path"}
prevPage={"/setup/appearance"}
pageId={"UnityHub"}
@ -25,9 +35,39 @@ export default function Page() {
);
}
function Body({ environment, refetch }: BodyProps) {
function Body({ environment }: BodyProps) {
const hubInstalled = !!environment.unity_hub;
const queryClient = useQueryClient();
const pickUnityHub = useMutation({
mutationFn: async () => await commands.environmentPickUnityHub(),
onError: (e) => {
console.error(e);
toastThrownError(e);
},
onSuccess: (result) => {
switch (result.type) {
case "NoFolderSelected":
// no-op
break;
case "InvalidSelection":
toastError(tc("general:toast:invalid directory"));
break;
case "Successful":
toastSuccess(tc("settings:toast:unity hub path updated"));
break;
default:
assertNever(result);
}
},
onSettled: async () => {
await queryClient.invalidateQueries({
queryKey: ["environmentGetSettings"],
});
},
});
return (
<>
<CardDescription className={"whitespace-normal"}>
@ -40,12 +80,10 @@ function Body({ environment, refetch }: BodyProps) {
{tc("setup:unity-hub:using this unity hub")}:
</p>
<FilePathRow
withoutSelect
path={environment.unity_hub ?? ""}
pick={commands.environmentPickUnityHub}
refetch={refetch}
pick={pickUnityHub.mutate}
notFoundMessage={"Unity Hub Not Found"}
successMessage={tc("settings:toast:unity hub path updated")}
withOpen={false}
/>
</>
) : (
@ -54,12 +92,18 @@ function Body({ environment, refetch }: BodyProps) {
<div className={"flex flex-row flex-wrap gap-2"}>
<Button
onClick={() =>
commands.utilOpenUrl("https://unity.com/ja/download")
commands.utilOpenUrl(tt("setup:unity-hub:unity hub link"))
}
>
{tc("setup:unity-hub:download unity hub from unity.com")}
</Button>
<Button onClick={refetch}>
<Button
onClick={() =>
queryClient.invalidateQueries({
queryKey: ["environmentGetSettings"],
})
}
>
{tc("setup:unity-hub:recheck installation")}
</Button>
</div>
@ -73,12 +117,10 @@ function Body({ environment, refetch }: BodyProps) {
{tc("setup:unity-hub:detection failed description")}
</p>
<FilePathRow
withoutSelect
path={environment.unity_hub}
pick={commands.environmentPickUnityHub}
refetch={refetch}
path={environment.unity_hub ?? ""}
pick={pickUnityHub.mutate}
notFoundMessage={"Unity Hub Not Found"}
successMessage={tc("settings:toast:unity hub path updated")}
withOpen={false}
/>
</AccordionContent>
</AccordionItem>

View file

@ -1,48 +1,166 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@import "tw-animate-css";
@layer base {
:root {
--background: 0 0% 100%;
--background-start: 190 7.89% 85.1%;
--background-end: 0, 0%, 100%;
--foreground: 240 10% 20%;
--card: 0 0% 100%;
--card-foreground: 240 10% 35%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 20%;
--primary: 240 5.9% 20%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 30%;
--info: 207 90% 54%;
--info-foreground: 210 40% 98%;
--success: 122 39% 49%;
--success-foreground: 210 40% 98%;
--warning: 52.15, 100%, 46.47%;
--warning-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.75rem;
@custom-variant dark (&:is(.dark *));
@custom-variant compact (&:is([compact] *));
@theme inline {
--background-image-gradient-radial: radial-gradient(var(--tw-gradient-stops));
--background-image-gradient-conic: conic-gradient(
from 180deg at 50% 50%,
var(--tw-gradient-stops)
);
--font-sans: system-ui;
--font-path: system-ui;
--font-mono: consolas, monospace;
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--radius-lg: var(--radius);
--radius-md: calc(var(--radius) - 2px);
--radius-sm: calc(var(--radius) - 4px);
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
.dark {
--bg-color: 240 10% 13%;
--fg-color: 240 10% 85%;
--secondary-bg: 240 3.7% 19%;
--primary-fg: 240 5.9% 15%;
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
@layer utilities {
.anchor-none {
overflow-anchor: none;
}
}
:root {
--background: hsl(0 0% 100%);
--background-start: hsl(190 7.89% 85.1%);
--background-end: hsl(0, 0%, 100%);
--foreground: hsl(240 10% 20%);
--card: hsl(0 0% 100%);
--card-foreground: hsl(240 10% 35%);
--popover: hsl(0 0% 100%);
--popover-foreground: hsl(240 10% 20%);
--primary: hsl(240 5.9% 20%);
--primary-foreground: hsl(0 0% 98%);
--secondary: hsl(240 4.8% 95.9%);
--secondary-foreground: hsl(240 5.9% 10%);
--muted: hsl(240 4.8% 95.9%);
--muted-foreground: oklch(0.556 0 0);
--accent: hsl(240 4.8% 95.9%);
--accent-foreground: hsl(240 5.9% 30%);
--info: hsl(207 90% 54%);
--info-foreground: hsl(210 40% 98%);
--success: hsl(122 39% 49%);
--success-foreground: hsl(210 40% 98%);
--warning: hsl(52.15, 100%, 46.47%);
--warning-foreground: hsl(240 10% 13%);
--destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: hsl(0 0% 98%);
--border: hsl(240 5.9% 90%);
--input: hsl(240 5.9% 90%);
--ring: hsl(240 5.9% 10%);
--radius: 0.75rem;
}
.dark {
--bg-color: hsl(240 10% 13%);
--fg-color: hsl(240 10% 85%);
--secondary-bg: hsl(240 3.7% 19%);
--primary-fg: hsl(240 5.9% 15%);
--background: var(--bg-color);
--background-start: hsl(0 0% 3%);
--background-end: hsl(10 8% 15%);
--foreground: var(--fg-color);
--card: var(--bg-color);
--card-foreground: var(--fg-color);
--popover: var(--bg-color);
--popover-foreground: var(--fg-color);
--primary: var(--fg-color);
--primary-foreground: var(--primary-fg);
--secondary: var(--secondary-bg);
--secondary-foreground: var(--fg-color);
--muted: var(--secondary-bg);
--muted-foreground: oklch(0.708 0 0);
--accent: var(--secondary-bg);
--accent-foreground: var(--fg-color);
--info: hsl(207 90% 54%);
--info-foreground: hsl(210 40% 90%);
--success: hsl(122 39% 49%);
--success-foreground: hsl(210 40% 90%);
--warning: hsl(52.15, 100%, 46.47%);
--warning-foreground: hsl(240 10% 13%);
--destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: var(--fg-color);
--border: var(--secondary-bg);
--input: var(--secondary-bg);
--ring: hsl(240 4.9% 83.9%);
}
@media (prefers-color-scheme: dark) {
.system {
--bg-color: hsl(240 10% 13%);
--fg-color: hsl(240 10% 85%);
--secondary-bg: hsl(240 3.7% 19%);
--primary-fg: hsl(240 5.9% 15%);
--background: var(--bg-color);
--background-start: 0 0% 3%;
--background-end: 10 8% 15%;
--background-start: hsl(0 0% 3%);
--background-end: hsl(10 8% 15%);
--foreground: var(--fg-color);
--card: var(--bg-color);
--card-foreground: var(--fg-color);
@ -53,57 +171,52 @@
--secondary: var(--secondary-bg);
--secondary-foreground: var(--fg-color);
--muted: var(--secondary-bg);
--muted-foreground: 240 5% 74%;
--muted-foreground: oklch(0.708 0 0);
--accent: var(--secondary-bg);
--accent-foreground: var(--fg-color);
--info: 207 90% 54%;
--info-foreground: 210 40% 90%;
--success: 122 39% 49%;
--success-foreground: 210 40% 90%;
--warning: 52.15, 100%, 46.47%;
--warning-foreground: 210 40% 90%;
--destructive: 0 84.2% 60.2%;
--info: hsl(207 90% 54%);
--info-foreground: hsl(210 40% 90%);
--success: hsl(122 39% 49%);
--success-foreground: hsl(210 40% 90%);
--warning: hsl(52.15, 100%, 46.47%);
--warning-foreground: hsl(240 10% 13%);
--destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: var(--fg-color);
--border: var(--secondary-bg);
--input: var(--secondary-bg);
--ring: 240 4.9% 83.9%;
--ring: hsl(240 4.9% 83.9%);
}
}
body {
--toastify-font-family: var(--font-sans);
--toastify-color-light: var(--background);
/*--toastify-color-info: #3498db;*/
--toastify-color-success: var(--success);
/*--toastify-color-warning: #f1c40f;*/
--toastify-color-error: var(--destructive);
/*--toastify-color-transparent: rgba(255, 255, 255, 0.7);*/
--toastify-icon-color-info: var(--toastify-color-info);
--toastify-icon-color-success: var(--toastify-color-success);
--toastify-icon-color-warning: var(--toastify-color-warning);
--toastify-icon-color-error: var(--toastify-color-error);
/* size and fonts are not customized */
--toastify-text-color-light: var(--foreground);
--toastify-color-progress-info: var(--toastify-color-info);
--toastify-color-progress-success: var(--toastify-color-success);
--toastify-color-progress-warning: var(--toastify-color-warning);
--toastify-color-progress-error: var(--toastify-color-error);
.Toastify__toast {
box-shadow: 0 4px 12px hsl(var(--primary) / 0.05);
}
@media (prefers-color-scheme: dark) {
.system {
--bg-color: 240 10% 13%;
--fg-color: 240 10% 85%;
--secondary-bg: 240 3.7% 19%;
--primary-fg: 240 5.9% 15%;
--background: var(--bg-color);
--background-start: 0 0% 3%;
--background-end: 10 8% 15%;
--foreground: var(--fg-color);
--card: var(--bg-color);
--card-foreground: var(--fg-color);
--popover: var(--bg-color);
--popover-foreground: var(--fg-color);
--primary: var(--fg-color);
--primary-foreground: var(--primary-fg);
--secondary: var(--secondary-bg);
--secondary-foreground: var(--fg-color);
--muted: var(--secondary-bg);
--muted-foreground: 240 5% 74%;
--accent: var(--secondary-bg);
--accent-foreground: var(--fg-color);
--info: 207 90% 54%;
--info-foreground: 210 40% 90%;
--success: 122 39% 49%;
--success-foreground: 210 40% 90%;
--warning: 52.15, 100%, 46.47%;
--warning-foreground: 210 40% 90%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: var(--fg-color);
--border: var(--secondary-bg);
--input: var(--secondary-bg);
--ring: 240 4.9% 83.9%;
}
.Toastify__close-button--light {
color: hsl(var(--foreground));
}
}
@ -112,20 +225,20 @@
@apply border-border;
}
button:not(:disabled),
[role="button"]:not(:disabled) {
cursor: pointer;
}
button:disabled,
[role="button"]:disabled {
cursor: not-allowed;
}
body {
@apply bg-background text-foreground;
color: hsl(var(--foreground));
background: linear-gradient(
to bottom,
transparent,
hsl(var(--background-end))
) hsl(var(--background-start));
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
background: linear-gradient(to bottom, transparent, var(--background-end))
var(--background-start);
}
}
@ -163,43 +276,18 @@ code {
@apply font-mono;
}
html {
overscroll-behavior: none;
}
/*
this is a ad-hoc way to apply toastify variables.
We could not find way to correctly order the toastify css and this css so put in body to get higher specificity
*/
body {
--toastify-color-light: hsl(var(--background));
/*--toastify-color-info: #3498db;*/
--toastify-color-success: hsl(var(--success));
/*--toastify-color-warning: #f1c40f;*/
--toastify-color-error: hsl(var(--destructive));
/*--toastify-color-transparent: rgba(255, 255, 255, 0.7);*/
--toastify-icon-color-info: var(--toastify-color-info);
--toastify-icon-color-success: var(--toastify-color-success);
--toastify-icon-color-warning: var(--toastify-color-warning);
--toastify-icon-color-error: var(--toastify-color-error);
/* size and fonts are not customized */
--toastify-text-color-light: hsl(var(--foreground));
--toastify-color-progress-info: var(--toastify-color-info);
--toastify-color-progress-success: var(--toastify-color-success);
--toastify-color-progress-warning: var(--toastify-color-warning);
--toastify-color-progress-error: var(--toastify-color-error);
.Toastify__toast {
box-shadow: 0 4px 12px hsl(var(--primary) / 0.05);
}
.Toastify__close-button--light {
color: hsl(var(--foreground));
}
}
/* Radix ui sets display:block for each scroll viewport element but it seem it make worse */
[data-radix-scroll-area-viewport] > div {
/* biome-ignore lint/complexity/noImportantStyles: necessary to override element */
display: block !important;
}
@ -207,7 +295,22 @@ body {
* Add padding end for horizontal scroll bar of scrollable card if vertical scroll bar is invisible
* This prevents the horizontal scroll bar hide corner of the card
*/
.vrc-get-scrollable-card:not(:has(> .vrc-get-scrollable-card-vertical-bar)) > div[data-radix-scroll-area-viewport] > div > div.vrc-get-scrollable-card-horizontal-bar {
.vrc-get-scrollable-card:not(
:has(> .vrc-get-scrollable-card-vertical-bar)
) > div[data-radix-scroll-area-viewport]
> div
> div.vrc-get-scrollable-card-horizontal-bar {
@apply pe-2.5;
}
/*
* Add padding end for the content area of scrollable card if vertical scroll bar is visible
* This prevents the table / items from being hidden behind the vertical scroll bar
*/
.vrc-get-scrollable-card:has(
> .vrc-get-scrollable-card-vertical-bar
) > div[data-radix-scroll-area-viewport]
> div {
@apply pe-2.5;
}
@ -215,3 +318,51 @@ body {
contain-intrinsic-size: 0 7em;
contain: size;
}
.fade-in {
animation: fadeInUp 0.1s ease-in-out;
}
.slide-left {
animation: slideLeft 0.1s ease-in-out;
}
.slide-right {
animation: slideRight 0.1s ease-in-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideLeft {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideRight {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}

11
vrc-get-gui/app/index.tsx Normal file
View file

@ -0,0 +1,11 @@
import { createFileRoute, Outlet } from "@tanstack/react-router";
import ErrorPage from "@/app/-error";
export const Route = createFileRoute("/")({
component: RouteComponent,
errorComponent: ErrorPage,
});
function RouteComponent() {
return <Outlet />;
}

View file

@ -1,40 +0,0 @@
import type { Metadata } from "next";
import "./globals.css";
import "react-toastify/ReactToastify.css";
import { Providers } from "@/components/providers";
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
// biome-ignore lint/a11y/useHtmlLang: we cannot determine the language of the content. we add in inner div.
<html>
<head>
{/* empty png to avoid erros */}
<link
rel="icon"
type="image/png"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII="
/>
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
<script src="vrc-get://localhost/global-info.js" />
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
<script src="http://vrc-get.localhost/global-info.js" />
</head>
<body
className={
"font-sans w-screen h-screen flex flex-row overflow-hidden whitespace-nowrap"
}
>
<Providers>{children}</Providers>
</body>
</html>
);
}

View file

@ -1,14 +1,16 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"ignore": [
"templates",
"node_modules",
".next",
"out",
"gen",
"lib/bindings.ts",
"build"
"includes": [
"**",
"!project-templates",
"!node_modules",
"!.next",
"!out",
"!gen",
"!lib/bindings.ts",
"!lib/routeTree.gen.ts",
"!build"
]
},
"formatter": {
@ -23,9 +25,20 @@
// In my opinion, '!.' => '?.' is not reasonable for all cases, so I disabled automatic fix.
"fix": "none",
"level": "error"
},
"noRestrictedGlobals": {
"level": "error",
"options": {
"deniedGlobals": {
"close": "window.close is unlikely to be called"
}
}
}
},
"suspicious": {
// false positives with tailwind css
// see https://github.com/biomejs/biome/issues/7223
"noUnknownAtRules": "off",
"noAssignInExpressions": "off"
},
"correctness": {
@ -37,16 +50,41 @@
"name": "useDocumentEvent",
"closureIndex": 1,
"dependenciesIndex": 2
},
{
"name": "useEffectEvent",
"stableResult": true
}
]
}
},
"noUnusedImports": "error"
},
"a11y": {
"noLabelWithoutControl": {
"level": "warn",
"options": {
"inputComponents": [
"Checkbox",
"SelectTrigger",
"BackupFormatSelect"
]
}
}
}
},
"enabled": true
},
"organizeImports": {
"enabled": true
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"css": {
"parser": {
"tailwindDirectives": true
}
}
}

3
vrc-get-gui/booth/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
thumbnail.png
booth.zip
app-icon.png

Some files were not shown because too many files have changed in this diff Show more