mariagrandury commited on
Commit
8e3b19a
Β·
1 Parent(s): 4bc565f

implement editing existing entries

Browse files
datasets_resource.py CHANGED
@@ -359,10 +359,372 @@ def create_contribute_tab():
359
  )
360
 
361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  def create_tab():
363
  """Create the complete tab for this resource type."""
364
  with gr.TabItem(f"πŸ“Š {RESOURCE_TITLE}", id=RESOURCE_TYPE):
365
  with gr.Tabs():
366
  table = create_all_tab()
367
  inputs = create_contribute_tab()
368
- return table, inputs
 
 
359
  )
360
 
361
 
362
+ def search_entries(query: str) -> pd.DataFrame:
363
+ """Search for entries by name or URL."""
364
+ if not query.strip():
365
+ return pd.DataFrame()
366
+
367
+ df = load_data()
368
+ if df.empty:
369
+ return df
370
+
371
+ # Search in name, github_url, huggingface_url, and zenodo_url columns
372
+ mask = (
373
+ df["name"].str.contains(query, case=False, na=False)
374
+ | df["github_url"].str.contains(query, case=False, na=False)
375
+ | df["huggingface_url"].str.contains(query, case=False, na=False)
376
+ | df["zenodo_url"].str.contains(query, case=False, na=False)
377
+ )
378
+
379
+ return df[mask]
380
+
381
+
382
+ def load_entry_for_edit(selected_entry: str) -> tuple:
383
+ """Load a specific entry for editing."""
384
+ if not selected_entry:
385
+ return ("",) * 11 # Return empty values for all fields
386
+
387
+ df = load_data()
388
+ if df.empty:
389
+ return ("",) * 11
390
+
391
+ # Find the entry by name
392
+ entry = df[df["name"] == selected_entry].iloc[0]
393
+
394
+ # Convert comma-separated strings back to lists for multi-select components
395
+ task_list = [t.strip() for t in entry["task"].split(",")] if entry["task"] else []
396
+ domain_list = (
397
+ [d.strip() for d in entry["domain"].split(",")] if entry["domain"] else []
398
+ )
399
+ countries_list = (
400
+ [c.strip() for c in entry["countries"].split(",")] if entry["countries"] else []
401
+ )
402
+ languages_list = (
403
+ [l.strip() for l in entry["languages"].split(",")] if entry["languages"] else []
404
+ )
405
+
406
+ return (
407
+ entry["name"],
408
+ entry["github_url"],
409
+ entry["huggingface_url"],
410
+ entry["zenodo_url"],
411
+ entry["paper_url"],
412
+ entry["dataset_type"],
413
+ task_list,
414
+ domain_list,
415
+ entry["website_url"],
416
+ countries_list,
417
+ languages_list,
418
+ )
419
+
420
+
421
+ def update_entry(
422
+ original_name: str,
423
+ name: str,
424
+ github_url: str,
425
+ huggingface_url: str,
426
+ zenodo_url: str,
427
+ paper_url: str,
428
+ dataset_type: str,
429
+ task: list,
430
+ domain: list,
431
+ website_url: str,
432
+ countries: list,
433
+ languages: list,
434
+ profile: gr.OAuthProfile | None,
435
+ ):
436
+ """Update an existing entry."""
437
+ if not profile:
438
+ return "❌ Please log in to edit entries."
439
+
440
+ username = profile.username
441
+ if not username:
442
+ return "❌ Could not get username from profile."
443
+
444
+ if not original_name:
445
+ return "❌ No entry selected to edit."
446
+
447
+ if not name.strip():
448
+ return "❌ Name is required."
449
+
450
+ # Validate that at least one URL is provided
451
+ urls = [github_url.strip(), huggingface_url.strip(), zenodo_url.strip()]
452
+ if not any(urls):
453
+ return "❌ At least one URL (GitHub, Hugging Face, or Zenodo) is required."
454
+
455
+ # Validate URLs
456
+ for url_field, url_value in [
457
+ ("GitHub URL", github_url),
458
+ ("Hugging Face URL", huggingface_url),
459
+ ("Zenodo URL", zenodo_url),
460
+ ("Paper URL", paper_url),
461
+ ("Website URL", website_url),
462
+ ]:
463
+ if url_value.strip() and not validate_url(url_value):
464
+ return f"❌ Invalid {url_field}. Please provide a valid URL."
465
+
466
+ try:
467
+ # Load existing dataset
468
+ existing_dataset = load_dataset(DATASET_NAME, CONFIG_NAME, split="train")
469
+ existing_df = existing_dataset.to_pandas()
470
+
471
+ # Find and update the entry
472
+ mask = existing_df["name"] == original_name
473
+ if not mask.any():
474
+ return f"❌ Entry '{original_name}' not found."
475
+
476
+ # Update the entry
477
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
478
+
479
+ existing_df.loc[mask, "name"] = name
480
+ existing_df.loc[mask, "github_url"] = github_url
481
+ existing_df.loc[mask, "huggingface_url"] = huggingface_url
482
+ existing_df.loc[mask, "zenodo_url"] = zenodo_url
483
+ existing_df.loc[mask, "paper_url"] = paper_url
484
+ existing_df.loc[mask, "dataset_type"] = dataset_type
485
+ existing_df.loc[mask, "task"] = ", ".join(task) if task else ""
486
+ existing_df.loc[mask, "domain"] = ", ".join(domain) if domain else ""
487
+ existing_df.loc[mask, "website_url"] = website_url
488
+ existing_df.loc[mask, "countries"] = ", ".join(countries) if countries else ""
489
+ existing_df.loc[mask, "languages"] = ", ".join(languages) if languages else ""
490
+ existing_df.loc[mask, "date_submitted"] = current_time
491
+
492
+ # Convert back to Dataset and push to hub
493
+ updated_dataset = Dataset.from_pandas(existing_df)
494
+ updated_dataset.push_to_hub(
495
+ DATASET_NAME,
496
+ config_name=CONFIG_NAME,
497
+ commit_message=f"Update dataset entry: {name} (edited by {username})",
498
+ )
499
+
500
+ return f"βœ… Successfully updated '{name}'!"
501
+
502
+ except Exception as e:
503
+ return f"❌ Error updating entry: {str(e)}"
504
+
505
+
506
+ def create_edit_tab():
507
+ """Create the edit tab for modifying existing entries."""
508
+ with gr.TabItem("✏️ Edit", id=f"{RESOURCE_TYPE}_edit"):
509
+ gr.Markdown(f"### Edit Existing {RESOURCE_TITLE}")
510
+ gr.Markdown("Please log in to edit entries:")
511
+ login_button = gr.LoginButton(elem_id=f"{RESOURCE_TYPE}-edit-oauth-button")
512
+
513
+ gr.Markdown("Search for an entry to edit:")
514
+
515
+ with gr.Row():
516
+ search_input = gr.Textbox(
517
+ label="Search by name or URL",
518
+ placeholder="Enter dataset name or URL to search...",
519
+ scale=3,
520
+ )
521
+ search_btn = gr.Button("πŸ” Search", scale=1)
522
+
523
+ search_results = gr.Dropdown(
524
+ label="Select entry to edit", choices=[], interactive=True
525
+ )
526
+
527
+ gr.Markdown("---")
528
+ gr.Markdown("**Edit the selected entry:**")
529
+
530
+ with gr.Column(visible=False) as edit_form:
531
+ name_input = gr.Textbox(label="Name *", placeholder="Dataset name")
532
+ dataset_type_input = gr.Dropdown(
533
+ label="Dataset Type *",
534
+ choices=[
535
+ "pretraining",
536
+ "benchmark",
537
+ "supervised fine-tuning",
538
+ "alignment",
539
+ ],
540
+ value="benchmark",
541
+ )
542
+
543
+ gr.Markdown("**URLs** (at least one required)")
544
+ with gr.Row():
545
+ github_url_input = gr.Textbox(
546
+ label="GitHub URL", placeholder="https://github.com/..."
547
+ )
548
+ huggingface_url_input = gr.Textbox(
549
+ label="Hugging Face URL",
550
+ placeholder="https://huggingface.co/datasets/...",
551
+ )
552
+ zenodo_url_input = gr.Textbox(
553
+ label="Zenodo URL", placeholder="https://zenodo.org/..."
554
+ )
555
+
556
+ gr.Markdown("**Optional Information**")
557
+ paper_url_input = gr.Textbox(
558
+ label="Paper URL", placeholder="https://arxiv.org/..."
559
+ )
560
+ website_url_input = gr.Textbox(
561
+ label="Website URL", placeholder="https://..."
562
+ )
563
+
564
+ task_input = gr.CheckboxGroup(
565
+ label="Tasks",
566
+ choices=[
567
+ "text classification",
568
+ "sentiment analysis",
569
+ "named entity recognition",
570
+ "part-of-speech tagging",
571
+ "question answering",
572
+ "text summarization",
573
+ "machine translation",
574
+ "language modeling",
575
+ "text generation",
576
+ "information extraction",
577
+ "semantic similarity",
578
+ "natural language inference",
579
+ ],
580
+ )
581
+
582
+ domain_input = gr.CheckboxGroup(
583
+ label="Domain",
584
+ choices=[
585
+ "clinical",
586
+ "legal",
587
+ "financial",
588
+ "scientific",
589
+ "news",
590
+ "social media",
591
+ "literature",
592
+ "general",
593
+ ],
594
+ )
595
+
596
+ countries_input = gr.CheckboxGroup(
597
+ label="Countries",
598
+ choices=[
599
+ "Spain",
600
+ "Mexico",
601
+ "Argentina",
602
+ "Colombia",
603
+ "Peru",
604
+ "Venezuela",
605
+ "Chile",
606
+ "Ecuador",
607
+ "Guatemala",
608
+ "Cuba",
609
+ "Bolivia",
610
+ "Dominican Republic",
611
+ "Honduras",
612
+ "Paraguay",
613
+ "El Salvador",
614
+ "Nicaragua",
615
+ "Costa Rica",
616
+ "Panama",
617
+ "Uruguay",
618
+ "Puerto Rico",
619
+ ],
620
+ )
621
+
622
+ languages_input = gr.CheckboxGroup(
623
+ label="Languages",
624
+ choices=[
625
+ "spanish",
626
+ "catalan",
627
+ "basque",
628
+ "galician",
629
+ "guarani",
630
+ "quechua",
631
+ "aymara",
632
+ ],
633
+ )
634
+
635
+ update_btn = gr.Button("πŸ’Ύ Update Entry", variant="primary")
636
+ result_msg = gr.Markdown()
637
+
638
+ # Store the original name for updating
639
+ original_name_state = gr.State("")
640
+
641
+ def search_and_update_dropdown(query):
642
+ results_df = search_entries(query)
643
+ if results_df.empty:
644
+ return gr.Dropdown(choices=[], value=None)
645
+ else:
646
+ choices = results_df["name"].tolist()
647
+ return gr.Dropdown(choices=choices, value=None)
648
+
649
+ def load_entry_and_show_form(selected_entry):
650
+ if not selected_entry:
651
+ return (gr.Column(visible=False), "", *[("",) * 11])
652
+
653
+ entry_data = load_entry_for_edit(selected_entry)
654
+ return (gr.Column(visible=True), selected_entry, *entry_data)
655
+
656
+ # Event handlers
657
+ search_btn.click(
658
+ fn=search_and_update_dropdown,
659
+ inputs=[search_input],
660
+ outputs=[search_results],
661
+ )
662
+
663
+ search_results.change(
664
+ fn=load_entry_and_show_form,
665
+ inputs=[search_results],
666
+ outputs=[
667
+ edit_form,
668
+ original_name_state,
669
+ name_input,
670
+ github_url_input,
671
+ huggingface_url_input,
672
+ zenodo_url_input,
673
+ paper_url_input,
674
+ dataset_type_input,
675
+ task_input,
676
+ domain_input,
677
+ website_url_input,
678
+ countries_input,
679
+ languages_input,
680
+ ],
681
+ )
682
+
683
+ update_btn.click(
684
+ fn=update_entry,
685
+ inputs=[
686
+ original_name_state,
687
+ name_input,
688
+ github_url_input,
689
+ huggingface_url_input,
690
+ zenodo_url_input,
691
+ paper_url_input,
692
+ dataset_type_input,
693
+ task_input,
694
+ domain_input,
695
+ website_url_input,
696
+ countries_input,
697
+ languages_input,
698
+ ],
699
+ outputs=[result_msg],
700
+ )
701
+
702
+ return (
703
+ search_input,
704
+ search_btn,
705
+ search_results,
706
+ edit_form,
707
+ name_input,
708
+ dataset_type_input,
709
+ github_url_input,
710
+ huggingface_url_input,
711
+ zenodo_url_input,
712
+ paper_url_input,
713
+ website_url_input,
714
+ task_input,
715
+ domain_input,
716
+ countries_input,
717
+ languages_input,
718
+ update_btn,
719
+ result_msg,
720
+ )
721
+
722
+
723
  def create_tab():
