mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-07-08 11:10:43 +00:00
fix: batch of webui fixes, update webui deps, apply formatter, and regen protos
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
devShellPkgs = with pkgs; [
|
||||
go goreleaser nodejs_20 pnpm_9
|
||||
protobuf buf protoc-gen-go protoc-gen-go-grpc
|
||||
protobuf buf protoc-gen-go protoc-gen-go-grpc protoc-gen-connect-go
|
||||
gnumake git restic rclone zsh oh-my-posh
|
||||
];
|
||||
in
|
||||
@@ -47,6 +47,7 @@
|
||||
buf
|
||||
protoc-gen-go
|
||||
protoc-gen-go-grpc
|
||||
protoc-gen-connect-go
|
||||
|
||||
# General build tools
|
||||
gnumake
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc (unknown)
|
||||
// source: v1/authentication.proto
|
||||
|
||||
@@ -77,10 +77,10 @@ type AuthenticationServer interface {
|
||||
type UnimplementedAuthenticationServer struct{}
|
||||
|
||||
func (UnimplementedAuthenticationServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Login not implemented")
|
||||
}
|
||||
func (UnimplementedAuthenticationServer) HashPassword(context.Context, *types.StringValue) (*types.StringValue, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method HashPassword not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method HashPassword not implemented")
|
||||
}
|
||||
func (UnimplementedAuthenticationServer) mustEmbedUnimplementedAuthenticationServer() {}
|
||||
func (UnimplementedAuthenticationServer) testEmbeddedByValue() {}
|
||||
@@ -93,7 +93,7 @@ type UnsafeAuthenticationServer interface {
|
||||
}
|
||||
|
||||
func RegisterAuthenticationServer(s grpc.ServiceRegistrar, srv AuthenticationServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAuthenticationServer was
|
||||
// If the following call panics, it indicates UnimplementedAuthenticationServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
@@ -913,7 +913,7 @@ func (x *RestoreSnapshotRequest) GetTarget() string {
|
||||
|
||||
type ListSnapshotFilesRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RepoGuid string `protobuf:"bytes,1,opt,name=repo_guid,json=repoGuid,proto3" json:"repo_guid,omitempty"`
|
||||
RepoId string `protobuf:"bytes,1,opt,name=repo_id,json=repoId,proto3" json:"repo_id,omitempty"`
|
||||
SnapshotId string `protobuf:"bytes,2,opt,name=snapshot_id,json=snapshotId,proto3" json:"snapshot_id,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
@@ -950,9 +950,9 @@ func (*ListSnapshotFilesRequest) Descriptor() ([]byte, []int) {
|
||||
return file_v1_service_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *ListSnapshotFilesRequest) GetRepoGuid() string {
|
||||
func (x *ListSnapshotFilesRequest) GetRepoId() string {
|
||||
if x != nil {
|
||||
return x.RepoGuid
|
||||
return x.RepoId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -2032,9 +2032,9 @@ const file_v1_service_proto_rawDesc = "" +
|
||||
"\vsnapshot_id\x18\x02 \x01(\tR\n" +
|
||||
"snapshotId\x12\x12\n" +
|
||||
"\x04path\x18\x03 \x01(\tR\x04path\x12\x16\n" +
|
||||
"\x06target\x18\x04 \x01(\tR\x06target\"l\n" +
|
||||
"\x18ListSnapshotFilesRequest\x12\x1b\n" +
|
||||
"\trepo_guid\x18\x01 \x01(\tR\brepoGuid\x12\x1f\n" +
|
||||
"\x06target\x18\x04 \x01(\tR\x06target\"h\n" +
|
||||
"\x18ListSnapshotFilesRequest\x12\x17\n" +
|
||||
"\arepo_id\x18\x01 \x01(\tR\x06repoId\x12\x1f\n" +
|
||||
"\vsnapshot_id\x18\x02 \x01(\tR\n" +
|
||||
"snapshotId\x12\x12\n" +
|
||||
"\x04path\x18\x03 \x01(\tR\x04path\"V\n" +
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc (unknown)
|
||||
// source: v1/service.proto
|
||||
|
||||
@@ -382,70 +382,70 @@ type BackrestServer interface {
|
||||
type UnimplementedBackrestServer struct{}
|
||||
|
||||
func (UnimplementedBackrestServer) GetConfig(context.Context, *emptypb.Empty) (*Config, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetConfig not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) SetConfig(context.Context, *Config) (*Config, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetConfig not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) SetupSftp(context.Context, *SetupSftpRequest) (*SetupSftpResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetupSftp not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetupSftp not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) CheckRepoExists(context.Context, *CheckRepoExistsRequest) (*CheckRepoExistsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckRepoExists not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CheckRepoExists not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) AddRepo(context.Context, *AddRepoRequest) (*Config, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddRepo not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AddRepo not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) RemoveRepo(context.Context, *RemoveRepoRequest) (*Config, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RemoveRepo not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveRepo not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetOperationEvents(*emptypb.Empty, grpc.ServerStreamingServer[OperationEvent]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetOperationEvents not implemented")
|
||||
return status.Error(codes.Unimplemented, "method GetOperationEvents not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetOperations(context.Context, *GetOperationsRequest) (*OperationList, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetOperations not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetOperations not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListSnapshots not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListSnapshots not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) ListSnapshotFiles(context.Context, *ListSnapshotFilesRequest) (*ListSnapshotFilesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListSnapshotFiles not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListSnapshotFiles not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) Backup(context.Context, *BackupRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Backup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Backup not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) DoRepoTask(context.Context, *DoRepoTaskRequest) (*ScheduleTaskResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DoRepoTask not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DoRepoTask not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) Forget(context.Context, *ForgetRequest) (*ScheduleTaskResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Forget not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Forget not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) Restore(context.Context, *RestoreSnapshotRequest) (*ScheduleTaskResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Restore not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Restore not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) Cancel(context.Context, *CancelOperationRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Cancel not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Cancel not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetLogs(*LogDataRequest, grpc.ServerStreamingServer[types.BytesValue]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetLogs not implemented")
|
||||
return status.Error(codes.Unimplemented, "method GetLogs not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) RunCommand(context.Context, *RunCommandRequest) (*RunCommandResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RunCommand not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RunCommand not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetDownloadURL(context.Context, *GetDownloadURLRequest) (*types.StringValue, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDownloadURL not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetDownloadURL not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) ClearHistory(context.Context, *ClearHistoryRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClearHistory not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ClearHistory not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PathAutocomplete not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PathAutocomplete not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetSummaryDashboard(context.Context, *emptypb.Empty) (*SummaryDashboardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetSummaryDashboard not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSummaryDashboard not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GeneratePairingToken(context.Context, *GeneratePairingTokenRequest) (*GeneratePairingTokenResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GeneratePairingToken not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GeneratePairingToken not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) mustEmbedUnimplementedBackrestServer() {}
|
||||
func (UnimplementedBackrestServer) testEmbeddedByValue() {}
|
||||
@@ -458,7 +458,7 @@ type UnsafeBackrestServer interface {
|
||||
}
|
||||
|
||||
func RegisterBackrestServer(s grpc.ServiceRegistrar, srv BackrestServer) {
|
||||
// If the following call pancis, it indicates UnimplementedBackrestServer was
|
||||
// If the following call panics, it indicates UnimplementedBackrestServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc (unknown)
|
||||
// source: v1sync/syncservice.proto
|
||||
|
||||
@@ -72,7 +72,7 @@ type BackrestSyncServiceServer interface {
|
||||
type UnimplementedBackrestSyncServiceServer struct{}
|
||||
|
||||
func (UnimplementedBackrestSyncServiceServer) Sync(grpc.BidiStreamingServer[SyncStreamItem, SyncStreamItem]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Sync not implemented")
|
||||
return status.Error(codes.Unimplemented, "method Sync not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestSyncServiceServer) mustEmbedUnimplementedBackrestSyncServiceServer() {}
|
||||
func (UnimplementedBackrestSyncServiceServer) testEmbeddedByValue() {}
|
||||
@@ -85,7 +85,7 @@ type UnsafeBackrestSyncServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterBackrestSyncServiceServer(s grpc.ServiceRegistrar, srv BackrestSyncServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedBackrestSyncServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedBackrestSyncServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@@ -195,10 +195,10 @@ type BackrestSyncStateServiceServer interface {
|
||||
type UnimplementedBackrestSyncStateServiceServer struct{}
|
||||
|
||||
func (UnimplementedBackrestSyncStateServiceServer) GetPeerSyncStatesStream(*SyncStateStreamRequest, grpc.ServerStreamingServer[PeerState]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetPeerSyncStatesStream not implemented")
|
||||
return status.Error(codes.Unimplemented, "method GetPeerSyncStatesStream not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestSyncStateServiceServer) SetRemoteClientConfig(context.Context, *SetRemoteClientConfigRequest) (*SetRemoteClientConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetRemoteClientConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetRemoteClientConfig not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestSyncStateServiceServer) mustEmbedUnimplementedBackrestSyncStateServiceServer() {
|
||||
}
|
||||
@@ -212,7 +212,7 @@ type UnsafeBackrestSyncStateServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterBackrestSyncStateServiceServer(s grpc.ServiceRegistrar, srv BackrestSyncStateServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedBackrestSyncStateServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedBackrestSyncStateServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
@@ -347,18 +347,7 @@ func (s *BackrestHandler) ListSnapshots(ctx context.Context, req *connect.Reques
|
||||
func (s *BackrestHandler) ListSnapshotFiles(ctx context.Context, req *connect.Request[v1.ListSnapshotFilesRequest]) (*connect.Response[v1.ListSnapshotFilesResponse], error) {
|
||||
query := req.Msg
|
||||
|
||||
// Lookup the repo by GUID to handle reimports correctly.
|
||||
cfg, err := s.config.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get config: %w", err)
|
||||
}
|
||||
repoCfg := config.FindRepoByGUID(cfg, query.RepoGuid)
|
||||
if repoCfg == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("repo not found: %q", query.RepoGuid))
|
||||
}
|
||||
|
||||
// Get the orchestrator for the repo if its configuration is available.
|
||||
repo, err := s.orchestrator.GetRepoOrchestrator(repoCfg.Id)
|
||||
repo, err := s.orchestrator.GetRepoOrchestrator(query.RepoId)
|
||||
if err != nil {
|
||||
return nil, withLookupCode(fmt.Errorf("failed to get repo: %w", err))
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ message RestoreSnapshotRequest {
|
||||
}
|
||||
|
||||
message ListSnapshotFilesRequest {
|
||||
string repo_guid = 1;
|
||||
string repo_id = 1;
|
||||
string snapshot_id = 2;
|
||||
string path = 3;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file google/api/annotations.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file google/api/http.proto (package google.api, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file types/value.proto (package types, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1/authentication.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1/config.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1/crypto.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1/operations.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1/restic.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
||||
// @generated by protoc-gen-es v2.11.0 with parameter "target=ts"
|
||||
// @generated from file v1sync/syncservice.proto (package v1sync, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
"react-icons": "^5.5.0",
|
||||
"react-js-cron": "^5.2.0",
|
||||
"react-router": "^8.1.0",
|
||||
"react-router-dom": "^7.18.1",
|
||||
"react-virtualized": "^9.22.6",
|
||||
"recharts": "^3.9.0"
|
||||
},
|
||||
|
||||
Generated
+28
-46
@@ -68,9 +68,6 @@ importers:
|
||||
react-router:
|
||||
specifier: ^8.1.0
|
||||
version: 8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
react-router-dom:
|
||||
specifier: ^7.18.1
|
||||
version: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
react-virtualized:
|
||||
specifier: ^9.22.6
|
||||
version: 9.22.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
@@ -731,36 +728,42 @@ packages:
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.6':
|
||||
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
||||
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.6':
|
||||
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.6':
|
||||
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
|
||||
@@ -885,36 +888,42 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.1.3':
|
||||
resolution: {integrity: sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.1.3':
|
||||
resolution: {integrity: sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.1.3':
|
||||
resolution: {integrity: sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.1.3':
|
||||
resolution: {integrity: sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.1.3':
|
||||
resolution: {integrity: sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.1.3':
|
||||
resolution: {integrity: sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==}
|
||||
@@ -976,56 +985,67 @@ packages:
|
||||
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
|
||||
resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.54.0':
|
||||
resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==}
|
||||
@@ -1519,10 +1539,6 @@ packages:
|
||||
cookie-es@3.1.1:
|
||||
resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==}
|
||||
|
||||
cookie@1.1.1:
|
||||
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
copy-to-clipboard@3.3.3:
|
||||
resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
|
||||
|
||||
@@ -1906,24 +1922,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.32.0:
|
||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||
@@ -2360,23 +2380,6 @@ packages:
|
||||
redux:
|
||||
optional: true
|
||||
|
||||
react-router-dom@7.18.1:
|
||||
resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
|
||||
react-router@7.18.1:
|
||||
resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
react-router@8.1.0:
|
||||
resolution: {integrity: sha512-Mdfi61uObuvWNN9OhChOC0HV6YWOIfKRzEWOvCHRSuQg8IM+Nv10edaM/2HE8ZixBpUTdQbruyWqC3sDkkh9vw==}
|
||||
engines: {node: '>=22.22.0'}
|
||||
@@ -2483,9 +2486,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
set-cookie-parser@2.7.2:
|
||||
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||
|
||||
sha.js@2.4.11:
|
||||
resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
|
||||
hasBin: true
|
||||
@@ -4402,7 +4402,7 @@ snapshots:
|
||||
|
||||
babel-plugin-macros@3.1.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.6
|
||||
'@babel/runtime': 7.29.7
|
||||
cosmiconfig: 7.1.0
|
||||
resolve: 1.22.11
|
||||
|
||||
@@ -4479,8 +4479,6 @@ snapshots:
|
||||
|
||||
cookie-es@3.1.1: {}
|
||||
|
||||
cookie@1.1.1: {}
|
||||
|
||||
copy-to-clipboard@3.3.3:
|
||||
dependencies:
|
||||
toggle-selection: 1.0.6
|
||||
@@ -5324,20 +5322,6 @@ snapshots:
|
||||
'@types/react': 19.2.17
|
||||
redux: 5.0.1
|
||||
|
||||
react-router-dom@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
react-router: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
|
||||
react-router@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
cookie: 1.1.1
|
||||
react: 19.2.7
|
||||
set-cookie-parser: 2.7.2
|
||||
optionalDependencies:
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
|
||||
react-router@8.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
cookie-es: 3.1.1
|
||||
@@ -5483,8 +5467,6 @@ snapshots:
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
set-cookie-parser@2.7.2: {}
|
||||
|
||||
sha.js@2.4.11:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
|
||||
+39
-47
@@ -1,4 +1,10 @@
|
||||
import React, { Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import React, {
|
||||
Suspense,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
FiCalendar,
|
||||
FiDatabase,
|
||||
@@ -66,12 +72,16 @@ import {
|
||||
Routes,
|
||||
useNavigate,
|
||||
useParams,
|
||||
Link as RouterLink,
|
||||
useLocation,
|
||||
} from "react-router-dom";
|
||||
} from "react-router";
|
||||
import { MainContentAreaTemplate } from "../components/layout/MainContentArea";
|
||||
import { create } from "@bufbuild/protobuf";
|
||||
import { PeerState, PlanMetadata, RepoMetadata, SetRemoteClientConfigRequestSchema } from "../../gen/ts/v1sync/syncservice_pb";
|
||||
import {
|
||||
PeerState,
|
||||
PlanMetadata,
|
||||
RepoMetadata,
|
||||
SetRemoteClientConfigRequestSchema,
|
||||
} from "../../gen/ts/v1sync/syncservice_pb";
|
||||
import { useSyncStates } from "../state/peerStates";
|
||||
import * as m from "../paraglide/messages";
|
||||
import { Link } from "../components/ui/link";
|
||||
@@ -145,7 +155,11 @@ const RepoViewContainer = () => {
|
||||
borderColor="blue.200"
|
||||
fontSize="sm"
|
||||
color="blue.800"
|
||||
_dark={{ bg: "blue.950", borderColor: "blue.800", color: "blue.200" }}
|
||||
_dark={{
|
||||
bg: "blue.950",
|
||||
borderColor: "blue.800",
|
||||
color: "blue.200",
|
||||
}}
|
||||
>
|
||||
This is a remote repo from{" "}
|
||||
<strong>{repo.originInstanceId}</strong>. Operation history only
|
||||
@@ -293,11 +307,7 @@ const PeerNavItem = ({
|
||||
{name}
|
||||
</Text>
|
||||
{onEdit && (
|
||||
<Box
|
||||
opacity={0}
|
||||
_groupHover={{ opacity: 1 }}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
<Box opacity={0} _groupHover={{ opacity: 1 }} transition="opacity 0.2s">
|
||||
<IconButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
@@ -471,20 +481,12 @@ const SidebarPlanItem = React.memo(
|
||||
onClick={() => onNav(planPath)}
|
||||
userSelect="none"
|
||||
>
|
||||
<Text
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
whiteSpace="nowrap"
|
||||
>
|
||||
<Text overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
|
||||
{plan.id}
|
||||
</Text>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Box
|
||||
opacity={0}
|
||||
_groupHover={{ opacity: 1 }}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
<Box opacity={0} _groupHover={{ opacity: 1 }} transition="opacity 0.2s">
|
||||
<IconButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
@@ -545,11 +547,7 @@ const SidebarRepoItem = React.memo(
|
||||
onClick={() => onNav(repoPath)}
|
||||
userSelect="none"
|
||||
>
|
||||
<Text
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
whiteSpace="nowrap"
|
||||
>
|
||||
<Text overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
|
||||
{repo.id}
|
||||
</Text>
|
||||
{repo.originInstanceId && (
|
||||
@@ -565,11 +563,7 @@ const SidebarRepoItem = React.memo(
|
||||
)}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Box
|
||||
opacity={0}
|
||||
_groupHover={{ opacity: 1 }}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
<Box opacity={0} _groupHover={{ opacity: 1 }} transition="opacity 0.2s">
|
||||
<IconButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
@@ -600,18 +594,17 @@ const SidebarContent = ({ onClose }: { onClose?: () => void }) => {
|
||||
|
||||
const isActive = (path: string) => location.pathname === path;
|
||||
|
||||
const reposById = useMemo(() => config ? keyBy(config.repos, (r) => r.id) : {}, [config?.repos]);
|
||||
const reposById = useMemo(
|
||||
() => (config ? keyBy(config.repos, (r) => r.id) : {}),
|
||||
[config?.repos],
|
||||
);
|
||||
|
||||
// Replicate getSidenavItems functionality with Chakra components
|
||||
if (!config) return null;
|
||||
|
||||
const configPlans = config.plans || [];
|
||||
const localRepos = (config.repos || []).filter(
|
||||
(r) => !r.originInstanceId,
|
||||
);
|
||||
const remoteRepos = (config.repos || []).filter(
|
||||
(r) => !!r.originInstanceId,
|
||||
);
|
||||
const localRepos = (config.repos || []).filter((r) => !r.originInstanceId);
|
||||
const remoteRepos = (config.repos || []).filter((r) => !!r.originInstanceId);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -1060,7 +1053,9 @@ const AuthenticationBoundary = ({
|
||||
const timeoutPromise = new Promise<never>((_, reject) =>
|
||||
setTimeout(
|
||||
() =>
|
||||
reject(new Error("Request timed out, backend may be unavailable")),
|
||||
reject(
|
||||
new Error("Request timed out, backend may be unavailable"),
|
||||
),
|
||||
10000,
|
||||
),
|
||||
);
|
||||
@@ -1070,9 +1065,8 @@ const AuthenticationBoundary = ({
|
||||
])) as Config;
|
||||
setConfig(config);
|
||||
if (shouldShowSettings(config)) {
|
||||
const { SettingsModal } = await import(
|
||||
"../features/settings/SettingsModal"
|
||||
);
|
||||
const { SettingsModal } =
|
||||
await import("../features/settings/SettingsModal");
|
||||
showModal(<SettingsModal />);
|
||||
} else {
|
||||
showModal(null);
|
||||
@@ -1134,12 +1128,10 @@ const AuthenticationBoundary = ({
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
const IconForResource = React.memo(
|
||||
({ selector }: { selector: OpSelector }) => {
|
||||
const status = useResourceStatus(selector);
|
||||
return iconForStatus(status);
|
||||
},
|
||||
);
|
||||
const IconForResource = React.memo(({ selector }: { selector: OpSelector }) => {
|
||||
const status = useResourceStatus(selector);
|
||||
return iconForStatus(status);
|
||||
});
|
||||
|
||||
const iconForStatus = (status: OperationStatus) => {
|
||||
const color = colorForStatus(status);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Toaster } from "../components/ui/toaster";
|
||||
|
||||
import "react-js-cron/dist/styles.css";
|
||||
|
||||
import { HashRouter } from "react-router-dom";
|
||||
import { HashRouter } from "react-router";
|
||||
import { AppProvider } from "./provider";
|
||||
|
||||
const Root = ({ children }: { children: React.ReactNode }) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { useUserPreferences } from "../lib/userPreferences";
|
||||
import { Config } from "../../gen/ts/v1/config_pb";
|
||||
import { Config, Repo } from "../../gen/ts/v1/config_pb";
|
||||
import { backrestService } from "../api/client";
|
||||
|
||||
// Config Context Logic
|
||||
@@ -14,6 +14,24 @@ export const useConfig = (): ConfigCtx => {
|
||||
return context;
|
||||
};
|
||||
|
||||
// Lookup of repos by their stable GUID, derived from the config. Cached on the
|
||||
// config object's identity so it is built once per config instance and shared
|
||||
// across all consumers (and garbage-collected when the config is replaced),
|
||||
// giving an O(1) lookup instead of rescanning config.repos on every render.
|
||||
const EMPTY_REPOS_BY_GUID: Map<string, Repo> = new Map();
|
||||
const reposByGuidCache = new WeakMap<Config, Map<string, Repo>>();
|
||||
|
||||
export const useReposByGuid = (): Map<string, Repo> => {
|
||||
const [config] = useConfig();
|
||||
if (!config) return EMPTY_REPOS_BY_GUID;
|
||||
let byGuid = reposByGuidCache.get(config);
|
||||
if (!byGuid) {
|
||||
byGuid = new Map(config.repos.map((r) => [r.guid, r]));
|
||||
reposByGuidCache.set(config, byGuid);
|
||||
}
|
||||
return byGuid;
|
||||
};
|
||||
|
||||
export function AppProvider(props: { children: React.ReactNode }) {
|
||||
useUserPreferences(); // Ensure locale is synced on startup
|
||||
const [config, setConfig] = useState<Config | null>(null);
|
||||
|
||||
@@ -31,7 +31,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
||||
{React.cloneElement(children, {
|
||||
...(startElement && { ps: "calc(var(--input-height) - 6px)" }),
|
||||
...(endElement && { pe: "calc(var(--input-height) - 6px)" }),
|
||||
...children.props,
|
||||
...(children.props as Record<string, unknown>),
|
||||
})}
|
||||
{endElement && (
|
||||
<InputElement placement="end" {...endElementProps}>
|
||||
|
||||
Vendored
+2
@@ -3,6 +3,8 @@ declare module "*.svg" {
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module "*.css";
|
||||
|
||||
declare module "*/paraglide/messages" {
|
||||
const messages: any;
|
||||
export = messages;
|
||||
|
||||
@@ -64,7 +64,8 @@ function agoText(ms: number): string {
|
||||
const s = Math.floor((Date.now() - ms) / 1000);
|
||||
if (s < 45) return m.dashboard_time_just_now();
|
||||
if (s < 90) return m.dashboard_time_a_minute_ago();
|
||||
if (s < 3600) return m.dashboard_time_minutes_ago({ count: Math.floor(s / 60) });
|
||||
if (s < 3600)
|
||||
return m.dashboard_time_minutes_ago({ count: Math.floor(s / 60) });
|
||||
if (s < 5400) return m.dashboard_time_an_hour_ago();
|
||||
if (s < 86400) {
|
||||
const h = Math.floor(s / 3600);
|
||||
@@ -82,7 +83,9 @@ function untilText(ms: number): string | null {
|
||||
const s = Math.floor((ms - Date.now()) / 1000);
|
||||
if (s <= 0) return m.dashboard_time_due_now();
|
||||
if (s < 5400)
|
||||
return m.dashboard_time_in_minutes({ count: Math.max(1, Math.round(s / 60)) });
|
||||
return m.dashboard_time_in_minutes({
|
||||
count: Math.max(1, Math.round(s / 60)),
|
||||
});
|
||||
if (s < 172800)
|
||||
return m.dashboard_time_in_hours({ count: Math.round(s / 3600) });
|
||||
return m.dashboard_time_in_days({ count: Math.round(s / 86400) });
|
||||
@@ -181,7 +184,9 @@ interface SummaryStatus {
|
||||
color: string;
|
||||
}
|
||||
|
||||
function summaryStatus(summary: SummaryDashboardResponse_Summary): SummaryStatus {
|
||||
function summaryStatus(
|
||||
summary: SummaryDashboardResponse_Summary,
|
||||
): SummaryStatus {
|
||||
const rb = summary.recentBackups;
|
||||
const latestStatus = rb?.status[0];
|
||||
const latestTs = Number(rb?.timestampMs[0] ?? 0);
|
||||
@@ -326,7 +331,7 @@ function progressFromOp(op: Operation): LiveProgress | null {
|
||||
const useLiveProgress = (
|
||||
planId: string,
|
||||
running: boolean,
|
||||
onFinished: () => void,
|
||||
onFinished?: () => void,
|
||||
) => {
|
||||
const [progress, setProgress] = useState<LiveProgress | null>(null);
|
||||
|
||||
@@ -350,7 +355,7 @@ const useLiveProgress = (
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
setProgress(null);
|
||||
onFinished();
|
||||
onFinished?.();
|
||||
return;
|
||||
}
|
||||
const p = progressFromOp(op);
|
||||
@@ -942,7 +947,7 @@ const MultihostSummary = ({
|
||||
return map;
|
||||
}, [config?.repos]);
|
||||
|
||||
const knownHostTiles: JSX.Element[] = [];
|
||||
const knownHostTiles: React.JSX.Element[] = [];
|
||||
for (const cfgPeer of multihostConfig?.knownHosts ?? []) {
|
||||
const peerState = peerStates.get(cfgPeer.keyid);
|
||||
if (!peerState) continue;
|
||||
@@ -955,7 +960,7 @@ const MultihostSummary = ({
|
||||
);
|
||||
}
|
||||
|
||||
const authorizedClientTiles: JSX.Element[] = [];
|
||||
const authorizedClientTiles: React.JSX.Element[] = [];
|
||||
for (const cfgPeer of multihostConfig?.authorizedClients ?? []) {
|
||||
const peerState = peerStates.get(cfgPeer.keyid);
|
||||
if (!peerState) continue;
|
||||
|
||||
@@ -59,6 +59,7 @@ import { OperationIcon } from "./OperationIcon";
|
||||
import { LogView } from "../../components/common/LogView";
|
||||
|
||||
import { create } from "@bufbuild/protobuf";
|
||||
import { useReposByGuid } from "../../app/provider";
|
||||
import { OperationListView } from "./OperationListView";
|
||||
import * as m from "../../paraglide/messages";
|
||||
import { FormModal } from "../../components/common/FormModal";
|
||||
@@ -107,9 +108,17 @@ export const OperationRow = ({
|
||||
showDelete?: boolean;
|
||||
}>) => {
|
||||
const showModal = useShowModal();
|
||||
const reposByGuid = useReposByGuid();
|
||||
const displayType = getTypeForDisplay(operation);
|
||||
const setRefresh = useState(0)[1];
|
||||
|
||||
// The operation's repoId reflects the repo's name when the operation was
|
||||
// recorded, which may be stale if the repo was removed and re-added under a
|
||||
// different name. Resolve the current repoId from the stable repoGuid so that
|
||||
// actions (e.g. browsing files, restoring) target the repo as it exists now.
|
||||
const currentRepoId =
|
||||
reposByGuid.get(operation.repoGuid)?.id ?? operation.repoId;
|
||||
|
||||
useEffect(() => {
|
||||
if (operation.status === OperationStatus.STATUS_INPROGRESS) {
|
||||
const interval = setInterval(() => {
|
||||
@@ -293,8 +302,7 @@ export const OperationRow = ({
|
||||
<SnapshotBrowser
|
||||
snapshotId={snapshotOp.snapshot!.id}
|
||||
snapshotOpId={operation.id}
|
||||
repoId={operation.repoId}
|
||||
repoGuid={operation.repoGuid}
|
||||
repoId={currentRepoId}
|
||||
planId={operation.planId}
|
||||
/>
|
||||
),
|
||||
|
||||
@@ -117,7 +117,6 @@ const findInTree = (
|
||||
|
||||
export const SnapshotBrowser = ({
|
||||
repoId,
|
||||
repoGuid,
|
||||
planId,
|
||||
snapshotId,
|
||||
snapshotOpId,
|
||||
@@ -125,7 +124,6 @@ export const SnapshotBrowser = ({
|
||||
snapshotId: string;
|
||||
snapshotOpId?: bigint;
|
||||
repoId: string;
|
||||
repoGuid: string;
|
||||
planId?: string;
|
||||
}>) => {
|
||||
const showModal = useShowModal();
|
||||
@@ -174,7 +172,7 @@ export const SnapshotBrowser = ({
|
||||
// But we can trigger a load for root immediately to populate it if expanded.
|
||||
loadData("/");
|
||||
setExpandedKeys(new Set(["/"])); // Auto-expand root for better UX
|
||||
}, [repoId, repoGuid, snapshotId]);
|
||||
}, [repoId, snapshotId]);
|
||||
|
||||
const loadData = async (key: string) => {
|
||||
// Check if node exists first
|
||||
@@ -201,7 +199,7 @@ export const SnapshotBrowser = ({
|
||||
const resp = await backrestService.listSnapshotFiles(
|
||||
create(ListSnapshotFilesRequestSchema, {
|
||||
path,
|
||||
repoGuid,
|
||||
repoId,
|
||||
snapshotId,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"types": ["node"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"ignoreDeprecations": "6.0",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
Reference in New Issue
Block a user