2izdZddlmZmZmZmZmZmZmZm Z m Z m Z m Z m Z mZmZmZmZmZmZmZmZddlmZddlmZddlZddlmZddlmZGdd eZdS) z Schedule Editor Dialog for Python Scheduler Create and edit schedules for individual jobs or groups (with inline group creation) )QDialog QVBoxLayout QHBoxLayout QFormLayoutQLabel QLineEdit QTextEdit QComboBox QPushButton QMessageBox QGroupBox QRadioButton QButtonGroupQStackedWidget QListWidgetQListWidgetItemQAbstractItemView QCheckBoxQSpinBoxQWidget)Qt)loggerN)SchedulerDatabase)SchedulerConfigc eZdZdZddedededeffd ZdZd Z d Z d Z d Z d Z dZdefdZdZdZdZdZdZdZdefdZdefdZdZxZS)ScheduleEditorDialogz6Dialog for creating/editing schedules (jobs or groups)Ndbconfig schedule_idpre_selected_job_idct|||_||_||_||_|du|_||jrdnd|dd| d| |jr| dSdS)Nz Edit Schedulez New ScheduleiiXT) super__init__rrrr is_edit_modesetWindowTitlesetMinimumSizesetModal _setup_ui_load_schedule_data)selfparentrrrr __class__s 1c:\PYTHON\Scheduler\gui\schedule_editor_dialog.pyr#zScheduleEditorDialog.__init__s     &#6 't3 t/@TOOnUUU C%%% d    '  $ $ & & & & & ' 'cR&t|}td}t}t|_|jd|d|jt|_|jd|j d|d|j| || |td}t}t}t||_td|_|jd |jj|j|j|jd | |jtd |_|jj|j|j|jd | |jtd |_|jj|j|j|jd| |jtd|_|jj|j|j|jd| |j|||t7|_t;}t|}t=|_|jd|jj |j!| tEd| |j||j |t;} t| } t} t||_#td|_$|j$d |j$j|j%|j#|j$d | |j$td|_&|j&j|j%|j#|j&d | |j&| | t7|_'t;} t| } t=|_(|j(d| tEd| |j(| |j' | t;}t|}t|_)|j)d| tEd| |j)t}| tEdt=|_*|j*+gd| |j*|||| tEdtY|_-|j-.t^j0j1|j- d| |j-t}ted|_3|j3j4|j5| |j3ted|_6|j6j4|j7| |j6|||| tEdtY|_8|j8 d| |j8t}ted |_9|j9j4|j:| |j9ted!|_;|j;j4|j<| |j;||||j' || |j'|j | t;}t|}t=|_=|j=d"| tEd#| |j=||j |t;}t|}t=|_>|j>d$| tEd%| |j>||j || |j| || |td&}t}t}| tEd't=|_?|j?+gd(|j?j@|jA| |j?|||t7|_Bt;}t|}t|_C|jCd)| tEd*| |jCtEd+}|Dd,| |tEd-}|Ed |Dd.| |||jB |t;}t|}t|_G|jGHd |jGId/|d0|jGt|_J|jJHd |jJId1|d2|jJt|_K|jKHd |jKId3|d4|jKt|_L|jLHd |jLId5|d6|jLt|_M|jMHd |jMId5|d7|jMtEd8} | Dd,| Nd |d9| |jB |t;}!t|!}"tEd:}#|#Dd;|#Nd |" |#|"|jB |!| |jBtd<|_P|jPd | |jP| || |t}$|$te|jQrd=nd>|_R|jRDd?|jRj4|jS|$ |jRted@}%|%j4|jT|$ |%||$|U|V|W|XdAS)BzSetup dialog UIzBasic Informationze.g., Daily ETL PipelinezSchedule Name:zOptional description...<z Description:zWhat to ExecutezExecute Single JobTrzExecute Job Group (Chain)zExecute Backup ProfilezExecute Sync ProfilezSelect a job...z Select Job:zUse Existing GroupzCreate New GroupzSelect a group...z Select Group:ze.g., Data Processing Chainz Group Name:zError Handling:) stop_on_errorcontinue_on_errorskip_remainingzAvailable Jobs:duAdd Selected ↓uRemove Selected ↑z Jobs in Group (execution order):u Move Up ↑u Move Down ↓zSelect a backup profile...zSelect Backup Profile:zSelect a sync profile...zSelect Sync Profile:zWhen to ExecutezSchedule Type:cronintervalmanualz$e.g., 0 2 * * * or 30 14 * * mon-frizCron Expression:uFormat: minute hour day month day_of_week Examples: • 0 8 * * * = Daily at 8:00 AM • 30 14 * * mon-fri = Weekdays at 2:30 PM • 0 9 * * mon,wed,fri = Mon/Wed/Fri at 9:00 AMzcolor: #666; font-size: 10px;zICron Expression Helper (crontab.guru)z color: #2196F3; font-size: 10px;4zWeeks:imzDays:zHours:;zMinutes:zSeconds:z{Specify the interval duration. At least one value must be non-zero. Example: 2 weeks = execute every 2 weeks from first runz[Manual execution only - no automatic scheduling. Use 'Run Now' button to execute on demand.z color: #666; font-style: italic;z)Enabled (schedule will run automatically)SaveCreatezNbackground-color: #4CAF50; color: white; padding: 8px 20px; font-weight: bold;CancelN)Yrr rr name_inputsetPlaceholderTextaddRowr description_inputsetMaximumHeight setLayout addWidgetrrtarget_button_groupr job_radio setCheckedtoggledconnect_on_target_type_changed addButton group_radio backup_radio sync_radio addStretch addLayoutr target_stackrr job_combocurrentIndexChanged_on_job_selectedrgroup_selection_button_groupexisting_group_radio_on_group_selection_changednew_group_radio group_stackexisting_group_combogroup_name_inputgroup_error_comboaddItemsravailable_jobs_listsetSelectionModer SelectionModeMultiSelectionr add_to_group_btnclicked_add_jobs_to_groupremove_from_group_btn_remove_jobs_from_groupgroup_jobs_list move_up_btn _move_job_up move_down_btn_move_job_down backup_combo sync_comboschedule_type_combocurrentTextChanged_on_schedule_type_changedschedule_config_stack cron_input setStyleSheetsetOpenExternalLinksrinterval_weeks setMinimum setMaximum interval_daysinterval_hoursinterval_minutesinterval_seconds setWordWraprenabled_checkboxr$save_btn_save_schedulereject _load_jobs _load_groups_load_backup_profiles_load_sync_profiles)&r*layout basic_group basic_layout target_group target_layout radio_layoutjob_pagejob_page_layout group_pagegroup_page_layoutgroup_radio_layoutexisting_group_widgetexisting_group_layoutnew_group_widgetnew_group_layout error_layoutadd_remove_layout order_layout backup_pagebackup_page_layout sync_pagesync_page_layoutschedule_groupschedule_layout type_layout cron_widget cron_layout cron_help cron_linkinterval_widgetinterval_layout interval_help manual_widget manual_layout manual_labelactions_layout cancel_btns& r-r(zScheduleEditorDialog._setup_ui*sT"" 344 "}} #++ **+EFFF,do>>>!* 112KLLL //333ND,BCCCl+++%%%!!233 # #}} #/#5#5 %&:;; !!$''' &&t'CDDD  **4>1===t~...'(CDD  (()EFFF  **4+;Q???t/000()ABB !))$*FGGG  **4+> ''(DEEE  **4?A>>>t///!!! ---+,,99%h//" ))*;<<< *2243HIII!!&"7"7888!!$.111""$$$ ##H---YY ' 33)]],8,>,>)$01E$F$F! !,,T222 !)11$2RSSS )33D4MqQQQ$$T%>???+,>?? $,,T-MNNN )33D4H!LLL$$T%9:::##$6777*++!(  +,A B B$-KK! !445HIII''(?(?@@@''(ABBB((*** ""#8999#99&'788!*  001NOOO""6-#8#8999""4#8999#}} v&788999!* '') ) )    t5666!!!""<000 ""6*;#<#<===#.==   112C2Q2`aaa  11#666""4#;<<<(MM +,> ? ? %--d.EFFF##D$9:::%01F%G%G" "*2243OPPP##D$>???$$&&&""#4555 ""6*L#M#MNNN*}} --c222""4#7888#}} &}55  (():;;;t/000(99 "**4+>???t1222!!!""<000 ""#3444##D$4555 ##J///ii (55%KK ,,-IJJJ$$V,D%E%EFFF$$T%6777%%''' ##K000II &y11#++ **+EFFF""6*@#A#ABBB""4?333##%%% ##I... 1222}---&&&##455%--"mm f%566777#,;;   ))*H*H*HIII  3;;D>>> 7 7&#f+'I'ISY'I'I'IJJ R_5s4yAAA(006666' F++D,DEEEEE F F 5 5 5 L333 4 4 4 4 4 4 4 4 4 5sCC D!C>>Dc |j5}|d}d|D}dddn #1swxYwY|D]\}|j|d}|j|ddt|d|d]dS#t$r"}tj d|Yd}~dSd}~wwxYw) zLoad existing groupsz&SELECT * FROM job_groups ORDER BY namec,g|]}t|S)dict).0rows r- z5ScheduleEditorDialog._load_groups..{sAAA$s))AAAr.Nrrz (z jobs)zError loading groups: ) r_get_connectionexecutefetchallget_job_group_membersr_rlenrrr)r*conncursorgroupsgroupmembersrs r-rz!ScheduleEditorDialog._load_groupsvsq 7((** Bd&NOOAAv/@/@AAA B B B B B B B B B B B B B B B   '77d DD)11V}<<G <<<$K   7 7 7 L5!55 6 6 6 6 6 6 6 6 6 7s;C4A CAC"A#A"C C3C..C3c |j}|D]1}|dr'|j|d|d2|jdkr7|jdd|jddSdS#t $r"}tjd|Yd}~dSd}~wwxYw) z"Load backup profiles for selectionenabledrrr(No enabled profiles)NFzError loading backup profiles: ) rget_all_backup_profilesrqrcount setEnabledrrrr*profilesprofilers r-rz*ScheduleEditorDialog._load_backup_profiless @w6688H# N N9%N%--gfowt}MMM &&((A--!))*A4HHH!,,U33333.- @ @ @ L>1>> ? ? ? ? ? ? ? ? ? @sBB%% C/C  Ccx |j|j}|D]1}|dr'|j|d|d2|jdkr7|jdd|jddS|jddS#t$rW}tj d ||jd d|jdYd}~dSd}~wwxYw) z Load sync profiles for selectionrrrrrNFTzError loading sync profiles: z(Error loading profiles)) rrclearrget_all_sync_profilesrrrrrrrs r-rz(ScheduleEditorDialog._load_sync_profilessQ . O ! ! # # #w4466H# L L9%LO++GFOWT]KKK$$&&!++''(?FFF**511111**400000 . . . L<<< = = = O # #$> E E E O & &u - - - - - - - - - .sB8C<C D9"A D44D9c|jr|jddS|jr|jddS|jr|jddS|jr|jddSdS)zHandle target type changerr1r2r3N)rK isCheckedrVsetCurrentIndexrQrRrSr*s r-rOz,ScheduleEditorDialog._on_target_type_changeds > # # % % 1   - -a 0 0 0 0 0   ' ' ) ) 1   - -a 0 0 0 0 0   ( ( * * 1   - -a 0 0 0 0 0 _ & & ( ( 1   - -a 0 0 0 0 0 1 1r.c|jr|jddS|jddS)z"Handle group selection type changerr1N)r[rr^rrs r-r\z0ScheduleEditorDialog._on_group_selection_changedsS  $ . . 0 0 0   , ,Q / / / / /   , ,Q / / / / /r. schedule_typecldddd}||d}tjd|d||j||jtjd|jjjdS) zHandle schedule type changerr1r2r8zSchedule type changed to 'z', switching to stack index zCurrent widget: N) getrdebugrvr currentWidgetupdateGeometryr,__name__)r*rtype_mapindexs r-ruz.ScheduleEditorDialog._on_schedule_type_changeds1:: ]A.. d-dd]bddeee "225999 "0022AACCC g(B(P(P(R(R(\(egghhhhhr.c|js|jrdS|j}|r||dSdS)z?When job is selected from combo, pre-populate schedule settingsN)r$r rW currentDatar)r*job_ids r-rYz%ScheduleEditorDialog._on_job_selecteds]    8  F++--  0  ' ' / / / / / 0 0r.c|j}|sdS|D]}t|}|t jj|t jj|j ||j |}|j |dS)zAdd selected jobs to groupN) rc selectedItemsrtextrrrrdatarlrrtakeItemr*selected_itemsrnew_itemrs r-riz'ScheduleEditorDialog._add_jobs_to_groups1??AA  F" 3 3D&tyy{{33H   R_5tyyAY7Z7Z [ [ [  ( ( 2 2 2*..t44C  $ - -c 2 2 2 2  3 3r.c|j}|sdS|D]}t|}|t jj|t jj|j ||j |}|j |dS)zRemove selected jobs from groupN) rlrrrrrrrrrcrrrrs r-rkz,ScheduleEditorDialog._remove_jobs_from_groups-;;==  F" / /D&tyy{{33H   R_5tyyAY7Z7Z [ [ [  $ , ,X 6 6 6&**400C  ) )# . . . .  / /r.c|j}|dkrW|j|}|j|dz ||j|dz dSdS)zMove selected job uprr1N)rl currentRowr insertItem setCurrentRowr* current_rowrs r-rnz!ScheduleEditorDialog._move_job_upsz*5577 ??'00==D  + +K!OT B B B  . .{Q ? ? ? ? ? ?r.c6|j}||jdz kr]|dkrY|j|}|j|dz||j|dzdSdSdS)zMove selected job downr1rN)rlrrrrrrs r-rpz#ScheduleEditorDialog._move_job_downs*5577 -33559 9 9kQ>N>N'00==D  + +K!OT B B B  . .{Q ? ? ? ? ? : 9>N>Nr.c |j|j}|s5tj|dd|jd|dS|j|d|dr |j |d|ddkr\|j d |j |d }|d kr|j |nB|dd kr[|j d |j |d }|d kr|j|n|dd kr[|j d |j |d }|d kr|j|nt|j d |j d |j |d }|d kr|j||j|dt1|dt2rt5j|dn|d}|ddkr/|j|ddn|ddkr|j|dd |j |dd |j!|dd |j"|dd |j#|dd |j$ |ddS#tJ$rO}tMj'd|tj(|dd||Yd}~dSd}~wwxYw)z'Load existing schedule data for editingErrorz Schedule z not foundNr description target_typerT target_idrbackup_profile sync_profilerschedule_configr9r?r:weeksdayshoursminutessecondsrzError loading schedule data: zFailed to load schedule: ))r get_schedulerr warningrrCsetTextrF setPlainTextrKrLrWfindDatarrRrqrSrrrQr[r_rssetCurrentText isinstancestrjsonloadsrwrrzsetValuer}r~rrrrrrcritical)r*schedulerrrs r-r)z(ScheduleEditorDialog._load_schedule_datas$5 w++D,<==H #D'3[t?O3[3[3[\\\  O # #HV$4 5 5 5 & M&33H]4KLLL &%//))$/////0EFFA::N225999-(,<<<!,,T222)228K3HIIA::%55e<<<-(N::**400000+1FGGA::O33E::: ++D111)44T:::1::8K;PQQA::-==eDDD  $ 3 3H_4M N N N@J8TeKfhk@l@lNTZ): ;<<(>????/*j88#,,VZZ-C-CDDD"++FJJvq,A,ABBB#,,VZZ-C-CDDD%..vzz)Q/G/GHHH%..vzz)Q/G/GHHH  ! , ,Xi-@ A A A A A    L<<< = = =  w0OA0O0O P P P KKMMMMMMMMM s AO6NO66 QAQ  Qreturnc|js1tj|dd|jdS|jr7|j dkrtj|dddSn|j rP|j dks|j tj|dddSn/|j rO|j dks|j tj|dddSn|jr6|j dkrtj|dd dSnx|jstj|dd dS|jdkrtj|dd dS|j}|d krD|jstj|dd dSn|dkr|jdkr|jdkro|jdkrR|jdkr5|jdkrtj|dddSdS)zValidate form inputsValidation ErrorzSchedule name is requiredFrzPlease select a jobNzPlease select a backup profilePlease select a sync profilezPlease select a groupzGroup name is requiredz(Please add at least one job to the groupr9zCron expression is requiredr:z*Please specify at least one interval valueT)rCrstripr r setFocusrKrrW currentIndexrRrqrrSrrr[r_r`rlrrs currentTextrwrzvaluer}r~rr)r*rs r-_validate_inputsz%ScheduleEditorDialog._validate_inputs7sU##%%++--   &8:U V V V O $ $ & & &5 > # # % % !~**,,q00#D*<>STTTu1  ( ( * * ! --//!33t7H7T7T7V7V7^#D*<>^___u8__ & & ( ( !++--11T_5P5P5R5R5Z#D*<>\]]]u6[(2244 !,99;;a??'.@BYZZZ 5@,113399;;!'.@BZ[[[ 5'--//144'.@Blmmm 50<<>> F " "?''))//11 #D*<>[\\\u j ( (#))++q00"((**a//#))++q00%++--22%++--22#D*<>jkkkutr.rc |j|}|stjd|ddS|jd|j|}|dkr|j||j s#|j d|d|dr|j |d t|d trt!j|d n|d }|dd kr3|d d }|r|j |n|dd kr|j|d d|j|dd|j|dd|j|dd|j|ddn.#t4$r!}tjd|Yd}~nd}~wwxYwtjd|dS#t4$r"}tjd|Yd}~dSd}~wwxYw)z3Pre-populate schedule settings from an existing jobzJob z not found for pre-populationNTrz Schedule for rrrr9r?r:rrrrr z*Could not parse schedule config from job: z'Pre-populated schedule editor from job zError pre-populating from job: )rget_jobrr rKrLrWrrrCrr rsrrrrrrrwrzrr}r~rrrinfor)r*rrrr cron_exprrs r-rz+ScheduleEditorDialog._pre_populate_from_jobis* @'//&))C KfKKKLLL N % %d + + +N++F33Ezz..u555?'')) G''(EF (E(EFFF?# U(77O8LMMMUCMcRcNdfiCjCjGTZ,=(>???psuFqGF?+v55$*JJvr$:$: $? O33I>>>_-;;+44VZZ5K5KLLL*33FJJvq4I4IJJJ+44VZZ5K5KLLL-66vzz)Q7O7OPPP-66vzz)Q7O7OPPP UUUN#SPQ#S#STTTTTTTTU KJ&JJ K K K K K @ @ @ L>1>> ? ? ? ? ? ? ? ? ? @sH4J(B9J(2E.I! J(! J +JJ(J  J(( K2KKc * |sdS |jrd}|j}n|jrd}|j}n|jr7d}|j}|tj |dddSnc|j rd}|j }n-|j d|j|jd }|jjdi|}t+|jD]`}|j|}|t4jj}|j|||d z at=jd |d |dd}|j }|dkr.d|j!i}n|dkr||j"#|j$#|j%#|j&#|j'#d}ni}|j|j()pd|||||j*d} |j+r^|jj,|j-fi| t=jd|j-d | dtj.|dd| ddnU|jj/di| } t=jd| d | dtj.|dd| dd| d|0dS#tb$r;} t=j2d| tj3|dd| Yd} ~ dSd} ~ wwxYw)zSave schedule to databaseNrrrrrrzAuto-created for schedule: )rrerror_handlingr1)execution_orderzCreated inline group z: rr9r:)rrrrr )rrrrrrrzUpdated schedule Successz Schedule 'z' updated successfullyzCreated schedule z' created successfully (ID: rzError saving schedule: rzFailed to save schedule: r)4r rKrrWrrRrqrSrrr r r[r_r`rrrCrarrcreate_job_grouprangerlrrrrrradd_job_to_grouprr#rsrwrzrr}r~rrrF toPlainTextrr$update_scheduler informationcreate_scheduleacceptrrr) r*rr group_datairrrr schedule_datarrs r-rz#ScheduleEditorDialog._save_schedules$$&&  FL Q~''))! *#  N6688 ",,.. *.  -99;; **,, *,  O7799 $'.@B`aaaF%,6688*")K $ 9 E E G GII!% 5 : : < < B B D D'eT_EYEYE[E[EaEaEcEc'e'e*.*@*L*L*N*N""J !9 8 F F: F FI#4#7#=#=#?#?@@YY#388;;!%2?+C!D!D00FTUVWTW0XXXXK Y Y YZPVEW Y YZZZ")K!4@@BBM&&#)4?+?+?+A+A+G+G+I+I"J*,,!06688 .4466!06688#4::<<#4::<< ###%,,..4466#5AACCIIKKSt*&!.#20::<<M  I''(8JJMJJJ [0@[[MRXDY[[\\\'i9smTZF[9s9s9stttt5dg5FF FF  V VV}V?TVVWWW'i:HmTZF[:H:HzE:H:H:HIII KKMMMMM Q Q Q L6166 7 7 7  w0OA0O0O P P P P P P P P P QsB8Q M9Q R0R  R)NN)r __module__ __qualname____doc__rrintr#r(rrrrrOr\rrurYrirkrnrpr)boolr rr __classcell__)r,s@r-rrs@@''#4'o'\_'~A''''''$t#t#t#l 555,777"@@@ ...* 1 1 1000isiiii000 3 3 3 / / /@@@@@@777r0$0000d,@S,@,@,@,@\QQQQQQQQQQQQQQr.r) r6PyQt6.QtWidgetsrrrrrrr r r r r rrrrrrrrr PyQt6.QtCorerlogururr core.databaser core.configrrrr.r-r?s  ++++++''''''S QS QS QS QS Q7S QS QS QS QS Qr.