724
  """Create the complete tab for this resource type."""
725
  with gr.TabItem(f"πŸ“Š {RESOURCE_TITLE}", id=RESOURCE_TYPE):
726
  with gr.Tabs():
727
  table = create_all_tab()
728
  inputs = create_contribute_tab()
729
+ edit_components = create_edit_tab()
730
+ return table, inputs, edit_components
events_resource.py CHANGED
@@ -306,10 +306,267 @@ def create_contribute_tab():
306
  )
307
 
308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  def create_tab():
310
  """Create the complete tab for this resource type."""
311
  with gr.TabItem(f"πŸ“… {RESOURCE_TITLE}", id=RESOURCE_TYPE):
312
  with gr.Tabs():
313
  table = create_all_tab()
314
  inputs = create_contribute_tab()
315
- return table, inputs
 
 
306
  )
307
 
308
 
309
+ def search_entries(query: str) -> pd.DataFrame:
310
+ """Search for entries by titulo or ponente."""
311
+ if not query.strip():
312
+ return pd.DataFrame()
313
+
314
+ df = load_data()
315
+ if df.empty:
316
+ return df
317
+
318
+ # Search in titulo and ponente columns
319
+ mask = df["titulo"].str.contains(query, case=False, na=False) | df[
320
+ "ponente"
321
+ ].str.contains(query, case=False, na=False)
322
+
323
+ return df[mask]
324
+
325
+
326
+ def load_entry_for_edit(selected_entry: str) -> tuple:
327
+ """Load a specific entry for editing."""
328
+ if not selected_entry:
329
+ return ("",) * 9 # Return empty values for all fields
330
+
331
+ df = load_data()
332
+ if df.empty:
333
+ return ("",) * 9
334
+
335
+ # Find the entry by titulo
336
+ entry = df[df["titulo"] == selected_entry].iloc[0]
337
+
338
+ return (
339
+ entry["titulo"],
340
+ entry["ponente"],
341
+ entry["bio"],
342
+ entry["tipo"],
343
+ entry["etiquetas"],
344
+ entry["tema"],
345
+ str(entry["nivel_tecnico"]),
346
+ entry["fecha"],
347
+ entry["youtube"],
348
+ )
349
+
350
+
351
+ def update_entry(
352
+ original_titulo: str,
353
+ titulo: str,
354
+ ponente: str,
355
+ bio: str,
356
+ tipo: str,
357
+ etiquetas: str,
358
+ tema: str,
359
+ nivel_tecnico: str,
360
+ fecha: str,
361
+ youtube: str,
362
+ profile: gr.OAuthProfile | None,
363
+ ):
364
+ """Update an existing entry."""
365
+ if not profile:
366
+ return "❌ Please log in to edit entries."
367
+
368
+ username = profile.username
369
+ if not username:
370
+ return "❌ Could not get username from profile."
371
+
372
+ if not original_titulo:
373
+ return "❌ No entry selected to edit."
374
+
375
+ # Validate required fields
376
+ required_fields = [
377
+ titulo,
378
+ ponente,
379
+ bio,
380
+ tipo,
381
+ etiquetas,
382
+ tema,
383
+ nivel_tecnico,
384
+ fecha,
385
+ youtube,
386
+ ]
387
+ if not all(field.strip() for field in required_fields):
388
+ return "❌ All fields are required."
389
+
390
+ # Validate YouTube URL
391
+ if not validate_url(youtube):
392
+ return "❌ Invalid YouTube URL. Please provide a valid URL."
393
+
394
+ # Validate technical level
395
+ if not validate_nivel_tecnico(nivel_tecnico):
396
+ return "❌ Invalid technical level. Please select a value from 1 to 5."
397
+
398
+ # Validate date format
399
+ if not validate_date(fecha):
400
+ return "❌ Invalid date format. Please use DD/MM/YYYY format."
401
+
402
+ try:
403
+ # Load existing dataset
404
+ existing_dataset = load_dataset(DATASET_NAME, CONFIG_NAME, split="train")
405
+ existing_df = existing_dataset.to_pandas()
406
+
407
+ # Find and update the entry
408
+ mask = existing_df["titulo"] == original_titulo
409
+ if not mask.any():
410
+ return f"❌ Entry '{original_titulo}' not found."
411
+
412
+ # Update the entry
413
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
414
+
415
+ existing_df.loc[mask, "titulo"] = titulo
416
+ existing_df.loc[mask, "ponente"] = ponente
417
+ existing_df.loc[mask, "bio"] = bio
418
+ existing_df.loc[mask, "tipo"] = tipo
419
+ existing_df.loc[mask, "etiquetas"] = etiquetas
420
+ existing_df.loc[mask, "tema"] = tema
421
+ existing_df.loc[mask, "nivel_tecnico"] = nivel_tecnico
422
+ existing_df.loc[mask, "fecha"] = fecha
423
+ existing_df.loc[mask, "youtube"] = youtube
424
+ existing_df.loc[mask, "date_submitted"] = current_time
425
+
426
+ # Convert back to Dataset and push to hub
427
+ updated_dataset = Dataset.from_pandas(existing_df)
428
+ updated_dataset.push_to_hub(
429
+ DATASET_NAME,
430
+ config_name=CONFIG_NAME,
431
+ commit_message=f"Update event entry: {titulo} (edited by {username})",
432
+ )
433
+
434
+ return f"βœ… Successfully updated '{titulo}'!"
435
+
436
+ except Exception as e:
437
+ return f"❌ Error updating entry: {str(e)}"
438
+
439
+
440
+ def create_edit_tab():
441
+ """Create the edit tab for modifying existing entries."""
442
+ with gr.TabItem("✏️ Edit", id=f"{RESOURCE_TYPE}_edit"):
443
+ gr.Markdown(f"### Edit Existing {RESOURCE_TITLE}")
444
+ gr.Markdown("Please log in to edit entries:")
445
+ login_button = gr.LoginButton(elem_id=f"{RESOURCE_TYPE}-edit-oauth-button")
446
+
447
+ gr.Markdown("Search for an entry to edit:")
448
+
449
+ with gr.Row():
450
+ search_input = gr.Textbox(
451
+ label="Search by title or speaker",
452
+ placeholder="Enter event title or speaker name...",
453
+ scale=3,
454
+ )
455
+ search_btn = gr.Button("πŸ” Search", scale=1)
456
+
457
+ search_results = gr.Dropdown(
458
+ label="Select entry to edit", choices=[], interactive=True
459
+ )
460
+
461
+ gr.Markdown("---")
462
+ gr.Markdown("**Edit the selected entry:**")
463
+
464
+ with gr.Column(visible=False) as edit_form:
465
+ titulo_input = gr.Textbox(label="TΓ­tulo *", placeholder="Event title")
466
+ ponente_input = gr.Textbox(label="Ponente *", placeholder="Speaker name")
467
+ bio_input = gr.Textbox(label="Bio *", lines=2, placeholder="Speaker bio")
468
+ tipo_input = gr.Dropdown(
469
+ label="Tipo *",
470
+ choices=["workshop", "talk", "AMA", "round table"],
471
+ value="talk",
472
+ )
473
+ etiquetas_input = gr.Textbox(label="Etiquetas *", placeholder="Tags")
474
+ tema_input = gr.Textbox(label="Tema *", placeholder="Topic")
475
+ nivel_tecnico_input = gr.Dropdown(
476
+ label="Nivel TΓ©cnico *", choices=["1", "2", "3", "4", "5"], value="3"
477
+ )
478
+ fecha_input = gr.Textbox(label="Fecha *", placeholder="DD/MM/YYYY")
479
+ youtube_input = gr.Textbox(
480
+ label="YouTube *", placeholder="https://youtube.com/..."
481
+ )
482
+
483
+ update_btn = gr.Button("πŸ’Ύ Update Entry", variant="primary")
484
+ result_msg = gr.Markdown()
485
+
486
+ # Store the original titulo for updating
487
+ original_titulo_state = gr.State("")
488
+
489
+ def search_and_update_dropdown(query):
490
+ results_df = search_entries(query)
491
+ if results_df.empty:
492
+ return gr.Dropdown(choices=[], value=None)
493
+ else:
494
+ choices = results_df["titulo"].tolist()
495
+ return gr.Dropdown(choices=choices, value=None)
496
+
497
+ def load_entry_and_show_form(selected_entry):
498
+ if not selected_entry:
499
+ return (gr.Column(visible=False), "", *[("",) * 9])
500
+
501
+ entry_data = load_entry_for_edit(selected_entry)
502
+ return (gr.Column(visible=True), selected_entry, *entry_data)
503
+
504
+ # Event handlers
505
+ search_btn.click(
506
+ fn=search_and_update_dropdown,
507
+ inputs=[search_input],
508
+ outputs=[search_results],
509
+ )
510
+
511
+ search_results.change(
512
+ fn=load_entry_and_show_form,
513
+ inputs=[search_results],
514
+ outputs=[
515
+ edit_form,
516
+ original_titulo_state,
517
+ titulo_input,
518
+ ponente_input,
519
+ bio_input,
520
+ tipo_input,
521
+ etiquetas_input,
522
+ tema_input,
523
+ nivel_tecnico_input,
524
+ fecha_input,
525
+ youtube_input,
526
+ ],
527
+ )
528
+
529
+ update_btn.click(
530
+ fn=update_entry,
531
+ inputs=[
532
+ original_titulo_state,
533
+ titulo_input,
534
+ ponente_input,
535
+ bio_input,
536
+ tipo_input,
537
+ etiquetas_input,
538
+ tema_input,
539
+ nivel_tecnico_input,
540
+ fecha_input,
541
+ youtube_input,
542
+ ],
543
+ outputs=[result_msg],
544
+ )
545
+
546
+ return (
547
+ search_input,
548
+ search_btn,
549
+ search_results,
550
+ edit_form,
551
+ titulo_input,
552
+ ponente_input,
553
+ bio_input,
554
+ tipo_input,
555
+ etiquetas_input,
556
+ tema_input,
557
+ nivel_tecnico_input,
558
+ fecha_input,
559
+ youtube_input,
560
+ update_btn,
561
+ result_msg,
562
+ )
563
+
564
+
565
  def create_tab():
