PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.6
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.6
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / apps / trash / trash.os.php

trash.os.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.6, at apps/trash/trash.os.php

180 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Trash — the Recycle Bin, as an OpenStation app.
4 *
5 * THE Recycle Bin: the App Framework rebuild replaced the legacy
6 * native window whole and claims its id — `desktop-mode-recycle-bin`
7 * is a frozen identifier (see AGENTS.md), so every desktop shortcut,
8 * dock placement, drag-to-trash drop target, theme icon slot and
9 * Apps & Plugins row keeps working unchanged. The window is this
10 * file; the body is `trash.os.ts`, a client view painting the same
11 * toolbar, `<os-table>` and empty state through its own cell
12 * renderers (`parts/table-visuals.ts`). All data and mutations run
13 * through the store (`includes/recycle-bin/`), which also keeps
14 * capture, realtime and REST exactly as they were; the closed-window
15 * tile art stays shell-side (`src/desktop-files/recycle-bin-icon-state.ts`).
16 *
17 * What the framework replaced: the window registration and template
18 * (`window.php` keeps only the tile art, the gate and the shell
19 * config), the per-window REST client and config blob (actions +
20 * `data()` + `ctx.fetch`), the broadcast subscriptions
21 * (`watch( '*' )`), and the imperative toolbar wiring.
22 *
23 * (Header kept short on purpose: Plugin Check's direct-access scan
24 * reads only the first 50 raw lines, and the guard below must land
25 * inside that window.)
26 *
27 * @package OpenStation
28 */
29
30 namespace OpenStation\Apps\Trash;
31
32 use OpenStation\App;
33 use OpenStation\App\Os;
34 use OpenStation\App\State;
35
36 // Direct access, unless a standalone host is booting on bare PHP.
37 if ( ! defined( 'ABSPATH' ) ) {
38 defined( 'OPENSTATION_STANDALONE' ) || exit;
39 }
40
41 /**
42 * Normalise the dispatched `items` argument into `{id, type}` refs.
43 *
44 * @param array<string,mixed> $args Action args.
45 * @return array<int,array{id:int,type:string}>
46 */
47 function refs( array $args ) {
48 $out = array();
49 foreach ( (array) ( $args['items'] ?? array() ) as $entry ) {
50 if ( ! is_array( $entry ) ) {
51 continue;
52 }
53 $id = isset( $entry['id'] ) ? (int) $entry['id'] : 0;
54 if ( $id <= 0 ) {
55 continue;
56 }
57 $out[] = array(
58 'id' => $id,
59 'type' => isset( $entry['type'] ) ? sanitize_key( (string) $entry['type'] ) : '',
60 );
61 }
62 return $out;
63 }
64
65 /**
66 * Run one of the store's bulk callbacks over the dispatched refs,
67 * announce the content change per affected type (the same
68 * `os.<type>.changed` broadcasts the legacy bin emits, which is also
69 * what repaints iframes and the legacy window), and surface errors
70 * as a toast — the legacy bin only logged them to the console.
71 *
72 * @param Os $os Host handle.
73 * @param array<int,array{id:int,type:string}> $items Refs.
74 * @param callable $callback Store bulk callback.
75 * @param string $action `untrashed` | `deleted`.
76 * @return void
77 */
78 function run_bulk( Os $os, array $items, $callback, $action ) {
79 if ( array() === $items ) {
80 return;
81 }
82 $result = openstation_recycle_bin_apply_bulk( $items, $callback );
83 $ok = array_map( 'intval', (array) $result['ok'] );
84 if ( array() !== $ok ) {
85 $by_type = array();
86 foreach ( $items as $item ) {
87 if ( in_array( $item['id'], $ok, true ) ) {
88 $by_type[ '' !== $item['type'] ? $item['type'] : 'post' ][] = $item['id'];
89 }
90 }
91 foreach ( $by_type as $type => $ids ) {
92 $os->announce( (string) $type, $action, $ids );
93 }
94 }
95 $errors = (array) $result['errors'];
96 if ( array() !== $errors ) {
97 $os->toast(
98 sprintf(
99 /* translators: %d: number of items that could not be processed. */
100 __( '%d item(s) could not be processed.', 'desktop-mode' ),
101 count( $errors )
102 )
103 );
104 }
105 }
106
107 return App::define( 'desktop-mode-recycle-bin' )
108 ->title( __( 'Trash', 'desktop-mode' ) )
109 // The same outlined-vessel mark the legacy dock tile draws — its
110 // empty state; the client view swaps in the full-bin art through
111 // `ctx.host.setIcon()` when the count crosses zero, and both
112 // drawings travel in the config extra below so the swap is a
113 // local operation, never a round trip. Deliberately NO badge: a
114 // count on the tile reads as update notifications, and a bin that
115 // changes shape carries the same signal without shouting.
116 ->icon( function_exists( 'openstation_recycle_bin_icon_svg' ) ? openstation_recycle_bin_icon_svg() : 'dashicons-trash' )
117 ->config( function_exists( 'openstation_recycle_bin_icon_uris' ) ? openstation_recycle_bin_icon_uris() : array() )
118 ->size( 880, 560 )
119 ->min_size( 520, 360 )
120 // The legacy bin's rail furniture, inherited whole: a control
121 // (not an app), last on the dock after the shell's own cluster
122 // (Mio 10, Overview 20, System 30) — Trash is where things END
123 // UP, and a dock reads left to right.
124 ->nav_kind( 'control' )
125 ->dock_order( 40 )
126 ->placeable()
127 ->can(
128 static function () {
129 return function_exists( 'openstation_recycle_bin_user_can_use' )
130 ? openstation_recycle_bin_user_can_use()
131 : current_user_can( 'edit_posts' );
132 }
133 )
134 // The whole interaction surface is two mutations; the filter and
135 // the search dispatch the built-in `refresh` (the bound value
136 // rides up with the state, `data()` re-queries).
137 ->state(
138 array(
139 'filter' => '',
140 'search' => '',
141 )
142 )
143 ->action(
144 'restore',
145 static function ( State $state, Os $os, array $args ) {
146 run_bulk( $os, refs( $args ), 'openstation_recycle_bin_restore', 'untrashed' );
147 }
148 )
149 ->action(
150 'purge',
151 static function ( State $state, Os $os, array $args ) {
152 run_bulk( $os, refs( $args ), 'openstation_recycle_bin_purge', 'deleted' );
153 }
154 )
155 // Anything trashed or restored ANYWHERE on the desktop repaints
156 // the bin — the framework's replacement for the legacy window's
157 // hand-wired per-type broadcast subscriptions.
158 ->watch( '*' )
159 ->data(
160 static function ( State $state ) {
161 $payload = openstation_recycle_bin_get_items(
162 array(
163 'type' => (string) $state->get( 'filter' ),
164 'search' => (string) $state->get( 'search' ),
165 'per_page' => 200,
166 )
167 );
168 return array(
169 'items' => $payload['items'],
170 // The GLOBAL bin count (every type, unfiltered) — what
171 // decides toolbar-vs-empty-state and the dock badge.
172 'total' => (int) $payload['total'],
173 // Whether WordPress routes attachment deletions through
174 // Trash at all — gates the Media filter segment, same
175 // as the legacy template.
176 'mediaTrash' => defined( 'MEDIA_TRASH' ) && MEDIA_TRASH,
177 );
178 }
179 );
180