@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
22import { useNavigate , useParams } from 'react-router-dom' ;
33import { useTranslation } from 'react-i18next' ;
44import { toolsApi } from '../../api/client' ;
5- import type { Tool , CreateToolRequest , ApiToolConfig , HttpMethod } from '../../types/tool' ;
5+ import type { Tool , CreateToolRequest , ApiToolConfig , HttpMethod , ToolType , GoogleCalendarToolConfig , GoogleSheetsToolConfig } from '../../types/tool' ;
66import './ToolsPage.css' ;
77
88const ToolsPage : React . FC = ( ) => {
@@ -81,25 +81,59 @@ const ToolsPage: React.FC = () => {
8181 setShowTypeDropdown ( ! showTypeDropdown ) ;
8282 } ;
8383
84- const selectToolType = ( type : 'api-request' ) => {
84+ const selectToolType = ( type : ToolType ) => {
8585 setShowTypeDropdown ( false ) ;
8686 setShowTypeSelection ( false ) ;
8787 setSelectedTool ( null ) ;
8888 setIsEditing ( true ) ;
89- const defaultBody = { } ;
89+
90+ let config : any ;
91+ let defaultBody = { } ;
92+ let defaultName = '' ;
93+
94+ switch ( type ) {
95+ case 'api-request' :
96+ config = {
97+ url : '' ,
98+ method : 'POST' ,
99+ headers : { } ,
100+ body : defaultBody ,
101+ authToken : '' ,
102+ parameters : [ ]
103+ } ;
104+ defaultName = '' ;
105+ break ;
106+ case 'google_calendar_event_create' :
107+ config = {
108+ calendarId : '' ,
109+ timezone : 'America/New_York'
110+ } ;
111+ defaultName = 'google_calendar_event_create' ;
112+ break ;
113+ case 'google_calendar_check_availability_tool' :
114+ config = {
115+ calendarId : '' ,
116+ timezone : 'America/New_York'
117+ } ;
118+ defaultName = 'google_calendar_check_availability_tool' ;
119+ break ;
120+ case 'google_sheets_tool' :
121+ config = {
122+ spreadsheetId : '' ,
123+ range : ''
124+ } ;
125+ defaultName = 'google_sheets_tool' ;
126+ break ;
127+ default :
128+ config = { } ;
129+ defaultName = '' ;
130+ }
90131
91132 setFormData ( {
92- name : '' ,
133+ name : defaultName ,
93134 type : type ,
94135 description : '' ,
95- config : {
96- url : '' ,
97- method : 'POST' ,
98- headers : { } ,
99- body : defaultBody ,
100- authToken : '' ,
101- parameters : [ ]
102- }
136+ config
103137 } ) ;
104138 setJsonBody ( JSON . stringify ( defaultBody , null , 2 ) ) ;
105139 setTestResult ( null ) ;
@@ -269,6 +303,22 @@ const ToolsPage: React.FC = () => {
269303 }
270304 } ;
271305
306+ const isFormValid = ( ) => {
307+ if ( ! formData . name || ! formData . description ) {
308+ return false ;
309+ }
310+
311+ // Validate Google Sheets required fields
312+ if ( formData . type === 'google_sheets_tool' ) {
313+ const config = formData . config as GoogleSheetsToolConfig ;
314+ if ( ! config ?. spreadsheetId || ! config ?. range ) {
315+ return false ;
316+ }
317+ }
318+
319+ return true ;
320+ } ;
321+
272322 return (
273323 < div className = "tools-page-container" >
274324 { /* Left Sidebar - Tools List */ }
@@ -280,7 +330,7 @@ const ToolsPage: React.FC = () => {
280330 </ button >
281331 { showTypeDropdown && (
282332 < div className = "tool-type-dropdown" >
283- < button
333+ < button
284334 className = "tool-type-option"
285335 onClick = { ( ) => selectToolType ( 'api-request' ) }
286336 >
@@ -290,6 +340,36 @@ const ToolsPage: React.FC = () => {
290340 < span className = "option-desc" > { t ( 'tools.typeDescriptions.apiRequest' ) } </ span >
291341 </ div >
292342 </ button >
343+ < button
344+ className = "tool-type-option"
345+ onClick = { ( ) => selectToolType ( 'google_calendar_event_create' ) }
346+ >
347+ < span className = "option-icon" > 📅</ span >
348+ < div className = "option-info" >
349+ < span className = "option-title" > { t ( 'tools.googleCalendar' ) } </ span >
350+ < span className = "option-desc" > { t ( 'tools.googleCalendarDesc' ) } </ span >
351+ </ div >
352+ </ button >
353+ < button
354+ className = "tool-type-option"
355+ onClick = { ( ) => selectToolType ( 'google_calendar_check_availability_tool' ) }
356+ >
357+ < span className = "option-icon" > 🗓️</ span >
358+ < div className = "option-info" >
359+ < span className = "option-title" > { t ( 'tools.checkAvailability' ) } </ span >
360+ < span className = "option-desc" > { t ( 'tools.checkAvailabilityDesc' ) } </ span >
361+ </ div >
362+ </ button >
363+ < button
364+ className = "tool-type-option"
365+ onClick = { ( ) => selectToolType ( 'google_sheets_tool' ) }
366+ >
367+ < span className = "option-icon" > 📊</ span >
368+ < div className = "option-info" >
369+ < span className = "option-title" > { t ( 'tools.googleSheets' ) } </ span >
370+ < span className = "option-desc" > { t ( 'tools.googleSheetsDesc' ) } </ span >
371+ </ div >
372+ </ button >
293373 </ div >
294374 ) }
295375 </ div >
@@ -394,7 +474,7 @@ const ToolsPage: React.FC = () => {
394474 type = "button"
395475 className = "btn-header-primary"
396476 onClick = { handleSave }
397- disabled = { saving || ! formData . name || ! formData . description }
477+ disabled = { saving || ! isFormValid ( ) }
398478 >
399479 { saving ? t ( 'tools.form.saving' ) : t ( 'tools.form.save' ) }
400480 </ button >
@@ -701,6 +781,131 @@ const ToolsPage: React.FC = () => {
701781 </ >
702782 ) }
703783
784+ { /* Google Calendar Tool Configuration */ }
785+ { formData . type === 'google_calendar_event_create' && (
786+ < div className = "form-section" >
787+ < h3 className = "section-title" >
788+ < span className = "section-icon" > 📅</ span >
789+ { t ( 'tools.calendarSettings' ) }
790+ </ h3 >
791+ < p className = "section-desc" > { t ( 'tools.calendarSettingsDesc' ) } </ p >
792+
793+ < div className = "form-group" >
794+ < label > Calendar ID</ label >
795+ < input
796+ type = "text"
797+ className = "form-input"
798+ placeholder = "Enter Calendar ID"
799+ value = { ( formData . config as GoogleCalendarToolConfig ) ?. calendarId || '' }
800+ onChange = { ( e ) => setFormData ( {
801+ ...formData ,
802+ config : { ...formData . config as GoogleCalendarToolConfig , calendarId : e . target . value }
803+ } ) }
804+ />
805+ < p className = "form-help" > The ID of the Google Calendar. Defaults to "primary" if not specified.</ p >
806+ </ div >
807+
808+ < div className = "form-group" >
809+ < label > Timezone</ label >
810+ < input
811+ type = "text"
812+ className = "form-input"
813+ placeholder = "America/New_York"
814+ value = { ( formData . config as GoogleCalendarToolConfig ) ?. timezone || 'America/New_York' }
815+ onChange = { ( e ) => setFormData ( {
816+ ...formData ,
817+ config : { ...formData . config as GoogleCalendarToolConfig , timezone : e . target . value }
818+ } ) }
819+ />
820+ < p className = "form-help" > The time zone for the calendar event (e.g., America/New_York). Defaults to UTC if not specified.</ p >
821+ </ div >
822+ </ div >
823+ ) }
824+
825+ { /* Google Calendar Check Availability Tool Configuration */ }
826+ { formData . type === 'google_calendar_check_availability_tool' && (
827+ < div className = "form-section" >
828+ < h3 className = "section-title" >
829+ < span className = "section-icon" > 🗓️</ span >
830+ { t ( 'tools.calendarSettings' ) }
831+ </ h3 >
832+ < p className = "section-desc" > { t ( 'tools.checkAvailabilitySettings' ) } </ p >
833+
834+ < div className = "form-group" >
835+ < label > Calendar ID</ label >
836+ < input
837+ type = "text"
838+ className = "form-input"
839+ placeholder = "Enter Calendar ID"
840+ value = { ( formData . config as GoogleCalendarToolConfig ) ?. calendarId || '' }
841+ onChange = { ( e ) => setFormData ( {
842+ ...formData ,
843+ config : { ...formData . config as GoogleCalendarToolConfig , calendarId : e . target . value }
844+ } ) }
845+ />
846+ < p className = "form-help" > The ID of the Google Calendar to check. Defaults to "primary" if not specified.</ p >
847+ </ div >
848+
849+ < div className = "form-group" >
850+ < label > Timezone</ label >
851+ < input
852+ type = "text"
853+ className = "form-input"
854+ placeholder = "America/New_York"
855+ value = { ( formData . config as GoogleCalendarToolConfig ) ?. timezone || 'America/New_York' }
856+ onChange = { ( e ) => setFormData ( {
857+ ...formData ,
858+ config : { ...formData . config as GoogleCalendarToolConfig , timezone : e . target . value }
859+ } ) }
860+ />
861+ < p className = "form-help" > The time zone for the availability check (e.g., America/New_York). Defaults to UTC if not specified.</ p >
862+ </ div >
863+ </ div >
864+ ) }
865+
866+ { /* Google Sheets Tool Configuration */ }
867+ { formData . type === 'google_sheets_tool' && (
868+ < div className = "form-section" >
869+ < h3 className = "section-title" >
870+ < span className = "section-icon" > 📊</ span >
871+ { t ( 'tools.googleSheetsSettings' ) }
872+ </ h3 >
873+ < p className = "section-desc" > { t ( 'tools.googleSheetsSettingsDesc' ) } </ p >
874+
875+ < div className = "form-group" >
876+ < label > Spreadsheet ID < span className = "required" > *</ span > </ label >
877+ < input
878+ type = "text"
879+ className = "form-input"
880+ placeholder = "Enter Spreadsheet ID"
881+ value = { ( formData . config as GoogleSheetsToolConfig ) ?. spreadsheetId || '' }
882+ onChange = { ( e ) => setFormData ( {
883+ ...formData ,
884+ config : { ...formData . config as GoogleSheetsToolConfig , spreadsheetId : e . target . value }
885+ } ) }
886+ required
887+ />
888+ < p className = "form-help" > The ID of the Google Sheet to append data to</ p >
889+ </ div >
890+
891+ < div className = "form-group" >
892+ < label > Range < span className = "required" > *</ span > </ label >
893+ < input
894+ type = "text"
895+ className = "form-input"
896+ placeholder = "Enter Range (e.g., Sheet1!A:Z)"
897+ value = { ( formData . config as GoogleSheetsToolConfig ) ?. range || '' }
898+ onChange = { ( e ) => setFormData ( {
899+ ...formData ,
900+ config : { ...formData . config as GoogleSheetsToolConfig , range : e . target . value }
901+ } ) }
902+ required
903+ />
904+ < p className = "form-help" > The range where the data should be appended (e.g., Sheet1, Sheet1!A:Z)</ p >
905+ </ div >
906+ </ div >
907+ ) }
908+
704909 { /* Actions */ }
705910 < div className = "form-actions" >
706911 { selectedTool && ! selectedTool . isDefault && (
0 commit comments