566
  """Create the complete tab for this resource type."""
567
  with gr.TabItem(f"πŸ“… {RESOURCE_TITLE}", id=RESOURCE_TYPE):
568
  with gr.Tabs():
569
  table = create_all_tab()
570
  inputs = create_contribute_tab()
571
+ edit_components = create_edit_tab()
572
+ return table, inputs, edit_components
initiatives_resource.py CHANGED
@@ -282,10 +282,281 @@ def create_contribute_tab():
282
  )
283
 
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  def create_tab():
286
  """Create the complete tab for this resource type."""
287
  with gr.TabItem(f"🌟 {RESOURCE_TITLE}", id=RESOURCE_TYPE):
288
  with gr.Tabs():
289
  table = create_all_tab()
290
  inputs = create_contribute_tab()
291
- return table, inputs
 
 
282
  )
283
 
284
 
285
+ def search_entries(query: str) -> pd.DataFrame:
286
+ """Search for entries by name or website URL."""
287
+ if not query.strip():
288
+ return pd.DataFrame()
289
+
290
+ df = load_data()
291
+ if df.empty:
292
+ return df
293
+
294
+ # Search in name and website_url columns
295
+ mask = df["name"].str.contains(query, case=False, na=False) | df[
296
+ "website_url"
297
+ ].str.contains(query, case=False, na=False)
298
+
299
+ return df[mask]
300
+
301
+
302
+ def load_entry_for_edit(selected_entry: str) -> tuple:
303
+ """Load a specific entry for editing."""
304
+ if not selected_entry:
305
+ return ("",) * 5 # Return empty values for all fields
306
+
307
+ df = load_data()
308
+ if df.empty:
309
+ return ("",) * 5
310
+
311
+ # Find the entry by name
312
+ entry = df[df["name"] == selected_entry].iloc[0]
313
+
314
+ # Convert comma-separated strings back to lists for multi-select components
315
+ countries_list = (
316
+ [c.strip() for c in entry["countries"].split(",")] if entry["countries"] else []
317
+ )
318
+ languages_list = (
319
+ [l.strip() for l in entry["languages"].split(",")] if entry["languages"] else []
320
+ )
321
+
322
+ return (
323
+ entry["name"],
324
+ entry["type"],
325
+ countries_list,
326
+ languages_list,
327
+ entry["website_url"],
328
+ )
329
+
330
+
331
+ def update_entry(
332
+ original_name: str,
333
+ name: str,
334
+ initiative_type: str,
335
+ countries: list,
336
+ languages: list,
337
+ website_url: str,
338
+ profile: gr.OAuthProfile | None,
339
+ ):
340
+ """Update an existing entry."""
341
+ if not profile:
342
+ return "❌ Please log in to edit entries."
343
+
344
+ username = profile.username
345
+ if not username:
346
+ return "❌ Could not get username from profile."
347
+
348
+ if not original_name:
349
+ return "❌ No entry selected to edit."
350
+
351
+ # Validate required fields
352
+ if not name.strip():
353
+ return "❌ Name is required."
354
+
355
+ if not initiative_type:
356
+ return "❌ Type is required."
357
+
358
+ if not countries:
359
+ return "❌ At least one country is required."
360
+
361
+ if not languages:
362
+ return "❌ At least one language is required."
363
+
364
+ if not website_url.strip():
365
+ return "❌ Website URL is required."
366
+
367
+ # Validate URL
368
+ if not validate_url(website_url):
369
+ return "❌ Invalid website URL. Please provide a valid URL."
370
+
371
+ try:
372
+ # Load existing dataset
373
+ existing_dataset = load_dataset(DATASET_NAME, CONFIG_NAME, split="train")
374
+ existing_df = existing_dataset.to_pandas()
375
+
376
+ # Find and update the entry
377
+ mask = existing_df["name"] == original_name
378
+ if not mask.any():
379
+ return f"❌ Entry '{original_name}' not found."
380
+
381
+ # Update the entry
382
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
383
+
384
+ existing_df.loc[mask, "name"] = name
385
+ existing_df.loc[mask, "type"] = initiative_type
386
+ existing_df.loc[mask, "countries"] = ", ".join(countries) if countries else ""
387
+ existing_df.loc[mask, "languages"] = ", ".join(languages) if languages else ""
388
+ existing_df.loc[mask, "website_url"] = website_url
389
+ existing_df.loc[mask, "date_submitted"] = current_time
390
+
391
+ # Convert back to Dataset and push to hub
392
+ updated_dataset = Dataset.from_pandas(existing_df)
393
+ updated_dataset.push_to_hub(
394
+ DATASET_NAME,
395
+ config_name=CONFIG_NAME,
396
+ commit_message=f"Update initiative entry: {name} (edited by {username})",
397
+ )
398
+
399
+ return f"βœ… Successfully updated '{name}'!"
400
+
401
+ except Exception as e:
402
+ return f"❌ Error updating entry: {str(e)}"
403
+
404
+
405
+ def create_edit_tab():
406
+ """Create the edit tab for modifying existing entries."""
407
+ with gr.TabItem("✏️ Edit", id=f"{RESOURCE_TYPE}_edit"):
408
+ gr.Markdown(f"### Edit Existing {RESOURCE_TITLE}")
409
+ gr.Markdown("Please log in to edit entries:")
410
+ login_button = gr.LoginButton(elem_id=f"{RESOURCE_TYPE}-edit-oauth-button")
411
+
412
+ gr.Markdown("Search for an entry to edit:")
413
+
414
+ with gr.Row():
415
+ search_input = gr.Textbox(
416
+ label="Search by name or website URL",
417
+ placeholder="Enter initiative name or website URL...",
418
+ scale=3,
419
+ )
420
+ search_btn = gr.Button("πŸ” Search", scale=1)
421
+
422
+ search_results = gr.Dropdown(
423
+ label="Select entry to edit", choices=[], interactive=True
424
+ )
425
+
426
+ gr.Markdown("---")
427
+ gr.Markdown("**Edit the selected entry:**")
428
+
429
+ with gr.Column(visible=False) as edit_form:
430
+ name_input = gr.Textbox(label="Name *", placeholder="Initiative name")
431
+ type_input = gr.Dropdown(
432
+ label="Type *",
433
+ choices=[
434
+ "project",
435
+ "event",
436
+ "research group",
437
+ "community",
438
+ "research institute",
439
+ "non-profit",
440
+ "OS company",
441
+ ],
442
+ value="project",
443
+ )
444
+ countries_input = gr.CheckboxGroup(
445
+ label="Countries *",
446
+ choices=[
447
+ "Spain",
448
+ "Mexico",
449
+ "Argentina",
450
+ "Colombia",
451
+ "Peru",
452
+ "Venezuela",
453
+ "Chile",
454
+ "Ecuador",
455
+ "Guatemala",
456
+ "Cuba",
457
+ "Bolivia",
458
+ "Dominican Republic",
459
+ "Honduras",
460
+ "Paraguay",
461
+ "El Salvador",
462
+ "Nicaragua",
463
+ "Costa Rica",
464
+ "Panama",
465
+ "Uruguay",
466
+ "Puerto Rico",
467
+ ],
468
+ )
469
+ languages_input = gr.CheckboxGroup(
470
+ label="Languages *",
471
+ choices=[
472
+ "spanish",
473
+ "catalan",
474
+ "basque",
475
+ "galician",
476
+ "guarani",
477
+ "quechua",
478
+ "aymara",
479
+ ],
480
+ )
481
+ website_url_input = gr.Textbox(
482
+ label="Website URL *", placeholder="https://..."
483
+ )
484
+
485
+ update_btn = gr.Button("πŸ’Ύ Update Entry", variant="primary")
486
+ result_msg = gr.Markdown()
487
+
488
+ # Store the original name for updating
489
+ original_name_state = gr.State("")
490
+
491
+ def search_and_update_dropdown(query):
492
+ results_df = search_entries(query)
493
+ if results_df.empty:
494
+ return gr.Dropdown(choices=[], value=None)
495
+ else:
496
+ choices = results_df["name"].tolist()
497
+ return gr.Dropdown(choices=choices, value=None)
498
+
499
+ def load_entry_and_show_form(selected_entry):
500
+ if not selected_entry:
501
+ return (gr.Column(visible=False), "", *[("",) * 5])
502
+
503
+ entry_data = load_entry_for_edit(selected_entry)
504
+ return (gr.Column(visible=True), selected_entry, *entry_data)
505
+
506
+ # Event handlers
507
+ search_btn.click(
508
+ fn=search_and_update_dropdown,
509
+ inputs=[search_input],
510
+ outputs=[search_results],
511
+ )
512
+
513
+ search_results.change(
514
+ fn=load_entry_and_show_form,
515
+ inputs=[search_results],
516
+ outputs=[
517
+ edit_form,
518
+ original_name_state,
519
+ name_input,
520
+ type_input,
521
+ countries_input,
522
+ languages_input,
523
+ website_url_input,
524
+ ],
525
+ )
526
+
527
+ update_btn.click(
528
+ fn=update_entry,
529
+ inputs=[
530
+ original_name_state,
531
+ name_input,
532
+ type_input,
533
+ countries_input,
534
+ languages_input,
535
+ website_url_input,
536
+ ],
537
+ outputs=[result_msg],
538
+ )
539
+
540
+ return (
541
+ search_input,
542
+ search_btn,
543
+ search_results,
544
+ edit_form,
545
+ name_input,
546
+ type_input,
547
+ countries_input,
548
+ languages_input,
549
+ website_url_input,
550
+ update_btn,
551
+ result_msg,
552
+ )
553
+
554
+
555
  def create_tab():
