-
Notifications
You must be signed in to change notification settings - Fork 42
migration recycle bin app
The Trash window is now an .os.php app (apps/trash/) driven by the App Framework instead of a PHP module plus a TypeScript bundle. The window keeps the frozen id desktop-mode-recycle-bin, so everything bound to it carries over untouched: desktop shortcuts, dock placements and the Apps & Plugins row, the drag-to-trash drop targets (window body and closed dock tile alike), the desktop-theme icon slots, and the closed-window tile art swap (icon-state.ts). The store, the capture hooks, the realtime channels and the REST routes are unchanged — same trash, new window.
| Surface | Replacement |
|---|---|
Filter openstation_recycle_bin_window_args
|
openstation_app_manifest — $manifest['width'], ['icon'], ['placement'], ['dock_order'], … for $id === 'desktop-mode-recycle-bin'. |
Filter openstation_recycle_bin_template_html
|
There is no server template. The body is a client view; the JS openstation.recycleBin.columns filter still shapes the table, and the data-os-recycle-bin-root hook still marks the window root for drop targets. |
PHP functions openstation_recycle_bin_render_template(), _register_window(), _localize_config()
|
The app registers itself; its config rides the window config blob (wp.os.getWindowConfig( 'desktop-mode-recycle-bin' )), not wp_localize_script. |
Script handle desktop-mode-recycle-bin, bundle assets/js/recycle-bin[.min].js, window.openStationRecycleBinConfig
|
The shared openstation-app-runtime bundle plus the app's companion client view (assets/js/apps/trash[.min].js). Nothing to enqueue, no config global. |
The whole src/recycle-bin/ directory |
The app owns its code: apps/trash/trash.os.ts (the client view over the dispatch wire and ctx.fetch) and apps/trash/parts/ — table-visuals.ts (cell renderers + the columns filter), empty-loop.ts, realtime.ts, and the wire types in types.ts. The one shell-side piece, the closed tile's empty/full art, is src/desktop-files/recycle-bin-icon-state.ts, beside the drop targets that share its frozen id. |
- Every store/capture/realtime surface:
openstation_recycle_bin_capture_post_types,_query_args,_items/_item,_user_can_view|restore|purge|use,_count,_empty_chunk_size(filters);_item_captured,_before/after_restore,_before/after_purge,_emptied(actions). - The REST routes under
/desktop-mode/v1/recycle-bin(GET /,POST /restore,POST /purge,POST /empty,GET /count) — the badge poller, the app's chunked Empty loop and third-party integrations keep using them. - The JS
openstation.recycleBin.columnsfilter, theos-recycle-bin-changeddocument event, theopenstation.recycleBin.changedhook, and the per-typeos.<type>.changedbroadcasts. - The stylesheet handle
desktop-mode-recycle-bin(assets/css/recycle-bin.css) stays on the boot path — it paints the drag-to-trash highlight on the closed bin's dock tile. - The window id, title, size, dock position (
dock_order40),placeablerow, gate, and everything the user sees.
The bin window was 2,155 lines — a 1,305-line imperative bundle, a 198-line REST client, a 366-line registration/template module and 286 lines of routes it used for itself. As an app it is ~640: two declared actions (restore, purge), a data() over the same store, and a client view whose filter, search and Refresh all ride the built-in refresh. The port also drove two framework additions every app now has: $os->icon() / ctx.host.setIcon() (state-driven tile art — the empty/full bin swap) and ctx.extra (App::config() values, which is how both drawings reach the client once instead of riding every response).
Drops from WP Explorer, desktop placements/folders and pinned notes appear in an open Trash window immediately; the closed bin also switches its artwork immediately. Restore, Delete forever, Pin to desktop, Undo and Empty Trash hide affected visible rows while their requests run. Destructive confirmations still come first. Pending incoming rows cannot be restored or purged until their server permissions arrive.
The internal src/desktop-files/trash-optimistic.ts presentation store is shared across bundles through createSharedStore. It overlays typed row identities (type:id) on each window's server snapshot. It does not emit a successful content-change broadcast before a request succeeds. Failed operations roll back individually; successful drops keep their overlay through the mounted windows' reconciliation requests. Type/search filters still apply to pending rows, and the server supplies the final counts, metadata and permissions.
The open window accepts the same drops as the dock, including uploaded files dragged from folder windows. Its drop target follows the mounted app body through asynchronous loading, re-rendering and close/reopen, so registration does not depend on the body already existing when the window opens.
This wiki is generated from the docs/ directory — edits made here are overwritten by the next sync.
To change a page, open a pull request against docs/.
Guides
- Development guide
- Releasing openstation
- Agents security model
- API Index
- The App Framework — a window in one PHP file
- Architecture
- Bridge protocol — wiring overview
- <os-*> component reference
- Data model — where OpenStation keeps its data
- Native Desktop Host — Experimental
- Desktop themes
- Dock customization — two registries, one mental model
- The event-driven framework
- Files on the Desktop
- Folder sharing
- Getting Started
- Hooks Reference
- Icons
- JavaScript Reference
- The Living Tree — algorithm definition
- Window-scoped MIO
- Mio
- Mobile — the phone layer
- Multisite
- Native Windows & Framework Interop
- OpenStation Network
- Plugin compatibility layer
- Progressive Web App (PWA)
- Station Home
- Using openstation from your own plugin
- Workspaces
Migration notes
- Migration: built-in activity channels move to the os/ namespace
- Migration — Code Blue becomes an App Framework app
- Migration — AI comment scoring leaves core
- Migration: window, wallpaper and widget bundles load on demand
- Migration — Posts, Pages, Users, User Edit, Plugins and Comments become App Framework apps
- Migration — the navigation model
- Migration — OpenStation Preferences becomes an App Framework app
- Performance settings move to Extended options
- Presence storage migration
- Migration — the Recycle Bin becomes an App Framework app
- Migration — the shell boots from its own screen
- Migration — Station Home becomes an App Framework app
- Migration: a native window's tabs move to the window chrome
- Migration — WP Explorer becomes the my-wordpress app
- Migration — WordPress package globals are no longer ambient
More
All examples
- AI Agents — extend and invoke from a plugin
- wp.os.ai.ask() — programmatic AI Copilot
- Tune the AI model config
- App layout recipes
- Custom arrange-menu action
- Open a child window its owner can't cover
- Style a specific admin page inside the iframe
- Code Blue — register your plugin's log file
- Open a file in the Code editor (deep-link from any window)
- Connect to a window — title-bar button + iframe pub/sub
- Content changes — live-refresh every window listing your type
- Custom window chrome (Experimental)
- Register a custom unfocused-window effect
- Example: render a data table
- Real file storage — react to uploads, gate policy, share from PHP
- React to a window being set free onto the real desktop
- Cross-window devtools — instrumentation primitives
- Add a dock item with a badge
- Decorate the dock without forking the renderer
- Replace the dock rail entirely
- Retune the Drafts widget's AI writing assistant
- Gate OpenStation by role
- Iframe-initiated window opens
- Build a feed reader without the bookkeeping
- Inject data into openStationConfig
- Render a list without losing clicks — renderKeyedList()
- Example: layout primitives (body → panel → row → col)
- Use <os-*> components from a plugin that ships as a zip
- Restyle and drive Mio
- Repairable form edits with MIO
- Register a window companion
- Pin your app to the phone tab bar, and react to the mode
- Add an action that works on a whole selection
- WP Explorer — custom post types and their folder
- WP Explorer — add a column to the list view
- Add an action button to a WP Explorer preview pane
- Example: native Posts window
- Example: native window with tabs
- Native windows
- Customize note → post conversion
- Send a notification
- OAuth relay — connect to an external service
- Ship a window as an .os.php app
- OS-file drop
- <os-flyout> — window-scoped sliding card
- Plugins window — extras
- Track who's around — wp.os.presence
- Example: progress bar
- PWA install — surface your own button
- React to window events
- Example: extend the Trash
- Register a slash-command
- Register a desktop theme from a plugin
- Register a game
- Example: register a desktop icon (Jorvy)
- Register a wallpaper
- Register a widget
- Related entities — extend the title bar's "Related" menu
- The native-window render ctx
- Revisions in their own window — extend or redirect "View revisions"
- Programmatic folder sharing
- Share state across multi-bundle plugins — wp.os.createSharedStore()
- Example: loading spinner
- Add an opt-in card to Station Home
- Observe stored-file cleanup failures
- Accept drops on your desktop icon
- Give a tile two icons, one per state
- Add a row to a window's ⋯ menu
- Example: window activity & the status ring
- Window controls
- Subscribe to window lifecycle events
- Window links — relate windows and restyle the ties (Experimental)
- Window loading state — spinner overlay & ready signal
- Show a banner at the top of a window
- Pulse a window's icon — Window.requestAttention()
- Register a custom window reveal
- Window slots
- Window themes
- Native window with bundle-bound config
- Place something where the user can reach it — wp.os.workArea
- Ship a workspace template