Skip to content

Implement undo for configuration item lists - #3477

Open
JunMyungH wants to merge 65 commits into
mainfrom
3439/undo-for-configitem-list
Open

JunMyungH wants to merge 65 commits into
mainfrom
3439/undo-for-configitem-list

Conversation

@JunMyungH

@JunMyungH JunMyungH commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds Global Undo functionality for configuration item lists and profiles, allowing users to reverse accidental changes without losing their existing configuration.

Users can undo actions such as adding, deleting, duplicating, renaming, toggling, and moving configuration items, as well as several profile operations.

The implementation includes a shared Undo history, accessible from the project toolbar next to the Save button, and supports Ctrl+Z and multi-step history navigation.

Screenshots / recordings

001.mp4

Acceptance criteria

  • Undo configuration item operations:
    • Add and Delete
    • Duplicate
    • Rename
    • Reorder within a profile
    • Move between profiles
    • Bulk Delete and Toggle
    • Undo committed configuration item edits
  • Undo profile operations:
    • Create
    • Rename
    • Delete
    • Merge
  • Config List View Undo history:
    • Display Undo and History controls next to the Save button
    • Support Ctrl+Z and Undo from the Edit menu
    • Support restoring previous states through the history dropdown
    • Record bulk operations as a single Undo step
    • Preserve history when an Undo operation fails
    • Clear history when switching projects
  • State consistency:
    • Restore configuration items with their original GUIDs, order, and relevant settings
    • Keep backend and frontend states synchronized after Undo
    • Preserve existing Global Undo history when applying or canceling local edits
    • Keep native text input Undo functionality working
    • Restore the project's clean state when all recorded changes are undone
    • Prevent unnecessary unsaved changes warnings after returning to the original saved state

DoD Checklist

  • Unit tests available
    • .NET backend
  • Frontend tests
  • i18n - All user-facing strings are translated
    • core (en,de,es)
    • additional langs

Related issues

fixes #3439
relates to #2886
depends on #3438

Out-of-scope

Notes

  • This implementation builds upon the local Input Config Undo functionality introduced in Implement undo for input configuration items #3438.
  • The Config List View Undo history is managed by the .NET backend to maintain the authoritative project state.
  • Configuration item and profile operations are recorded as bounded history entries.
  • Failed Undo operations preserve the existing history and display a notification.
  • Additional .NET unit tests cover Undo operations, failure handling, history preservation, and project dirty-state restoration.
  • Playwright tests cover history navigation, keyboard shortcuts, error notifications, and interactions between local and Global Undo.
  • All local tests passed before pushing the branch.

… showing undo and history on button for now. added test according to that, if drawer changes would be saved as one history in config item
…tead and aligned undo button in drawelr left
…ary doubled items in InputConfigDialog were deleted
@JunMyungH
JunMyungH requested a review from DocMoebiuz as a code owner October 29, 2026 18:45
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Translation Statistics:
Language: DE (Core)

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: ES (Core)

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: FI

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: JA

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: KO

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: PT

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

Language: RU

  • Percentage Complete: 100.00%
  • Missing Keys: 0/651

GitHub Workflow Comment:

Translation Statistics

Language Core Language Percentage Complete Missing Keys
DE ✅ 100.00% 0
ES ✅ 100.00% 0
FI ❌ 100.00% 0
JA ❌ 100.00% 0
KO ❌ 100.00% 0
PT ❌ 100.00% 0
RU ❌ 100.00% 0

@github-actions

Copy link
Copy Markdown

Build for this pull request:
MobiFlightConnector.zip

@github-actions

Copy link
Copy Markdown

Build for this pull request:
MobiFlightConnector.zip

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Build for this pull request:
MobiFlightConnector.zip

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Build for this pull request:
MobiFlightConnector.zip

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Build for this pull request:
MobiFlightConnector.zip

@DocMoebiuz DocMoebiuz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am very excited to see this coming along!

Please review my first round of feedback.
I am convinced that especially the CommandUpdateConfigItem vs CommandConfigContextMenu can be simplified.

The .NET C# side will benefit from a more thorough review in another round.

Comment on lines -168 to 170

setTimeout(() => setActiveConfigFileIndex(configFiles.length), 200)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why was this removed?

Comment on lines +19 to +28
const handleToggle = () => {
publish({
key: "CommandConfigContextMenu",
payload: {
action: "toggle",
item,
},
} as CommandConfigContextMenu)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CommandUpdateConfigItem - instead of adding new individual actions to the the backend, the frontend could still modify the object as needed and simply "annotate" the type of change together with the CommandUpdateConfigItem.

The benefit: backend stays KISS, and mechanism is extensible.

Comment on lines +32 to 38
const saveChanges = (newName: string) => {
if (newName === item.Name) return
publish({
key: "CommandUpdateConfigItem",
payload: { item: updatedItem },
} as CommandUpdateConfigItem)
key: "CommandConfigContextMenu",
payload: { action: "rename", item: { ...item, Name: newName } },
} as CommandConfigContextMenu)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as comment above... but here you are also modifying the config object on the frontend side.
So that is incosistent.

My suggestion from above would make sure that our approach is consistent.

Frontend modifies the item.
Frontend publishes "CommandUpdateConfigItem" command + modify annotation "rename"
Backend only simply stores the new state, doesn't perform any modification logic.

Comment on lines 267 to +293
const deleteSelected = useCallback(() => {
const action = "delete"
const selectedConfigs = table.getSelectedRowModel().rows.map((row) => {
return row.original as IConfigItem
})
const selectedConfigs = table
.getSelectedRowModel()
.rows.map((row) => row.original as IConfigItem)

if (selectedConfigs.length === 0) return

publish({
key: "CommandConfigBulkAction",
payload: {
action: action,
items: selectedConfigs,
},
})
// Clear selection after deletion
if (selectedConfigs.length === 1) {
// Use the single-item delete path.
// The backend records an Undo snapshot here.
publish({
key: "CommandConfigContextMenu",
payload: {
action: "delete",
item: selectedConfigs[0],
},
} as CommandConfigContextMenu)
} else {
publish({
key: "CommandConfigBulkAction",
payload: {
action: "delete",
items: selectedConfigs,
},
})
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why is it necessary to treat single delete different?

Command: preset ? preset.code : null,
} as MsfsInputAction,
t("Dialog.InputConfigWizard.History.ActionPresetChanged"),
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

don't resolve i18n labels on creating and storing a history entry, resolve labels at the time when they are displayed to the user.

Add,
Duplicate,
BulkDelete,
Toggle,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this would not be required if we use the CommandUpdateConfigItem and provide change annotation.

ProfileAdded,
ProfileRename,
ProfileDeleted,
ItemRename,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this would not be required if we use the CommandUpdateConfigItem and provide change annotation.

ProfileDeleted,
ItemRename,
ProfileMerged,
ItemEdited

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this would not be required if we use the CommandUpdateConfigItem and provide change annotation.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

it looks like on the backend side we are applying a new concept, where you have undoActions instead of just a snapshot?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Now that you moved classes to ConfigListUndoManager, this class requires updates

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement undo for configuration item lists

2 participants