556
  """Create the complete tab for this resource type."""
557
  with gr.TabItem(f"🌟 {RESOURCE_TITLE}", id=RESOURCE_TYPE):
558
  with gr.Tabs():
559
  table = create_all_tab()
560
  inputs = create_contribute_tab()
561
+ edit_components = create_edit_tab()
562
+ return table, inputs, edit_components
models_resource.py CHANGED
@@ -256,10 +256,208 @@ def create_contribute_tab():
256
  )
257
 
258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  def create_tab():
260
  """Create the complete tab for this resource type."""
261
  with gr.TabItem(f"πŸ€– {RESOURCE_TITLE}", id=RESOURCE_TYPE):
262
  with gr.Tabs():
263
  table = create_all_tab()
264
  inputs = create_contribute_tab()
265
- return table, inputs
 
 
256
  )
257
 
258
 
259
+
260
+ def search_entries(query: str) -> pd.DataFrame:
261
+ """Search for entries by familia or URL."""
262
+ if not query.strip():
263
+ return pd.DataFrame()
264
+
265
+ df = load_data()
266
+ if df.empty:
267
+ return df
268
+
269
+ # Search in familia and hf_collection_url columns
270
+ mask = (
271
+ df['familia'].str.contains(query, case=False, na=False) |
272
+ df['hf_collection_url'].str.contains(query, case=False, na=False)
273
+ )
274
+
275
+ return df[mask]
276
+
277
+
278
+ def load_entry_for_edit(selected_entry: str) -> tuple:
279
+ """Load a specific entry for editing."""
280
+ if not selected_entry:
281
+ return ("",) * 5 # Return empty values for all fields
282
+
283
+ df = load_data()
284
+ if df.empty:
285
+ return ("",) * 5
286
+
287
+ # Find the entry by familia or hf_collection_url
288
+ entry = df[df['familia'] == selected_entry].iloc[0] if (df['familia'] == selected_entry).any() else df[df['hf_collection_url'] == selected_entry].iloc[0]
289
+
290
+ return (
291
+ entry['familia'],
292
+ entry['available_sizes'],
293
+ entry['hf_collection_url'],
294
+ entry['website_url'],
295
+ entry['paper_url']
296
+ )
297
+
298
+
299
+ def update_entry(
300
+ original_identifier: str,
301
+ familia: str, available_sizes: str, hf_collection_url: str,
302
+ website_url: str, paper_url: str, profile: gr.OAuthProfile | None
303
+ ):
304
+ """Update an existing entry."""
305
+ if not profile:
306
+ return "❌ Please log in to edit entries."
307
+
308
+ username = profile.username
309
+ if not username:
310
+ return "❌ Could not get username from profile."
311
+
312
+ if not original_identifier:
313
+ return "❌ No entry selected to edit."
314
+
315
+ if not hf_collection_url.strip():
316
+ return "❌ Hugging Face Collection URL is required."
317
+
318
+ # Validate URLs
319
+ for url_field, url_value in [("Hugging Face Collection URL", hf_collection_url),
320
+ ("Website URL", website_url), ("Paper URL", paper_url)]:
321
+ if url_value.strip() and not validate_url(url_value):
322
+ return f"❌ Invalid {url_field}. Please provide a valid URL."
323
+
324
+ # Validate available_sizes format
325
+ if available_sizes.strip() and not validate_sizes(available_sizes):
326
+ return "❌ Invalid available sizes format. Use comma-separated numbers (e.g., '0.1, 1.3, 7, 14')."
327
+
328
+ try:
329
+ # Load existing dataset
330
+ existing_dataset = load_dataset(DATASET_NAME, CONFIG_NAME, split="train")
331
+ existing_df = existing_dataset.to_pandas()
332
+
333
+ # Find and update the entry
334
+ mask = (existing_df['familia'] == original_identifier) | (existing_df['hf_collection_url'] == original_identifier)
335
+ if not mask.any():
336
+ return f"❌ Entry '{original_identifier}' not found."
337
+
338
+ # Update the entry
339
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
340
+
341
+ existing_df.loc[mask, 'familia'] = familia
342
+ existing_df.loc[mask, 'available_sizes'] = available_sizes
343
+ existing_df.loc[mask, 'hf_collection_url'] = hf_collection_url
344
+ existing_df.loc[mask, 'website_url'] = website_url
345
+ existing_df.loc[mask, 'paper_url'] = paper_url
346
+ existing_df.loc[mask, 'date_submitted'] = current_time
347
+
348
+ # Convert back to Dataset and push to hub
349
+ updated_dataset = Dataset.from_pandas(existing_df)
350
+ updated_dataset.push_to_hub(
351
+ DATASET_NAME,
352
+ config_name=CONFIG_NAME,
353
+ commit_message=f"Update model entry: {familia or hf_collection_url} (edited by {username})",
354
+ )
355
+
356
+ return f"βœ… Successfully updated '{familia or hf_collection_url}'!"
357
+
358
+ except Exception as e:
359
+ return f"❌ Error updating entry: {str(e)}"
360
+
361
+
362
+
363
+ def create_edit_tab():
364
+ """Create the edit tab for modifying existing entries."""
365
+ with gr.TabItem("✏️ Edit", id=f"{RESOURCE_TYPE}_edit"):
366
+ gr.Markdown(f"### Edit Existing {RESOURCE_TITLE}")
367
+ gr.Markdown("Please log in to edit entries:")
368
+ login_button = gr.LoginButton(elem_id=f"{RESOURCE_TYPE}-edit-oauth-button")
369
+
370
+ gr.Markdown("Search for an entry to edit:")
371
+
372
+ with gr.Row():
373
+ search_input = gr.Textbox(
374
+ label="Search by familia or collection URL",
375
+ placeholder="Enter model familia or Hugging Face collection URL...",
376
+ scale=3
377
+ )
378
+ search_btn = gr.Button("πŸ” Search", scale=1)
379
+
380
+ search_results = gr.Dropdown(
381
+ label="Select entry to edit",
382
+ choices=[],
383
+ interactive=True
384
+ )
385
+
386
+ gr.Markdown("---")
387
+ gr.Markdown("**Edit the selected entry:**")
388
+
389
+ with gr.Column(visible=False) as edit_form:
390
+ hf_collection_url_input = gr.Textbox(label="Hugging Face Collection URL *", placeholder="https://huggingface.co/collections/...")
391
+ familia_input = gr.Textbox(label="Familia", placeholder="e.g., BERT, GPT, T5...")
392
+ available_sizes_input = gr.Textbox(
393
+ label="Available Sizes (in B parameters)",
394
+ placeholder="e.g., 0.1, 1.3, 7, 14",
395
+ info="Comma-separated list of model sizes in billions of parameters"
396
+ )
397
+ website_url_input = gr.Textbox(label="Website URL", placeholder="https://...")
398
+ paper_url_input = gr.Textbox(label="Paper URL", placeholder="https://arxiv.org/...")
399
+
400
+ update_btn = gr.Button("πŸ’Ύ Update Entry", variant="primary")
401
+ result_msg = gr.Markdown()
402
+
403
+ # Store the original identifier for updating
404
+ original_identifier_state = gr.State("")
405
+
406
+ def search_and_update_dropdown(query):
407
+ results_df = search_entries(query)
408
+ if results_df.empty:
409
+ return gr.Dropdown(choices=[], value=None)
410
+ else:
411
+ # Use familia if available, otherwise use hf_collection_url
412
+ choices = [entry if entry else url for entry, url in zip(results_df['familia'].fillna(''), results_df['hf_collection_url'])]
413
+ return gr.Dropdown(choices=choices, value=None)
414
+
415
+ def load_entry_and_show_form(selected_entry):
416
+ if not selected_entry:
417
+ return (gr.Column(visible=False), "", *[("",) * 5])
418
+
419
+ entry_data = load_entry_for_edit(selected_entry)
420
+ return (gr.Column(visible=True), selected_entry, *entry_data)
421
+
422
+ # Event handlers
423
+ search_btn.click(
424
+ fn=search_and_update_dropdown,
425
+ inputs=[search_input],
426
+ outputs=[search_results]
427
+ )
428
+
429
+ search_results.change(
430
+ fn=load_entry_and_show_form,
431
+ inputs=[search_results],
432
+ outputs=[
433
+ edit_form, original_identifier_state,
434
+ familia_input, available_sizes_input, hf_collection_url_input,
435
+ website_url_input, paper_url_input
436
+ ]
437
+ )
438
+
439
+ update_btn.click(
440
+ fn=update_entry,
441
+ inputs=[
442
+ original_identifier_state,
443
+ familia_input, available_sizes_input, hf_collection_url_input,
444
+ website_url_input, paper_url_input
445
+ ],
446
+ outputs=[result_msg]
447
+ )
448
+
449
+ return (
450
+ search_input, search_btn, search_results, edit_form,
451
+ familia_input, available_sizes_input, hf_collection_url_input,
452
+ website_url_input, paper_url_input, update_btn, result_msg
453
+ )
454
+
455
+
456
  def create_tab():
