Page MenuHomePhabricator

Add simulate mode to Cat-a-lot for readonly testing
Open, Needs TriagePublicFeature

Description

As a developer, I would like to have option in Cat-a-lot Preferences to set it in simulation mode. In simulation mode it would work as normally as possible in user interactions and code perspective, but would skip actual editing.

Simplest way would be to use Mediawiki:Gadget-Cat-a-lot.js doAPICall() function for calling callback() instead of editing if simulate mode is on. Alternatively it could be done in Mediawiki:Gadget-libAPI.js if we want to implement feature deeper in the stack.

Also, as the edit API calls are asynchronous, parallel and rather slow; this needs to be simulated somehow.

Event Timeline

Hey @Zache,
I was trying to approach this task, and here’s my understanding and the approach I’m thinking of:

Understanding of the Task:
In Simulation Mode, the file actions (move, copy, delete) will behave exactly as they do normally. Files will visually appear to be moved or categorized in the interface, and changes will be reflected in the UI immediately. Since the UI is modified through JavaScript without waiting for server confirmation, it behaves as if the change was real. These changes will be reverted after a page reload because no actual modification happens on the server.

Approach I’m Thinking:

  1. Add Simulation Mode in Preferences : Add a checkbox in Cat-a-lot Preferences to enable/disable Simulation Mode.
  2. UI Indication for Simulation Mode : Show a pop-up or mention in an alert to highlight that Simulation Mode is enabled, so the user doesn’t get confused if they forgot to turn it off.
  3. Modify Gadget-libAPI.js : If Simulation Mode is enabled, doRequest() will skip real API calls. It will return a simulated success response with a random delay using setTimeout() to mimic real API behavior.
  4. Simulated API Responses : The simulated responses will contain a simulate: true flag along with relevant API data. (Currently I feel we can also skip this step but will be useful if we want to perform any specific action based on whether the response is simulated or real.)

Please let me know if this approach looks good or if I should refine anything before proceeding!

Yes, idea is pretty solid. Just some notes when I was looking the Gadget-libAPI.js code.

I think i would define a new config variable api.config.simulationMode to Mediawiki:Gadget-libAPI.js . In Mediawiki:Gadget-Cat-a-lot.js this variable can be accessed usign mw.libs.commons.api.config.simulationMode .

If simulationMode is True then it would skip the actual edits. However, I think that this needs to be done where the actual $.ajax query is done inside doRequest() ( Line 426 ). In there our fakeAjax query should least do following things

  • update counters (Line 620 )
  • call allways() to decrement the concurrency counters.
  • call callback cb() with simulated result to pretend that edit succeeded.
  • print something to javascript console that there is hint that the we are in simulation mode

simulate: true in the responses is good idea. Also, everything inside Gadget-Cat-a-lot.js side sounded good.

Thanks, @Zache!
Defining api.config.simulationMode in Mediawiki:Gadget-libAPI.js makes a lot of sense because it centralizes the configuration, making it easier to manage in both files and toggle Simulation Mode without modifying multiple parts of the code.
I’ll proceed with this approach and keep you posted on the progress.

Hi @Zache ,

I've been revisiting the simulation mode feature for Cat‑a‑lot capability that should allow the tool to visually simulate file actions without actually performing any server-side edits. The idea is for the UI to behave as if the edit were successful while no actual changes are made. This is particularly useful for testing and debugging, with changes automatically reverting on page reload.

My Understanding and Approach:

Intended Behavior:
In Simulation Mode, every action should appear to work normally: files are moved or recategorized in the interface immediately. However, behind the scenes, no real API calls are executed the system should simply simulate a successful response. This means we should mimic the asynchronous nature and concurrency of actual edits, including updating counters and providing a simulated response with a flag.

Initial Approach:
I first tried to integrate the simulation mode by modifying Gadget-libAPI.js directly. The plan was to add a configuration variable (mw.libs.commons.api.config.simulationMode) and check its value inside the doRequest() function (around where the $.ajax call is made). In simulation mode, the function would skip the real API call, update necessary counters, and invoke the callback with a simulated success response after a random delay.

Feedback & Adjustments:
@Zache, you mentioned that doing this inside the AJAX query (around Line 426) would be ideal, ensuring that counters are updated and the concurrency counter is decremented properly. However, this approach didn’t yield the expected results in my testing, likely due to the complexity and timing issues within the API calls.

