9999 </div >
100100
101101 <div id =" output-global" class =" fixed top-4 right-4 z-50 max-w-sm hidden" ></div >
102+
103+ <!-- Command Input Modal -->
104+ <div id =" command-input-modal" class =" fixed inset-0 z-50 items-center justify-center hidden" >
105+ <div class =" absolute inset-0 bg-black bg-opacity-50" ></div >
106+ <div class =" relative bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md p-6 mx-4" >
107+ <h3 class =" text-lg font-medium text-gray-900 dark:text-gray-100 mb-4" id =" modal-title" >Command Input</h3 >
108+ <div class =" mb-4" >
109+ <label id =" input-label" class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" >Input</label >
110+ <input type =" text" id =" command-input-field" class =" w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" placeholder =" " >
111+ <p class =" mt-1 text-sm text-gray-500 dark:text-gray-400" id =" current-command-display" ></p >
112+ </div >
113+ <div class =" flex justify-end space-x-3" >
114+ <button id =" cancel-input" class =" px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" >
115+ Cancel
116+ </button >
117+ <button id =" submit-input" class =" px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" >
118+ Run Command
119+ </button >
120+ </div >
121+ </div >
122+ </div >
102123
103124 <div class =" flex-none h-[45vh] mb-4" >
104125 <div class =" w-full overflow-x-auto whitespace-nowrap" >
113134 @foreach ($groupCommands as $command )
114135 <div >
115136 <button
116- class =" w-full px-2 py-1 text-sm text-left border border-blue-500 text-blue-500 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/30 rounded truncate transition-colors command-btn"
137+ class =" w-full px-2 py-1 text-sm text-left border border-blue-500 text-blue-500 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/30 rounded truncate transition-colors command-btn flex items-center justify-between "
117138 data-command =" {{ $command [' command' ] } }"
118139 data-tooltip =" {{ $command [' description' ] } }"
119140 >
120- {{ $command [' command' ] } }
141+ <span >{{ $command [' command' ] } } </span >
142+ <span class =" input-icon hidden ml-1 flex-shrink-0" >
143+ <svg xmlns =" http://www.w3.org/2000/svg" viewBox =" 0 0 24 24" width =" 16" height =" 16" class =" text-blue-500 dark:text-blue-400" stroke =" currentColor" >
144+ <path d =" M19 7H5C3.34315 7 2 8.34315 2 10V19C2 20.6569 3.34315 22 5 22H19C20.6569 22 22 20.6569 22 19V10C22 8.34315 20.6569 7 19 7Z" stroke-width =" 1" stroke-linejoin =" round" ></path >
145+ <path d =" M12 7V5.53078C12 4.92498 12.4123 4.39693 13 4.25V4.25C13.5877 4.10307 14 3.57502 14 2.96922V2" stroke-width =" 1" stroke-linecap =" round" stroke-linejoin =" round" ></path >
146+ <path d =" M7 12L8 12M11.5 12L12.5 12M16 12L17 12" stroke-width =" 1" stroke-linecap =" round" stroke-linejoin =" round" ></path >
147+ <path d =" M7 17L17 17" stroke-width =" 1" stroke-linecap =" round" stroke-linejoin =" round" ></path >
148+ </svg >
149+ </span >
121150 </button >
122151 </div >
123152 @endforeach
@@ -147,6 +176,41 @@ class="w-full px-2 py-1 text-sm text-left border border-blue-500 text-blue-500 d
147176
148177 <script >
149178 document .addEventListener (' DOMContentLoaded' , function () {
179+ // Store commands that require input
180+ let commandsWithInput = {};
181+
182+ // Fetch commands with input requirements
183+ axios .get (' {{ route (" artisan-command-palette.commands" ) } }' )
184+ .then (response => {
185+ if (response .data && response .data .commands_with_input ) {
186+ commandsWithInput = response .data .commands_with_input ;
187+
188+ // Mark commands that require input with an icon
189+ Object .keys (commandsWithInput).forEach (commandName => {
190+ const commandButtons = document .querySelectorAll (` .command-btn[data-command="${ commandName} "]` );
191+ commandButtons .forEach (button => {
192+ const iconElement = button .querySelector (' .input-icon' );
193+ if (iconElement) {
194+ iconElement .classList .remove (' hidden' );
195+ iconElement .classList .add (' inline-block' );
196+ }
197+ });
198+ });
199+ }
200+ })
201+ .catch (error => {
202+ console .error (' Error fetching commands with input:' , error);
203+ });
204+
205+ // Command input modal elements
206+ const commandInputModal = document .getElementById (' command-input-modal' );
207+ const commandInputField = document .getElementById (' command-input-field' );
208+ const inputLabel = document .getElementById (' input-label' );
209+ const modalTitle = document .getElementById (' modal-title' );
210+ const currentCommandDisplay = document .getElementById (' current-command-display' );
211+ const submitInputBtn = document .getElementById (' submit-input' );
212+ const cancelInputBtn = document .getElementById (' cancel-input' );
213+
150214 // Custom tooltip implementation
151215 const tooltip = document .getElementById (' tooltip' );
152216 document .querySelectorAll (' [data-tooltip]' ).forEach (element => {
@@ -168,55 +232,124 @@ class="w-full px-2 py-1 text-sm text-left border border-blue-500 text-blue-500 d
168232 document .querySelectorAll (' .command-btn' ).forEach (button => {
169233 button .addEventListener (' click' , async function () {
170234 const command = this .dataset .command ;
171- const originalText = this .textContent ;
172-
173- // Disable button and show loading
174- this .disabled = true ;
175- this .innerHTML = `
176- <svg class =" animate-spin h-4 w-4 inline mr-2" xmlns =" http://www.w3.org/2000/svg" fill =" none" viewBox =" 0 0 24 24" >
177- <circle class =" opacity-25" cx =" 12" cy =" 12" r =" 10" stroke =" currentColor" stroke-width =" 4" ></circle >
178- <path class =" opacity-75" fill =" currentColor" d =" M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" ></path >
179- </svg >
180- Running...
181- ` ;
235+ const originalHTML = this .innerHTML ;
236+
237+ // Check if command requires input
238+ if (commandsWithInput[command]) {
239+ // Show input modal
240+ const inputConfig = commandsWithInput[command];
241+ modalTitle .textContent = ` Input for ${ command} ` ;
242+ inputLabel .textContent = inputConfig .label || ' Input' ;
243+ commandInputField .placeholder = inputConfig .placeholder || ' Enter input value' ;
244+ currentCommandDisplay .textContent = ` Command: ${ command} ` ;
245+
246+ // Show modal with flex display
247+ commandInputModal .classList .remove (' hidden' );
248+ commandInputModal .classList .add (' flex' );
249+ commandInputField .focus ();
250+
251+ // Store the command button reference for later use
252+ submitInputBtn .dataset .commandButton = button .dataset .command ;
253+ return ;
254+ }
255+
256+ // For commands without input, proceed as usual
257+ await executeCommand (command, this );
258+ });
259+ });
260+
261+ // Handle input submission
262+ submitInputBtn .addEventListener (' click' , async function () {
263+ const command = this .dataset .commandButton ;
264+ const inputValue = commandInputField .value .trim ();
265+ const buttonElement = document .querySelector (` .command-btn[data-command="${ command} "]` );
266+
267+ // Validate input if required
268+ if (commandsWithInput[command]? .required && ! inputValue) {
269+ showAlert (' error' , ' Input is required for this command' );
270+ return ;
271+ }
272+
273+ // Hide modal
274+ commandInputModal .classList .add (' hidden' );
275+ commandInputModal .classList .remove (' flex' );
276+
277+ // Execute command with input
278+ await executeCommand (command, buttonElement, inputValue);
279+
280+ // Reset input field
281+ commandInputField .value = ' ' ;
282+ });
283+
284+ // Handle cancel button
285+ cancelInputBtn .addEventListener (' click' , function () {
286+ commandInputModal .classList .add (' hidden' );
287+ commandInputModal .classList .remove (' flex' );
288+ commandInputField .value = ' ' ;
289+ });
290+
291+ // Handle Enter key in input field
292+ commandInputField .addEventListener (' keydown' , function (e ) {
293+ if (e .key === ' Enter' ) {
294+ submitInputBtn .click ();
295+ } else if (e .key === ' Escape' ) {
296+ cancelInputBtn .click ();
297+ }
298+ });
299+
300+ // Execute command function
301+ async function executeCommand (command , buttonElement , inputValue = null ) {
302+ const originalHTML = buttonElement .innerHTML ;
182303
183- // Update command status
184- document .getElementById (' current-command' ).innerHTML = `
185- <span class =" inline-block w-2 h-2 rounded-full bg-yellow-400 mr-2" ></span >
186- Running: ${ command}
187- ` ;
304+ // Disable button and show loading
305+ buttonElement .disabled = true ;
306+ buttonElement .innerHTML = `
307+ <svg class =" animate-spin h-4 w-4 inline mr-2" xmlns =" http://www.w3.org/2000/svg" fill =" none" viewBox =" 0 0 24 24" >
308+ <circle class =" opacity-25" cx =" 12" cy =" 12" r =" 10" stroke =" currentColor" stroke-width =" 4" ></circle >
309+ <path class =" opacity-75" fill =" currentColor" d =" M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" ></path >
310+ </svg >
311+ Running...
312+ ` ;
188313
189- try {
190- const response = await axios .post (' {{ route (" artisan-command-palette.execute" ) } }' , {
191- command: command
192- });
314+ // Update command status
315+ document .getElementById (' current-command' ).innerHTML = `
316+ <span class =" inline-block w-2 h-2 rounded-full bg-yellow-400 mr-2" ></span >
317+ Running: ${ command}${ inputValue ? ' ' + inputValue : ' ' }
318+ ` ;
193319
194- document .getElementById (' logs-output' ).innerHTML = response .data .output || ' Command executed successfully with no output.' ;
195- showAlert (' success' , ' Command executed successfully' );
196- document .getElementById (' current-command' ).innerHTML = `
197- <span class =" inline-block w-2 h-2 rounded-full bg-green-500 mr-2" ></span >
198- ${ command}
199- ` ;
200- // Scroll to bottom of output div
201- const logsOutput = document .getElementById (' logs-output' );
202- logsOutput .scrollTop = logsOutput .scrollHeight ;
203- } catch (error) {
204- const response = error .response ? .data ;
205- document .getElementById (' logs-output' ).innerHTML = response? .error || ' Command execution failed.' ;
206- showAlert (' error' , ` ${ response? .message }: ${response? .error }` );
207- document.getElementById('current-command').innerHTML = `
208- < span class = " inline-block w-2 h-2 rounded-full bg-red-500 mr-2" >< / span>
209- ${command}
210- ` ;
211- // Scroll to bottom of output div
212- const logsOutput = document.getElementById('logs-output');
213- logsOutput.scrollTop = logsOutput.scrollHeight;
214- } finally {
215- this.disabled = false;
216- this.textContent = originalText;
320+ try {
321+ const payload = { command: command };
322+ if (inputValue) {
323+ payload .input_value = inputValue;
217324 }
218- });
219- });
325+
326+ const response = await axios .post (' {{ route (" artisan-command-palette.execute" ) } }' , payload);
327+
328+ document .getElementById (' logs-output' ).innerHTML = response .data .output || ' Command executed successfully with no output.' ;
329+ showAlert (' success' , ' Command executed successfully' );
330+ document .getElementById (' current-command' ).innerHTML = `
331+ <span class =" inline-block w-2 h-2 rounded-full bg-green-500 mr-2" ></span >
332+ ${ command}${ inputValue ? ' ' + inputValue : ' ' }
333+ ` ;
334+ // Scroll to bottom of output div
335+ const logsOutput = document .getElementById (' logs-output' );
336+ logsOutput .scrollTop = logsOutput .scrollHeight ;
337+ } catch (error) {
338+ const response = error .response ? .data ;
339+ document .getElementById (' logs-output' ).innerHTML = response? .error || ' Command execution failed.' ;
340+ showAlert (' error' , ` ${ response? .message }: ${response? .error }` );
341+ document.getElementById('current-command').innerHTML = `
342+ < span class = " inline-block w-2 h-2 rounded-full bg-red-500 mr-2" >< / span>
343+ ${command}
344+ ` ;
345+ // Scroll to bottom of output div
346+ const logsOutput = document.getElementById('logs-output');
347+ logsOutput.scrollTop = logsOutput.scrollHeight;
348+ } finally {
349+ buttonElement.disabled = false;
350+ buttonElement.innerHTML = originalHTML;
351+ }
352+ }
220353
221354 // Clear logs
222355 document.getElementById('clear-logs').addEventListener('click', function() {
0 commit comments