457
  """Create the complete tab for this resource type."""
458
  with gr.TabItem(f"πŸ€– {RESOURCE_TITLE}", id=RESOURCE_TYPE):
459
  with gr.Tabs():
460
  table = create_all_tab()
461
  inputs = create_contribute_tab()
462
+ edit_components = create_edit_tab()
463
+ return table, inputs, edit_components
shared_tasks_resource.py CHANGED
@@ -289,10 +289,222 @@ def create_contribute_tab():
289
  )
290
 
291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  def create_tab():
293
  """Create the complete tab for this resource type."""
294
  with gr.TabItem(f"πŸ† {RESOURCE_TITLE}", id=RESOURCE_TYPE):
295
  with gr.Tabs():
296
  table = create_all_tab()
297
  inputs = create_contribute_tab()
298
- return table, inputs
 
 
289
  )
290
 
291
 
292
+
293
+ def search_entries(query: str) -> pd.DataFrame:
294
+ """Search for entries by name or conference."""
295
+ if not query.strip():
296
+ return pd.DataFrame()
297
+
298
+ df = load_data()
299
+ if df.empty:
300
+ return df
301
+
302
+ # Search in name and conference_name columns
303
+ mask = (
304
+ df['name'].str.contains(query, case=False, na=False) |
305
+ df['conference_name'].str.contains(query, case=False, na=False)
306
+ )
307
+
308
+ return df[mask]
309
+
310
+
311
+ def load_entry_for_edit(selected_entry: str) -> tuple:
312
+ """Load a specific entry for editing."""
313
+ if not selected_entry:
314
+ return ("",) * 7 # Return empty values for all fields
315
+
316
+ df = load_data()
317
+ if df.empty:
318
+ return ("",) * 7
319
+
320
+ # Find the entry by name
321
+ entry = df[df['name'] == selected_entry].iloc[0]
322
+
323
+ return (
324
+ entry['name'],
325
+ entry['conference_name'],
326
+ entry['workshop_date'],
327
+ entry['registration_deadline'],
328
+ entry['data_available_date'],
329
+ entry['submission_deadline'],
330
+ entry['more_info_url']
331
+ )
332
+
333
+
334
+ def update_entry(
335
+ original_name: str,
336
+ name: str, conference_name: str, workshop_date: str, registration_deadline: str,
337
+ data_available_date: str, submission_deadline: str, more_info_url: str,
338
+ profile: gr.OAuthProfile | None,
339
+ ):
340
+ """Update an existing entry."""
341
+ if not profile:
342
+ return "❌ Please log in to edit entries."
343
+
344
+ username = profile.username
345
+ if not username:
346
+ return "❌ Could not get username from profile."
347
+
348
+ if not original_name:
349
+ return "❌ No entry selected to edit."
350
+
351
+ # Validate required fields
352
+ required_fields = [name, conference_name, workshop_date, registration_deadline,
353
+ data_available_date, submission_deadline, more_info_url]
354
+ if not all(field.strip() for field in required_fields):
355
+ return "❌ All fields are required."
356
+
357
+ # Validate URL
358
+ if not validate_url(more_info_url):
359
+ return "❌ Invalid URL. Please provide a valid URL."
360
+
361
+ # Validate dates
362
+ date_fields = [("Workshop Date", workshop_date), ("Registration Deadline", registration_deadline),
363
+ ("Data Available Date", data_available_date), ("Submission Deadline", submission_deadline)]
364
+ for field_name, date_value in date_fields:
365
+ if not validate_date(date_value):
366
+ return f"❌ Invalid {field_name}. Please use DD/MM/YYYY format."
367
+
368
+ try:
369
+ # Load existing dataset
370
+ existing_dataset = load_dataset(DATASET_NAME, CONFIG_NAME, split="train")
371
+ existing_df = existing_dataset.to_pandas()
372
+
373
+ # Find and update the entry
374
+ mask = existing_df['name'] == original_name
375
+ if not mask.any():
376
+ return f"❌ Entry '{original_name}' not found."
377
+
378
+ # Update the entry
379
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
380
+
381
+ existing_df.loc[mask, 'name'] = name
382
+ existing_df.loc[mask, 'conference_name'] = conference_name
383
+ existing_df.loc[mask, 'workshop_date'] = workshop_date
384
+ existing_df.loc[mask, 'registration_deadline'] = registration_deadline
385
+ existing_df.loc[mask, 'data_available_date'] = data_available_date
386
+ existing_df.loc[mask, 'submission_deadline'] = submission_deadline
387
+ existing_df.loc[mask, 'more_info_url'] = more_info_url
388
+ existing_df.loc[mask, 'date_submitted'] = current_time
389
+
390
+ # Convert back to Dataset and push to hub
391
+ updated_dataset = Dataset.from_pandas(existing_df)
392
+ updated_dataset.push_to_hub(
393
+ DATASET_NAME,
394
+ config_name=CONFIG_NAME,
395
+ commit_message=f"Update shared task entry: {name} (edited by {username})",
396
+ )
397
+
398
+ return f"βœ… Successfully updated '{name}'!"
399
+
400
+ except Exception as e:
401
+ return f"❌ Error updating entry: {str(e)}"
402
+
403
+
404
+
405
+ def create_edit_tab():
406
+ """Create the edit tab for modifying existing entries."""
407
+ with gr.TabItem("✏️ Edit", id=f"{RESOURCE_TYPE}_edit"):
408
+ gr.Markdown(f"### Edit Existing {RESOURCE_TITLE}")
409
+ gr.Markdown("Please log in to edit entries:")
410
+ login_button = gr.LoginButton(elem_id=f"{RESOURCE_TYPE}-edit-oauth-button")
411
+
412
+ gr.Markdown("Search for an entry to edit:")
413
+
414
+ with gr.Row():
415
+ search_input = gr.Textbox(
416
+ label="Search by name or conference",
417
+ placeholder="Enter shared task name or conference name...",
418
+ scale=3
419
+ )
420
+ search_btn = gr.Button("πŸ” Search", scale=1)
421
+
422
+ search_results = gr.Dropdown(
423
+ label="Select entry to edit",
424
+ choices=[],
425
+ interactive=True
426
+ )
427
+
428
+ gr.Markdown("---")
429
+ gr.Markdown("**Edit the selected entry:**")
430
+
431
+ with gr.Column(visible=False) as edit_form:
432
+ name_input = gr.Textbox(label="Name *", placeholder="Shared task name")
433
+ conference_name_input = gr.Textbox(label="Conference Name *", placeholder="Conference or workshop name")
434
+
435
+ gr.Markdown("**Important Dates** (all required, format: DD/MM/YYYY)")
436
+ with gr.Row():
437
+ workshop_date_input = gr.Textbox(label="Workshop Date *", placeholder="DD/MM/YYYY")
438
+ registration_deadline_input = gr.Textbox(label="Registration Deadline *", placeholder="DD/MM/YYYY")
439
+ with gr.Row():
440
+ data_available_date_input = gr.Textbox(label="Data Available Date *", placeholder="DD/MM/YYYY")
441
+ submission_deadline_input = gr.Textbox(label="Submission Deadline *", placeholder="DD/MM/YYYY")
442
+
443
+ more_info_url_input = gr.Textbox(label="More Info URL *", placeholder="https://...")
444
+
445
+ update_btn = gr.Button("πŸ’Ύ Update Entry", variant="primary")
446
+ result_msg = gr.Markdown()
447
+
448
+ # Store the original name for updating
449
+ original_name_state = gr.State("")
450
+
451
+ def search_and_update_dropdown(query):
452
+ results_df = search_entries(query)
453
+ if results_df.empty:
454
+ return gr.Dropdown(choices=[], value=None)
455
+ else:
456
+ choices = results_df['name'].tolist()
457
+ return gr.Dropdown(choices=choices, value=None)
458
+
459
+ def load_entry_and_show_form(selected_entry):
460
+ if not selected_entry:
461
+ return (gr.Column(visible=False), "", *[("",) * 7])
462
+
463
+ entry_data = load_entry_for_edit(selected_entry)
464
+ return (gr.Column(visible=True), selected_entry, *entry_data)
465
+
466
+ # Event handlers
467
+ search_btn.click(
468
+ fn=search_and_update_dropdown,
469
+ inputs=[search_input],
470
+ outputs=[search_results]
471
+ )
472
+
473
+ search_results.change(
474
+ fn=load_entry_and_show_form,
475
+ inputs=[search_results],
476
+ outputs=[
477
+ edit_form, original_name_state,
478
+ name_input, conference_name_input, workshop_date_input,
479
+ registration_deadline_input, data_available_date_input,
480
+ submission_deadline_input, more_info_url_input
481
+ ]
482
+ )
483
+
484
+ update_btn.click(
485
+ fn=update_entry,
486
+ inputs=[
487
+ original_name_state,
488
+ name_input, conference_name_input, workshop_date_input,
489
+ registration_deadline_input, data_available_date_input,
490
+ submission_deadline_input, more_info_url_input,
491
+ ],
492
+ outputs=[result_msg]
493
+ )
494
+
495
+ return (
496
+ search_input, search_btn, search_results, edit_form,
497
+ name_input, conference_name_input, workshop_date_input,
498
+ registration_deadline_input, data_available_date_input,
499
+ submission_deadline_input, more_info_url_input, update_btn, result_msg
500
+ )
501
+
502
+
503
  def create_tab():
504
  """Create the complete tab for this resource type."""
505
  with gr.TabItem(f"πŸ† {RESOURCE_TITLE}", id=RESOURCE_TYPE):
506
  with gr.Tabs():
507
  table = create_all_tab()
508
  inputs = create_contribute_tab()
509
+ edit_components = create_edit_tab()
510
+ return table, inputs, edit_components