Alternate Approach Attempted:
I then experimented with "monkey-patching" the mw.libs.commons.api.editPage function in my user-space JavaScript. The goal was to override this function to simulate an API response when Simulation Mode is enabled. The simulated function logs a message, delays with setTimeout(), and then invokes the callback with a fake revision ID and timestamp while including a simulate: true flag. This method works to some extent, but I’m still refining the mechanism, especially the proper updating of counters and ensuring the UI feedback reliably mirrors real edit behavior.

Status & Next Steps:
I’m still working on achieving full parity between simulation and real edit flows. I want to ensure that every aspect, including asynchronous behavior, concurrency management, and detailed UI feedback, is accurately simulated. Any insights or suggestions on improving the integration, especially around counter updates and mimicking the API’s behavior more reliably, would be highly appreciated.

Hi, I've made a patch that solves this problem. The feature allows users to enable a simulation mode via a checkbox in the UI, which visually mimics category changes without performing real edits. The logic is integrated with Gadget-libAPI.js and respects the concurrency flow. I added the checkbox directly to the main dialog box so there would be minimal edits to the code files.

Here are the diffs to the updated files:

Let me know if you’d like any changes or refinements!

Simulation mode seems to be working as expected. (ie. when it is ON it doesn't do edits, if it is OFF then it edits.). Some quick comments.

Placement of the setting
I would add the simulation mode setting to the Cat-a-lot preferences so it would not be visible by default.

One approach could be adding a preference setting called "Show Cat-a-lot simulation toggle in UI" that works similarly to the current implementation, but the toggle is only visible in the UI when enabled from preferences.

Another alternative would be to move the simulation mode toggle to preferences altogether, with an indicator in the Cat-a-lot window showing when simulation mode is active. However, this approach wouldn't provide a quick way to toggle it on/off on fly, which could be useful when developing code.

Notification
You could use mw.notify() instead of a jQuery dialog to indicate that the setting has been changed, so the user won't need to click to close it.

mw.notify('Cat-a-lot Simulation Mode: ' + (this.checked ? 'ON' : 'OFF'), { tag: 'cat-a-lot-simulation-mode' });

Gadget-libAPI.js

In line 434, I would move the body of the simulate mode to a function so the code would just be a function call, which would make the code easier to read. The code itself in the simulation mode is OK.

if (api.config.simulationMode) {
    doSimulatedEdit();
    return;
}

$.ajax({
...

Second $.ajax() call
There is also another AJAX call for edits in line 1143. I am not sure where/how this is used and I would need to investigate it further. For now, I would just add a test: if simulatedMode is ON, then show alert() with text that simulation mode is not supported in this function. Please notify about the error to the ticket https://phabricator.wikimedia.org/T389858. After the alert, just do a return without doing the edit.

The idea for this is just to confirm that it doesn't do edits in case the user has set simulation mode ON and that code won't fail silently.

Thanks for the feedback. I've been able to implement everything you suggested:

  • Replaced the jQuery UI dialog with mw.notify()
  • The simulation logic is now in a doSimulatedEdit() helper function.
  • Added a fallback alert to the second $.ajax() and referenced task T389858.

The only thing I’m still figuring out is the Simulation Mode checkbox placement. Right now, if the user enables the toggle in Preferences, the checkbox doesn’t show up right away because the Cat-a-lot UI isn’t reloaded — CAL.init() only runs once when the page loads. So the user has to refresh the page to see the change, which isn't ideal.

To avoid this, I’m thinking of going with the second approach, removing the checkbox from the UI completely and just letting users turn Simulation Mode on/off directly in the Preferences panel. Since Preferences are loaded before CAL.init() runs, the setting would apply right away with no reload needed. This would simplify things and make the behavior more consistent.

The downside is it’s not as quick to toggle during editing, but I think it’s a cleaner solution overall. Let me know what you think!

Hey @Zache, quick update, I decided to go with the second approach, removing the checkbox from the UI completely and just letting users turn Simulation Mode on/off directly in the preferences. This new setup applies the preference immediately on page load, so there’s no need to manually reload or delay UI elements. It’s cleaner and avoids the two-step toggle issue we had earlier.