Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion desktop/docs/UI_FEEDBACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Single source of truth for how the shell surfaces status, errors, and confirmati

**Use for:** destructive actions, import-with-issues, closing unsaved observation tabs.

- `confirmDestructiveAction()` for destructive flows (always strict production-tier wording).
- `confirmDestructiveAction()` for destructive flows (clear, profile-scoped wording).
- `confirm()` from `@tauri-apps/plugin-dialog` for save-anyway / import-anyway / tab discard (Save / Don't save / Cancel via separate flows).

## Retired patterns
Expand Down
2 changes: 1 addition & 1 deletion desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ode-desktop",
"private": true,
"version": "1.1.1",
"version": "1.2.0",
"packageManager": "pnpm@10.33.2",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "odedesktop"
version = "1.1.1"
version = "1.2.0"
description = "ODE Desktop"
authors = ["OpenDataEnsemble.org"]
edition = "2024"
Expand Down
14 changes: 0 additions & 14 deletions desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,6 @@ pub struct BundleFormSpec {
pub ui_schema: Value,
}

/// Client-side guardrail for confirmations (not interpreted by Synkronus).
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
enum ProfileEnvironment {
#[default]
Production,
Staging,
Development,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
enum DefaultAppMode {
Expand All @@ -132,8 +122,6 @@ struct ServerProfile {
database_path: String,
attachments_path: Option<String>,
#[serde(default)]
environment: ProfileEnvironment,
#[serde(default)]
default_app_mode: DefaultAppMode,
#[serde(default)]
custom_app_developer_mode: bool,
Expand Down Expand Up @@ -847,7 +835,6 @@ fn default_app_config(data_dir: &Path) -> AppConfigFile {
workspace_path: Some(workspace_dir.to_string_lossy().to_string()),
database_path: db_path.to_string_lossy().to_string(),
attachments_path: None,
environment: ProfileEnvironment::default(),
default_app_mode: DefaultAppMode::default(),
custom_app_developer_mode: false,
custom_app_local_folder: None,
Expand All @@ -870,7 +857,6 @@ fn migrate_legacy_workspace(workspace_path: &str, _data_dir: &Path) -> AppConfig
workspace_path: Some(workspace_path.to_string()),
database_path: db.to_string_lossy().to_string(),
attachments_path: None,
environment: ProfileEnvironment::default(),
default_app_mode: DefaultAppMode::default(),
custom_app_developer_mode: false,
custom_app_local_folder: None,
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "ODE Desktop",
"version": "1.1.1",
"version": "1.2.0",
"identifier": "org.opendataensemble.custodian",
"build": {
"beforeDevCommand": "pnpm dev",
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/components/ObservationIndexPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ export function ObservationIndexPrompt() {
<p
className="notice warn"
style={{ fontSize: '0.85rem', margin: '1rem 0 0.5rem' }}>
Indexes are created on this profile&apos;s production database (the
same store used for sync and observations). This is not limited to
Indexes are created in this profile&apos;s local database (the same
store used for sync and observations). This is not limited to
developer mode or the dev mirror folder.
</p>
<button
Expand Down
16 changes: 7 additions & 9 deletions desktop/src/lib/destructivePolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,32 @@ export async function confirmDestructiveAction(
detail: string,
): Promise<boolean> {
const title = describeAction(kind);
const dialogTitle = `${title} — PRODUCTION`;
const messageBody = `${detail}\n\nType OK only if this is intentional.`;

if (isTauri()) {
return await tauriConfirm(messageBody, {
title: dialogTitle,
return await tauriConfirm(detail, {
title,
kind: 'warning',
});
}

return window.confirm(`${dialogTitle}\n\n${messageBody}`);
return window.confirm(`${title}\n\n${detail}`);
}

function describeAction(kind: DestructiveActionKind): string {
switch (kind) {
case 'push':
return 'Push local changes to Synkronus';
return 'Push observations';
case 'bundle_push':
return 'Upload / replace app bundle on server';
return 'Upload app bundle';
case 'bulk_delete':
return 'Delete multiple items';
return 'Delete observations';
case 'profile_delete':
return 'Delete profile';
case 'server_reset':
return 'Reset server repository';
case 'local_reset':
return 'Reset local data';
default:
return 'Destructive action';
return 'Confirm action';
}
}
22 changes: 17 additions & 5 deletions desktop/src/lib/syncUiCopy.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import { describe, expect, it } from 'vitest';
import { productionPushConfirmDetail } from './syncUiCopy';
import { pushConfirmMessage } from './syncUiCopy';

describe('productionPushConfirmDetail', () => {
it('includes the dirty observation count', () => {
expect(productionPushConfirmDetail(12)).toBe(
'Push 12 pending observation(s) to production?',
describe('pushConfirmMessage', () => {
it('includes the observation count and profile label', () => {
expect(pushConfirmMessage(12, 'AnthroCollect field')).toBe(
'Push 12 observations to AnthroCollect field?',
);
});

it('uses singular observation for one row', () => {
expect(pushConfirmMessage(1, 'Local dev')).toBe(
'Push 1 observation to Local dev?',
);
});

it('falls back when the profile label is empty', () => {
expect(pushConfirmMessage(3, ' ')).toBe(
'Push 3 observations to this profile?',
);
});
});
11 changes: 8 additions & 3 deletions desktop/src/lib/syncUiCopy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/** Production push confirmation body (no server URL). */
export function productionPushConfirmDetail(dirtyCount: number): string {
return `Push ${dirtyCount} pending observation(s) to production?`;
/** Push confirmation body shown before syncing dirty observations. */
export function pushConfirmMessage(
observationCount: number,
profileLabel: string,
): string {
const label = profileLabel.trim() || 'this profile';
const noun = observationCount === 1 ? 'observation' : 'observations';
return `Push ${observationCount} ${noun} to ${label}?`;
}
2 changes: 1 addition & 1 deletion desktop/src/lib/synkConstants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/** Must match Synkronus OpenAPI `x-ode-version` (semver). */
export const SYNKRONUS_CLIENT_VERSION = '1.1.1';
export const SYNKRONUS_CLIENT_VERSION = '1.2.0';
2 changes: 0 additions & 2 deletions desktop/src/pages/ProfilesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ function emptyProfile(dataDirectory: string): ServerProfile {
workspacePath,
databasePath,
attachmentsPath: null,
environment: 'production',
defaultAppMode: 'data_management',
};
}
Expand Down Expand Up @@ -177,7 +176,6 @@ export function ProfilesPage() {
workspacePath: ws,
databasePath,
attachmentsPath: null,
environment: 'production',
};
await upsertProfileRemote(profile);
if (password.trim()) {
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/pages/SyncPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
auditPendingPushMissingAttachments,
type MissingAttachmentIssue,
} from '../lib/pushAttachmentAudit';
import { productionPushConfirmDetail } from '../lib/syncUiCopy';
import { pushConfirmMessage } from '../lib/syncUiCopy';
import { useSynkServerStatus } from '../hooks/useSynkServerStatus';
import {
selectActiveProfileState,
Expand Down Expand Up @@ -167,7 +167,7 @@ export function SyncPage() {
if (
!(await confirmDestructiveAction(
'push',
productionPushConfirmDetail(dirtyCount),
pushConfirmMessage(dirtyCount, profileLabel),
))
) {
return;
Expand Down
5 changes: 0 additions & 5 deletions desktop/src/types/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,6 @@ export interface AuthSession {
expiresAt?: number;
}

/** Client-side server tier for confirmation strictness (mirrors Rust `ProfileEnvironment`). */
export type ProfileEnvironment = 'production' | 'staging' | 'development';

/** Default sidebar mode when opening the app or switching profiles (mirrors Rust `DefaultAppMode`). */
export type DefaultAppMode = 'data_management' | 'workbench';

Expand All @@ -227,8 +224,6 @@ export interface ServerProfile {
workspacePath?: string | null;
databasePath: string;
attachmentsPath?: string | null;
/** Client-only guardrail; not sent to Synkronus as an API mode. */
environment?: ProfileEnvironment | null;
/** Which mode subtree to open by default for this profile. */
defaultAppMode?: DefaultAppMode | null;
/** When true, Workbench custom app loads from a mirrored local folder instead of `bundles/active`. */
Expand Down
4 changes: 2 additions & 2 deletions formulus/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ android {
applicationId = "org.opendataensemble.formulus"
minSdk = rootProject.ext.minSdkVersion
targetSdk = rootProject.ext.targetSdkVersion
versionCode = 14
versionName = "1.1.1"
versionCode = 24
versionName = "1.2.0"

buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", (findProperty("newArchEnabled") ?: "false").toString()

Expand Down
8 changes: 4 additions & 4 deletions formulus/ios/Formulus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 24;
DEVELOPMENT_TEAM = ZZ9482ZVMJ;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Formulus/Info.plist;
Expand All @@ -304,7 +304,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.1;
MARKETING_VERSION = 1.2.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand All @@ -329,15 +329,15 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 24;
DEVELOPMENT_TEAM = ZZ9482ZVMJ;
INFOPLIST_FILE = Formulus/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.1;
MARKETING_VERSION = 1.2.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
4 changes: 2 additions & 2 deletions formulus/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion formulus/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formulus-app",
"version": "1.1.1",
"version": "1.2.0",
"packageManager": "pnpm@10.33.2",
"type": "module",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion synkronus-cli/internal/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

var (
// Version is the CLI version, set during build
Version = "1.1.2"
Version = "1.2.0"
// BuildDate is the date when the CLI was built
BuildDate = "unknown"
// CommitHash is the git commit hash
Expand Down
12 changes: 6 additions & 6 deletions synkronus-cli/versioninfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"FixedFileInfo": {
"FileVersion": {
"Major": 1,
"Minor": 1,
"Patch": 2,
"Minor": 2,
"Patch": 0,
"Build": 0
},
"ProductVersion": {
"Major": 1,
"Minor": 1,
"Patch": 2,
"Minor": 2,
"Patch": 0,
"Build": 0
},
"FileFlagsMask": "3f",
Expand All @@ -22,14 +22,14 @@
"Comments": "Synkronus CLI Tool",
"CompanyName": "OpenDataEnsemble",
"FileDescription": "Synkronus CLI - A command-line interface for the Synkronus API",
"FileVersion": "1.1.2.0",
"FileVersion": "1.2.0.0",
"InternalName": "synk",
"LegalCopyright": "© 2025 OpenDataEnsemble",
"LegalTrademarks": "",
"OriginalFilename": "synk.exe",
"PrivateBuild": "",
"ProductName": "Synkronus CLI",
"ProductVersion": "1.1.2.0",
"ProductVersion": "1.2.0.0",
"SpecialBuild": ""
},
"VarFileInfo": {
Expand Down
2 changes: 1 addition & 1 deletion synkronus-portal/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "synkronus-portal",
"private": true,
"version": "1.1.1",
"version": "1.2.0",
"packageManager": "pnpm@10.33.2",
"license": "MIT",
"type": "module",
Expand Down
Loading