From 9a257a104cffc6c31c9ee2009aa781880a5e6f9c Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 25 Jul 2025 12:16:04 +0530 Subject: [PATCH 01/14] [GOVCMSCT2-121] Added fact fact related fields and configuration and added test to verify the BE fields. --- ...civictheme_infographic_card.fields.feature | 26 ++++++++ .../contrib/civictheme/civictheme.info.yml | 11 ++++ ...ph.civictheme_infographic_card.default.yml | 60 +++++++++++++++++ ...ph.civictheme_infographic_card.default.yml | 61 +++++++++++++++++ ...ctheme_infographic_card.field_c_p_icon.yml | 28 ++++++++ ...ctheme_infographic_card.field_c_p_link.yml | 22 +++++++ ...eme_infographic_card.field_c_p_summary.yml | 18 +++++ ...theme_infographic_card.field_c_p_theme.yml | 22 +++++++ ...theme_infographic_card.field_c_p_title.yml | 18 +++++ ...theme_manual_list.field_c_p_list_items.yml | 66 +++++++++++-------- ...raphs_type.civictheme_infographic_card.yml | 9 +++ .../contrib/civictheme/includes/cards.inc | 14 ++++ 12 files changed, 326 insertions(+), 29 deletions(-) create mode 100644 tests/behat/features/paragraph.civictheme_infographic_card.fields.feature create mode 100644 web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml create mode 100644 web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml create mode 100644 web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml create mode 100644 web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml create mode 100644 web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml create mode 100644 web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml create mode 100644 web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml create mode 100644 web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml diff --git a/tests/behat/features/paragraph.civictheme_infographic_card.fields.feature b/tests/behat/features/paragraph.civictheme_infographic_card.fields.feature new file mode 100644 index 0000000000..b3bb7f680c --- /dev/null +++ b/tests/behat/features/paragraph.civictheme_infographic_card.fields.feature @@ -0,0 +1,26 @@ +@p1 @civictheme @civictheme_card @civictheme_infographic_card +Feature: Fast fact card fields + + @api + Scenario: Fields appear as expected + Given I am logged in as a user with the "Site Administrator" role + When I visit "node/add/civictheme_page" + And I fill in "Title" with "[TEST] Page fields" + When I press "Add Manual list" + And I press "Add Fast fact card" + + Then I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_title][0][value]']" element + And I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_title][0][value]'].required" element + And I should not see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_title][0][value]'][disabled]" element + + And I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_icon][media_library_selection]']" element + + And I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_summary][0][value]']" element + And I should not see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_summary][0][value]'].required" element + And I should not see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_summary][0][value]'][disabled]" element + + And I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_link][0][uri]']" element + And I should not see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_link][0][uri]'].required" element + And I should not see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_link][0][uri]'][disabled]" element + + And I should see an "[name='field_c_n_components[0][subform][field_c_p_list_items][0][subform][field_c_p_theme]']" element diff --git a/web/themes/contrib/civictheme/civictheme.info.yml b/web/themes/contrib/civictheme/civictheme.info.yml index f5cb843b84..ef148a1790 100644 --- a/web/themes/contrib/civictheme/civictheme.info.yml +++ b/web/themes/contrib/civictheme/civictheme.info.yml @@ -154,6 +154,7 @@ config_devel: - core.entity_form_display.paragraph.civictheme_event_card.default - core.entity_form_display.paragraph.civictheme_event_card_ref.default - core.entity_form_display.paragraph.civictheme_iframe.default + - core.entity_form_display.paragraph.civictheme_infographic_card.default - core.entity_form_display.paragraph.civictheme_manual_list.default - core.entity_form_display.paragraph.civictheme_map.default - core.entity_form_display.paragraph.civictheme_message.default @@ -216,6 +217,7 @@ config_devel: - core.entity_view_display.paragraph.civictheme_event_card.default - core.entity_view_display.paragraph.civictheme_event_card_ref.default - core.entity_view_display.paragraph.civictheme_iframe.default + - core.entity_view_display.paragraph.civictheme_infographic_card.default - core.entity_view_display.paragraph.civictheme_manual_list.default - core.entity_view_display.paragraph.civictheme_map.default - core.entity_view_display.paragraph.civictheme_message.default @@ -236,6 +238,7 @@ config_devel: - core.entity_view_display.paragraph.civictheme_subject_card.default - core.entity_view_display.paragraph.civictheme_subject_card_ref.default - core.entity_view_display.paragraph.civictheme_webform.default + - core.entity_view_mode.crop.token - core.entity_view_mode.media.component - core.entity_view_mode.media.embedded - core.entity_view_mode.node.civictheme_navigation_card @@ -243,6 +246,7 @@ config_devel: - core.entity_view_mode.node.civictheme_slider_slide - core.entity_view_mode.node.civictheme_snippet - core.entity_view_mode.node.civictheme_subject_card + - core.entity_view_mode.search_api_task.token - editor.editor.civictheme_rich_text - field.field.block_content.civictheme_banner.field_c_b_background_image - field.field.block_content.civictheme_banner.field_c_b_banner_blend_mode @@ -380,6 +384,11 @@ config_devel: - field.field.paragraph.civictheme_iframe.field_c_p_url - field.field.paragraph.civictheme_iframe.field_c_p_vertical_spacing - field.field.paragraph.civictheme_iframe.field_c_p_width + - field.field.paragraph.civictheme_infographic_card.field_c_p_icon + - field.field.paragraph.civictheme_infographic_card.field_c_p_link + - field.field.paragraph.civictheme_infographic_card.field_c_p_summary + - field.field.paragraph.civictheme_infographic_card.field_c_p_theme + - field.field.paragraph.civictheme_infographic_card.field_c_p_title - field.field.paragraph.civictheme_manual_list.field_c_p_background - field.field.paragraph.civictheme_manual_list.field_c_p_content - field.field.paragraph.civictheme_manual_list.field_c_p_list_column_count @@ -604,6 +613,7 @@ config_devel: - paragraphs.paragraphs_type.civictheme_event_card - paragraphs.paragraphs_type.civictheme_event_card_ref - paragraphs.paragraphs_type.civictheme_iframe + - paragraphs.paragraphs_type.civictheme_infographic_card - paragraphs.paragraphs_type.civictheme_manual_list - paragraphs.paragraphs_type.civictheme_map - paragraphs.paragraphs_type.civictheme_message @@ -642,6 +652,7 @@ config_devel: - views.view.civictheme_moderated_content - webform.webform.civictheme_enquiry - webform.webform.civictheme_feedback + - webform.webform.civictheme_test_webform_fields - workflows.workflow.civictheme_editorial optional: - block.block.civictheme_banner diff --git a/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml new file mode 100644 index 0000000000..d27f244e34 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml @@ -0,0 +1,60 @@ +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.civictheme_infographic_card.field_c_p_icon + - field.field.paragraph.civictheme_infographic_card.field_c_p_link + - field.field.paragraph.civictheme_infographic_card.field_c_p_summary + - field.field.paragraph.civictheme_infographic_card.field_c_p_theme + - field.field.paragraph.civictheme_infographic_card.field_c_p_title + - paragraphs.paragraphs_type.civictheme_infographic_card + module: + - link +id: paragraph.civictheme_infographic_card.default +targetEntityType: paragraph +bundle: civictheme_infographic_card +mode: default +content: + field_c_p_icon: + type: entity_reference_autocomplete + weight: 2 + region: content + settings: + match_operator: CONTAINS + match_limit: 10 + size: 60 + placeholder: '' + third_party_settings: { } + field_c_p_link: + type: link_default + weight: 4 + region: content + settings: + placeholder_url: '' + placeholder_title: '' + third_party_settings: { } + field_c_p_summary: + type: string_textarea + weight: 3 + region: content + settings: + rows: 5 + placeholder: '' + third_party_settings: { } + field_c_p_theme: + type: options_select + weight: 5 + region: content + settings: { } + third_party_settings: { } + field_c_p_title: + type: string_textfield + weight: 1 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } +hidden: + created: true + status: true diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml new file mode 100644 index 0000000000..86bd88b123 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml @@ -0,0 +1,61 @@ +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.civictheme_infographic_card.field_c_p_icon + - field.field.paragraph.civictheme_infographic_card.field_c_p_link + - field.field.paragraph.civictheme_infographic_card.field_c_p_summary + - field.field.paragraph.civictheme_infographic_card.field_c_p_theme + - field.field.paragraph.civictheme_infographic_card.field_c_p_title + - paragraphs.paragraphs_type.civictheme_infographic_card + module: + - link + - options +id: paragraph.civictheme_infographic_card.default +targetEntityType: paragraph +bundle: civictheme_infographic_card +mode: default +content: + field_c_p_icon: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 2 + region: content + field_c_p_link: + type: link + label: above + settings: + trim_length: 80 + url_only: false + url_plain: false + rel: '' + target: '' + third_party_settings: { } + weight: 4 + region: content + field_c_p_summary: + type: basic_string + label: above + settings: { } + third_party_settings: { } + weight: 3 + region: content + field_c_p_theme: + type: list_default + label: above + settings: { } + third_party_settings: { } + weight: 5 + region: content + field_c_p_title: + type: string + label: above + settings: + link_to_entity: false + third_party_settings: { } + weight: 1 + region: content +hidden: { } diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml new file mode 100644 index 0000000000..ccd3697d50 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml @@ -0,0 +1,28 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_c_p_icon + - media.type.civictheme_icon + - paragraphs.paragraphs_type.civictheme_infographic_card +id: paragraph.civictheme_infographic_card.field_c_p_icon +field_name: field_c_p_icon +entity_type: paragraph +bundle: civictheme_infographic_card +label: Icon +description: '' +required: true +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:media' + handler_settings: + target_bundles: + civictheme_icon: civictheme_icon + sort: + field: _none + direction: ASC + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml new file mode 100644 index 0000000000..597e8a1c96 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_c_p_link + - paragraphs.paragraphs_type.civictheme_infographic_card + module: + - link +id: paragraph.civictheme_infographic_card.field_c_p_link +field_name: field_c_p_link +entity_type: paragraph +bundle: civictheme_infographic_card +label: Link +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + title: 0 + link_type: 17 +field_type: link diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml new file mode 100644 index 0000000000..98a7de9899 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_c_p_summary + - paragraphs.paragraphs_type.civictheme_infographic_card +id: paragraph.civictheme_infographic_card.field_c_p_summary +field_name: field_c_p_summary +entity_type: paragraph +bundle: civictheme_infographic_card +label: Summary +description: 'Limited to the number of characters configured in the theme settings. Any characters past the character limit will not show for users.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string_long diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml new file mode 100644 index 0000000000..0e3bf349ec --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_c_p_theme + - paragraphs.paragraphs_type.civictheme_infographic_card + module: + - options +id: paragraph.civictheme_infographic_card.field_c_p_theme +field_name: field_c_p_theme +entity_type: paragraph +bundle: civictheme_infographic_card +label: Theme +description: '' +required: true +translatable: false +default_value: + - + value: light +default_value_callback: '' +settings: { } +field_type: list_string diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml new file mode 100644 index 0000000000..f7096b697a --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_c_p_title + - paragraphs.paragraphs_type.civictheme_infographic_card +id: paragraph.civictheme_infographic_card.field_c_p_title +field_name: field_c_p_title +entity_type: paragraph +bundle: civictheme_infographic_card +label: Title +description: '' +required: true +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml index c3621f7470..9e037c59f8 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml @@ -5,6 +5,7 @@ dependencies: - field.storage.paragraph.field_c_p_list_items - paragraphs.paragraphs_type.civictheme_event_card - paragraphs.paragraphs_type.civictheme_event_card_ref + - paragraphs.paragraphs_type.civictheme_infographic_card - paragraphs.paragraphs_type.civictheme_manual_list - paragraphs.paragraphs_type.civictheme_navigation_card - paragraphs.paragraphs_type.civictheme_navigation_card_ref @@ -34,6 +35,7 @@ settings: target_bundles: civictheme_event_card: civictheme_event_card civictheme_event_card_ref: civictheme_event_card_ref + civictheme_infographic_card: civictheme_infographic_card civictheme_navigation_card: civictheme_navigation_card civictheme_navigation_card_ref: civictheme_navigation_card_ref civictheme_promo_card: civictheme_promo_card @@ -47,90 +49,96 @@ settings: negate: 0 target_bundles_drag_drop: civictheme_accordion: - weight: -61 + weight: -63 enabled: false civictheme_accordion_panel: - weight: -60 + weight: -62 enabled: false civictheme_attachment: - weight: -59 + weight: -61 enabled: false civictheme_automated_list: - weight: -58 + weight: -60 enabled: false civictheme_callout: - weight: -57 + weight: -59 enabled: false civictheme_campaign: - weight: -56 + weight: -58 enabled: false civictheme_content: - weight: -55 + weight: -57 enabled: false civictheme_event_card: - weight: -54 + weight: -56 enabled: true civictheme_event_card_ref: - weight: -53 + weight: -55 enabled: true civictheme_iframe: - weight: -52 + weight: -53 enabled: false + civictheme_infographic_card: + weight: -54 + enabled: true civictheme_manual_list: - weight: -51 + weight: -52 enabled: false civictheme_map: - weight: -50 + weight: -51 + enabled: false + civictheme_message: + weight: -33 enabled: false civictheme_navigation_card: - weight: -49 + weight: -50 enabled: true civictheme_navigation_card_ref: - weight: -48 + weight: -49 enabled: true civictheme_next_step: - weight: -47 + weight: -48 enabled: false civictheme_promo: - weight: -46 + weight: -47 enabled: false civictheme_promo_card: - weight: -45 + weight: -46 enabled: true civictheme_promo_card_ref: - weight: -44 + weight: -45 enabled: true civictheme_publication_card: - weight: -43 + weight: -44 enabled: true civictheme_service_card: - weight: -41 + weight: -43 enabled: true civictheme_slider: - weight: -40 + weight: -42 enabled: false civictheme_slider_slide: - weight: -39 + weight: -41 enabled: false civictheme_slider_slide_ref: - weight: -38 + weight: -40 enabled: false civictheme_snippet: - weight: -37 + weight: -39 enabled: true civictheme_snippet_ref: - weight: -36 + weight: -38 enabled: true civictheme_social_icon: - weight: -35 + weight: -37 enabled: false civictheme_subject_card: - weight: -34 + weight: -36 enabled: true civictheme_subject_card_ref: - weight: -33 + weight: -35 enabled: true civictheme_webform: - weight: -32 + weight: -34 enabled: false field_type: entity_reference_revisions diff --git a/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml b/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml new file mode 100644 index 0000000000..00dd0201cf --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: { } +id: civictheme_infographic_card +label: 'Fast fact card' +icon_uuid: null +icon_default: null +description: '' +behavior_plugins: { } diff --git a/web/themes/contrib/civictheme/includes/cards.inc b/web/themes/contrib/civictheme/includes/cards.inc index e48608b13b..bf2192ff98 100644 --- a/web/themes/contrib/civictheme/includes/cards.inc +++ b/web/themes/contrib/civictheme/includes/cards.inc @@ -201,3 +201,17 @@ function civictheme_preprocess_paragraph__civictheme_service_card(array &$variab _civictheme_preprocess_paragraph__paragraph_field__links($variables); _civictheme_preprocess_paragraph__paragraph_field__theme($variables); } + +/** + * Implements template_preprocess_paragraph(). + */ +function civictheme_preprocess_paragraph__civictheme_infographic_card(array &$variables): void { + _civictheme_preprocess_paragraph__paragraph_field__theme($variables); + _civictheme_preprocess_paragraph__paragraph_field__title($variables); + _civictheme_preprocess_paragraph__paragraph_field__summary($variables); + _civictheme_preprocess_paragraph__paragraph_field__link($variables); + $media = civictheme_get_field_value($variables['paragraph'], 'field_c_p_icon', TRUE); + if ($media) { + $variables['image'] = civictheme_media_image_get_variables($media); + } +} From 006540b231b2bd7c995771bf01c5b3b464f9a8c8 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 25 Jul 2025 12:49:13 +0530 Subject: [PATCH 02/14] Added config missign files. --- .../core.entity_view_mode.crop.token.yml | 10 + ...entity_view_mode.search_api_task.token.yml | 10 + ...webform.civictheme_test_webform_fields.yml | 383 ++++++++++++++++++ 3 files changed, 403 insertions(+) create mode 100644 web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml create mode 100644 web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml create mode 100644 web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml new file mode 100644 index 0000000000..39479a1067 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml @@ -0,0 +1,10 @@ +langcode: en +status: true +dependencies: + module: + - crop +id: crop.token +label: Token +description: null +targetEntityType: crop +cache: true diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml new file mode 100644 index 0000000000..588b000079 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml @@ -0,0 +1,10 @@ +langcode: en +status: true +dependencies: + module: + - search_api +id: search_api_task.token +label: Token +description: null +targetEntityType: search_api_task +cache: true diff --git a/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml b/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml new file mode 100644 index 0000000000..4ca9bc63e7 --- /dev/null +++ b/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml @@ -0,0 +1,383 @@ +langcode: en +status: open +dependencies: { } +open: null +close: null +weight: 0 +uid: 1 +template: false +archive: false +id: civictheme_test_webform_fields +title: 'Civictheme Test Webform - Fields' +description: '

This form will be used to test the available webform fields, including conditional form elements.

' +categories: { } +elements: |- + basic_elements_container: + '#type': container + checkbox: + '#type': checkbox + '#title': Checkbox + hidden: + '#type': hidden + '#title': Hidden + text_field: + '#type': textfield + '#title': 'Text field' + conditional_container: + '#type': container + select_to_display_textarea: + '#type': radios + '#title': 'Select to display textarea' + '#options': + 'Display textarea': 'Display textarea' + 'Do not display textarea': 'Do not display textarea' + textarea: + '#type': textarea + '#title': Textarea + '#states': + visible: + ':input[name="checkbox_visible_text_field_1"]': + checked: true + checkbox_visible_text_field_1: + '#type': checkbox + '#title': 'Check to display textfield' + text_field_1: + '#type': textfield + '#title': 'Text field 1' + '#states': + visible: + ':input[name="checkbox_visible_text_field_1"]': + checked: true + advanced_elements_container: + '#type': container + autocomplete: + '#type': webform_autocomplete + '#title': Autocomplete + '#autocomplete_items': gender + color: + '#type': color + '#title': Color + email: + '#type': email + '#title': Email + email_confirm: + '#type': webform_email_confirm + '#title': 'Email confirm' + '#confirm__title': 'Email confirm title - Test' + '#confirm__description': '

Email confirm description - test

' + '#confirm__placeholder': 'Email confirm placeholder- Test' + email_multiple: + '#type': webform_email_multiple + '#title': 'Email multiple' + number: + '#type': number + '#title': Number + number_max_10_min_4: + '#type': number + '#title': 'Number - Max 10 - Min 4' + '#min': 4 + '#max': 10 + range: + '#type': range + '#title': Range + range_min_10_max_100_steps_10: + '#type': range + '#title': 'Range Min 10 Max 100 Steps 10' + '#min': 10 + '#step': 10 + rating: + '#type': webform_rating + '#title': Rating + telephone: + '#type': tel + '#title': Telephone + terms_of_service: + '#type': webform_terms_of_service + '#terms_title': 'Terms of service' + '#terms_content': '

Terms of service test content

' + url: + '#type': url + '#title': URL + composite_elements_container: + '#type': container + address: + '#type': webform_address + '#title': Address + contact: + '#type': webform_contact + '#title': Contact + link: + '#type': webform_link + '#title': Link + name: + '#type': webform_name + '#title': Name + telephone_advanced: + '#type': webform_telephone + '#title': 'Telephone advanced' + markup_container: + '#type': container + advanced_html_text: + '#type': processed_text + '#text': "

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

" + '#format': civictheme_rich_text + label: + '#type': label + '#title': Label + more: + '#type': webform_more + file_uploads_container: + '#type': container + audio_file: + '#type': webform_audio_file + '#title': 'Audio file' + document_file: + '#type': webform_document_file + '#title': 'Document file' + file: + '#type': managed_file + '#title': File + image_file: + '#type': webform_image_file + '#title': 'Image file' + video_file: + '#type': webform_video_file + '#title': 'Video file' + options_element_container: + '#type': container + checkboxes: + '#type': checkboxes + '#title': Checkboxes + '#options': + 'Test Option 1': 'Test Option 1' + 'Test Option 2': 'Test Option 2' + 'Test Option 3': 'Test Option 3' + '#options_randomize': true + '#options_all': true + '#options_none': true + checkboxes_other: + '#type': webform_checkboxes_other + '#title': 'Checkboxes other' + '#options': education + '#options_randomize': true + radios: + '#type': radios + '#title': Radios + '#options': marital_status + radios_other: + '#type': webform_radios_other + '#title': 'Radios other' + '#options': phone_types + select: + '#type': select + '#title': Select + '#options': country_names + select_other: + '#type': webform_select_other + '#title': 'Select other' + '#options': ethnicity + datetime_elements_container: + '#type': container + date: + '#type': date + '#title': Date + date_time: + '#type': datetime + '#title': Date/time + entity_reference_container: + '#type': container + entity_autocomplete: + '#type': entity_autocomplete + '#title': 'Entity autocomplete' + '#target_type': node + '#selection_handler': 'default:node' + '#selection_settings': + target_bundles: + civictheme_alert: civictheme_alert + civictheme_event: civictheme_event + civictheme_page: civictheme_page +css: '' +javascript: '' +settings: + ajax: false + ajax_scroll_top: form + ajax_progress_type: '' + ajax_effect: '' + ajax_speed: null + page: true + page_submit_path: '' + page_confirm_path: '' + page_theme_name: '' + form_title: both + form_submit_once: false + form_open_message: '' + form_close_message: '' + form_exception_message: '' + form_previous_submissions: true + form_confidential: false + form_confidential_message: '' + form_disable_remote_addr: false + form_convert_anonymous: false + form_prepopulate: false + form_prepopulate_source_entity: false + form_prepopulate_source_entity_required: false + form_prepopulate_source_entity_type: '' + form_unsaved: false + form_disable_back: false + form_submit_back: false + form_disable_autocomplete: false + form_novalidate: true + form_disable_inline_errors: false + form_required: false + form_autofocus: false + form_details_toggle: false + form_reset: false + form_access_denied: default + form_access_denied_title: '' + form_access_denied_message: '' + form_access_denied_attributes: { } + form_file_limit: '' + form_attributes: { } + form_method: '' + form_action: '' + share: false + share_node: false + share_theme_name: '' + share_title: true + share_page_body_attributes: { } + submission_label: '' + submission_exception_message: '' + submission_locked_message: '' + submission_log: false + submission_excluded_elements: { } + submission_exclude_empty: false + submission_exclude_empty_checkbox: false + submission_views: { } + submission_views_replace: { } + submission_user_columns: { } + submission_user_duplicate: false + submission_access_denied: default + submission_access_denied_title: '' + submission_access_denied_message: '' + submission_access_denied_attributes: { } + previous_submission_message: '' + previous_submissions_message: '' + autofill: false + autofill_message: '' + autofill_excluded_elements: { } + wizard_progress_bar: true + wizard_progress_pages: false + wizard_progress_percentage: false + wizard_progress_link: false + wizard_progress_states: false + wizard_start_label: '' + wizard_preview_link: false + wizard_confirmation: true + wizard_confirmation_label: '' + wizard_auto_forward: true + wizard_auto_forward_hide_next_button: false + wizard_keyboard: true + wizard_track: '' + wizard_prev_button_label: '' + wizard_next_button_label: '' + wizard_toggle: false + wizard_toggle_show_label: '' + wizard_toggle_hide_label: '' + wizard_page_type: container + wizard_page_title_tag: h2 + preview: 0 + preview_label: '' + preview_title: '' + preview_message: '' + preview_attributes: { } + preview_excluded_elements: { } + preview_exclude_empty: true + preview_exclude_empty_checkbox: false + draft: none + draft_multiple: false + draft_auto_save: false + draft_saved_message: '' + draft_loaded_message: '' + draft_pending_single_message: '' + draft_pending_multiple_message: '' + confirmation_type: page + confirmation_url: '' + confirmation_title: '' + confirmation_message: '' + confirmation_attributes: { } + confirmation_back: true + confirmation_back_label: '' + confirmation_back_attributes: { } + confirmation_exclude_query: false + confirmation_exclude_token: false + confirmation_update: false + limit_total: null + limit_total_interval: null + limit_total_message: '' + limit_total_unique: false + limit_user: null + limit_user_interval: null + limit_user_message: '' + limit_user_unique: false + entity_limit_total: null + entity_limit_total_interval: null + entity_limit_user: null + entity_limit_user_interval: null + purge: none + purge_days: null + results_disabled: false + results_disabled_ignore: false + results_customize: false + token_view: false + token_update: false + token_delete: false + serial_disabled: false +access: + create: + roles: + - anonymous + - authenticated + users: { } + permissions: { } + view_any: + roles: { } + users: { } + permissions: { } + update_any: + roles: { } + users: { } + permissions: { } + delete_any: + roles: { } + users: { } + permissions: { } + purge_any: + roles: { } + users: { } + permissions: { } + view_own: + roles: { } + users: { } + permissions: { } + update_own: + roles: { } + users: { } + permissions: { } + delete_own: + roles: { } + users: { } + permissions: { } + administer: + roles: { } + users: { } + permissions: { } + test: + roles: { } + users: { } + permissions: { } + configuration: + roles: { } + users: { } + permissions: { } +handlers: { } +variants: { } From c9996b74e2ea8b06093f8c2d9790c208e0eff9ff Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 25 Jul 2025 13:28:14 +0530 Subject: [PATCH 03/14] Fixed config related issue. --- .../contrib/civictheme/civictheme.info.yml | 3 - .../core.entity_view_mode.crop.token.yml | 10 - ...entity_view_mode.search_api_task.token.yml | 10 - ...webform.civictheme_test_webform_fields.yml | 383 ------------------ 4 files changed, 406 deletions(-) delete mode 100644 web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml delete mode 100644 web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml delete mode 100644 web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml diff --git a/web/themes/contrib/civictheme/civictheme.info.yml b/web/themes/contrib/civictheme/civictheme.info.yml index ef148a1790..ee57a1a286 100644 --- a/web/themes/contrib/civictheme/civictheme.info.yml +++ b/web/themes/contrib/civictheme/civictheme.info.yml @@ -238,7 +238,6 @@ config_devel: - core.entity_view_display.paragraph.civictheme_subject_card.default - core.entity_view_display.paragraph.civictheme_subject_card_ref.default - core.entity_view_display.paragraph.civictheme_webform.default - - core.entity_view_mode.crop.token - core.entity_view_mode.media.component - core.entity_view_mode.media.embedded - core.entity_view_mode.node.civictheme_navigation_card @@ -246,7 +245,6 @@ config_devel: - core.entity_view_mode.node.civictheme_slider_slide - core.entity_view_mode.node.civictheme_snippet - core.entity_view_mode.node.civictheme_subject_card - - core.entity_view_mode.search_api_task.token - editor.editor.civictheme_rich_text - field.field.block_content.civictheme_banner.field_c_b_background_image - field.field.block_content.civictheme_banner.field_c_b_banner_blend_mode @@ -652,7 +650,6 @@ config_devel: - views.view.civictheme_moderated_content - webform.webform.civictheme_enquiry - webform.webform.civictheme_feedback - - webform.webform.civictheme_test_webform_fields - workflows.workflow.civictheme_editorial optional: - block.block.civictheme_banner diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml deleted file mode 100644 index 39479a1067..0000000000 --- a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.crop.token.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - crop -id: crop.token -label: Token -description: null -targetEntityType: crop -cache: true diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml deleted file mode 100644 index 588b000079..0000000000 --- a/web/themes/contrib/civictheme/config/install/core.entity_view_mode.search_api_task.token.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - search_api -id: search_api_task.token -label: Token -description: null -targetEntityType: search_api_task -cache: true diff --git a/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml b/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml deleted file mode 100644 index 4ca9bc63e7..0000000000 --- a/web/themes/contrib/civictheme/config/install/webform.webform.civictheme_test_webform_fields.yml +++ /dev/null @@ -1,383 +0,0 @@ -langcode: en -status: open -dependencies: { } -open: null -close: null -weight: 0 -uid: 1 -template: false -archive: false -id: civictheme_test_webform_fields -title: 'Civictheme Test Webform - Fields' -description: '

This form will be used to test the available webform fields, including conditional form elements.

' -categories: { } -elements: |- - basic_elements_container: - '#type': container - checkbox: - '#type': checkbox - '#title': Checkbox - hidden: - '#type': hidden - '#title': Hidden - text_field: - '#type': textfield - '#title': 'Text field' - conditional_container: - '#type': container - select_to_display_textarea: - '#type': radios - '#title': 'Select to display textarea' - '#options': - 'Display textarea': 'Display textarea' - 'Do not display textarea': 'Do not display textarea' - textarea: - '#type': textarea - '#title': Textarea - '#states': - visible: - ':input[name="checkbox_visible_text_field_1"]': - checked: true - checkbox_visible_text_field_1: - '#type': checkbox - '#title': 'Check to display textfield' - text_field_1: - '#type': textfield - '#title': 'Text field 1' - '#states': - visible: - ':input[name="checkbox_visible_text_field_1"]': - checked: true - advanced_elements_container: - '#type': container - autocomplete: - '#type': webform_autocomplete - '#title': Autocomplete - '#autocomplete_items': gender - color: - '#type': color - '#title': Color - email: - '#type': email - '#title': Email - email_confirm: - '#type': webform_email_confirm - '#title': 'Email confirm' - '#confirm__title': 'Email confirm title - Test' - '#confirm__description': '

Email confirm description - test

' - '#confirm__placeholder': 'Email confirm placeholder- Test' - email_multiple: - '#type': webform_email_multiple - '#title': 'Email multiple' - number: - '#type': number - '#title': Number - number_max_10_min_4: - '#type': number - '#title': 'Number - Max 10 - Min 4' - '#min': 4 - '#max': 10 - range: - '#type': range - '#title': Range - range_min_10_max_100_steps_10: - '#type': range - '#title': 'Range Min 10 Max 100 Steps 10' - '#min': 10 - '#step': 10 - rating: - '#type': webform_rating - '#title': Rating - telephone: - '#type': tel - '#title': Telephone - terms_of_service: - '#type': webform_terms_of_service - '#terms_title': 'Terms of service' - '#terms_content': '

Terms of service test content

' - url: - '#type': url - '#title': URL - composite_elements_container: - '#type': container - address: - '#type': webform_address - '#title': Address - contact: - '#type': webform_contact - '#title': Contact - link: - '#type': webform_link - '#title': Link - name: - '#type': webform_name - '#title': Name - telephone_advanced: - '#type': webform_telephone - '#title': 'Telephone advanced' - markup_container: - '#type': container - advanced_html_text: - '#type': processed_text - '#text': "

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

" - '#format': civictheme_rich_text - label: - '#type': label - '#title': Label - more: - '#type': webform_more - file_uploads_container: - '#type': container - audio_file: - '#type': webform_audio_file - '#title': 'Audio file' - document_file: - '#type': webform_document_file - '#title': 'Document file' - file: - '#type': managed_file - '#title': File - image_file: - '#type': webform_image_file - '#title': 'Image file' - video_file: - '#type': webform_video_file - '#title': 'Video file' - options_element_container: - '#type': container - checkboxes: - '#type': checkboxes - '#title': Checkboxes - '#options': - 'Test Option 1': 'Test Option 1' - 'Test Option 2': 'Test Option 2' - 'Test Option 3': 'Test Option 3' - '#options_randomize': true - '#options_all': true - '#options_none': true - checkboxes_other: - '#type': webform_checkboxes_other - '#title': 'Checkboxes other' - '#options': education - '#options_randomize': true - radios: - '#type': radios - '#title': Radios - '#options': marital_status - radios_other: - '#type': webform_radios_other - '#title': 'Radios other' - '#options': phone_types - select: - '#type': select - '#title': Select - '#options': country_names - select_other: - '#type': webform_select_other - '#title': 'Select other' - '#options': ethnicity - datetime_elements_container: - '#type': container - date: - '#type': date - '#title': Date - date_time: - '#type': datetime - '#title': Date/time - entity_reference_container: - '#type': container - entity_autocomplete: - '#type': entity_autocomplete - '#title': 'Entity autocomplete' - '#target_type': node - '#selection_handler': 'default:node' - '#selection_settings': - target_bundles: - civictheme_alert: civictheme_alert - civictheme_event: civictheme_event - civictheme_page: civictheme_page -css: '' -javascript: '' -settings: - ajax: false - ajax_scroll_top: form - ajax_progress_type: '' - ajax_effect: '' - ajax_speed: null - page: true - page_submit_path: '' - page_confirm_path: '' - page_theme_name: '' - form_title: both - form_submit_once: false - form_open_message: '' - form_close_message: '' - form_exception_message: '' - form_previous_submissions: true - form_confidential: false - form_confidential_message: '' - form_disable_remote_addr: false - form_convert_anonymous: false - form_prepopulate: false - form_prepopulate_source_entity: false - form_prepopulate_source_entity_required: false - form_prepopulate_source_entity_type: '' - form_unsaved: false - form_disable_back: false - form_submit_back: false - form_disable_autocomplete: false - form_novalidate: true - form_disable_inline_errors: false - form_required: false - form_autofocus: false - form_details_toggle: false - form_reset: false - form_access_denied: default - form_access_denied_title: '' - form_access_denied_message: '' - form_access_denied_attributes: { } - form_file_limit: '' - form_attributes: { } - form_method: '' - form_action: '' - share: false - share_node: false - share_theme_name: '' - share_title: true - share_page_body_attributes: { } - submission_label: '' - submission_exception_message: '' - submission_locked_message: '' - submission_log: false - submission_excluded_elements: { } - submission_exclude_empty: false - submission_exclude_empty_checkbox: false - submission_views: { } - submission_views_replace: { } - submission_user_columns: { } - submission_user_duplicate: false - submission_access_denied: default - submission_access_denied_title: '' - submission_access_denied_message: '' - submission_access_denied_attributes: { } - previous_submission_message: '' - previous_submissions_message: '' - autofill: false - autofill_message: '' - autofill_excluded_elements: { } - wizard_progress_bar: true - wizard_progress_pages: false - wizard_progress_percentage: false - wizard_progress_link: false - wizard_progress_states: false - wizard_start_label: '' - wizard_preview_link: false - wizard_confirmation: true - wizard_confirmation_label: '' - wizard_auto_forward: true - wizard_auto_forward_hide_next_button: false - wizard_keyboard: true - wizard_track: '' - wizard_prev_button_label: '' - wizard_next_button_label: '' - wizard_toggle: false - wizard_toggle_show_label: '' - wizard_toggle_hide_label: '' - wizard_page_type: container - wizard_page_title_tag: h2 - preview: 0 - preview_label: '' - preview_title: '' - preview_message: '' - preview_attributes: { } - preview_excluded_elements: { } - preview_exclude_empty: true - preview_exclude_empty_checkbox: false - draft: none - draft_multiple: false - draft_auto_save: false - draft_saved_message: '' - draft_loaded_message: '' - draft_pending_single_message: '' - draft_pending_multiple_message: '' - confirmation_type: page - confirmation_url: '' - confirmation_title: '' - confirmation_message: '' - confirmation_attributes: { } - confirmation_back: true - confirmation_back_label: '' - confirmation_back_attributes: { } - confirmation_exclude_query: false - confirmation_exclude_token: false - confirmation_update: false - limit_total: null - limit_total_interval: null - limit_total_message: '' - limit_total_unique: false - limit_user: null - limit_user_interval: null - limit_user_message: '' - limit_user_unique: false - entity_limit_total: null - entity_limit_total_interval: null - entity_limit_user: null - entity_limit_user_interval: null - purge: none - purge_days: null - results_disabled: false - results_disabled_ignore: false - results_customize: false - token_view: false - token_update: false - token_delete: false - serial_disabled: false -access: - create: - roles: - - anonymous - - authenticated - users: { } - permissions: { } - view_any: - roles: { } - users: { } - permissions: { } - update_any: - roles: { } - users: { } - permissions: { } - delete_any: - roles: { } - users: { } - permissions: { } - purge_any: - roles: { } - users: { } - permissions: { } - view_own: - roles: { } - users: { } - permissions: { } - update_own: - roles: { } - users: { } - permissions: { } - delete_own: - roles: { } - users: { } - permissions: { } - administer: - roles: { } - users: { } - permissions: { } - test: - roles: { } - users: { } - permissions: { } - configuration: - roles: { } - users: { } - permissions: { } -handlers: { } -variants: { } From bb9b36493dfae10cd629e98b535fe5617c750484 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 25 Jul 2025 14:09:51 +0530 Subject: [PATCH 04/14] [GOVCMSCT2-121] Fixed behat test. --- ...play.paragraph.civictheme_infographic_card.default.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml index d27f244e34..91dce302b5 100644 --- a/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml +++ b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml @@ -10,20 +10,18 @@ dependencies: - paragraphs.paragraphs_type.civictheme_infographic_card module: - link + - media_library id: paragraph.civictheme_infographic_card.default targetEntityType: paragraph bundle: civictheme_infographic_card mode: default content: field_c_p_icon: - type: entity_reference_autocomplete + type: media_library_widget weight: 2 region: content settings: - match_operator: CONTAINS - match_limit: 10 - size: 60 - placeholder: '' + media_types: { } third_party_settings: { } field_c_p_link: type: link_default From cf7d57f453b82e488c13fe4ebc3fd95b961e5473 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Wed, 30 Jul 2025 17:15:38 +0530 Subject: [PATCH 05/14] [GOVCMSCT2-121] Updated machine name to civictheme_fast_fact_card. --- ...aph.civictheme_fast_fact_card.fields.feature} | 2 +- .../contrib/civictheme/civictheme.info.yml | 16 ++++++++-------- ...agraph.civictheme_fast_fact_card.default.yml} | 16 ++++++++-------- ...agraph.civictheme_fast_fact_card.default.yml} | 16 ++++++++-------- ...civictheme_fast_fact_card.field_c_p_icon.yml} | 6 +++--- ...civictheme_fast_fact_card.field_c_p_link.yml} | 6 +++--- ...ictheme_fast_fact_card.field_c_p_summary.yml} | 6 +++--- ...ivictheme_fast_fact_card.field_c_p_theme.yml} | 6 +++--- ...ivictheme_fast_fact_card.field_c_p_title.yml} | 6 +++--- ...victheme_manual_list.field_c_p_list_items.yml | 6 +++--- ...aragraphs_type.civictheme_fast_fact_card.yml} | 2 +- web/themes/contrib/civictheme/includes/cards.inc | 2 +- 12 files changed, 45 insertions(+), 45 deletions(-) rename tests/behat/features/{paragraph.civictheme_infographic_card.fields.feature => paragraph.civictheme_fast_fact_card.fields.feature} (96%) rename web/themes/contrib/civictheme/config/install/{core.entity_form_display.paragraph.civictheme_infographic_card.default.yml => core.entity_form_display.paragraph.civictheme_fast_fact_card.default.yml} (65%) rename web/themes/contrib/civictheme/config/install/{core.entity_view_display.paragraph.civictheme_infographic_card.default.yml => core.entity_view_display.paragraph.civictheme_fast_fact_card.default.yml} (66%) rename web/themes/contrib/civictheme/config/install/{field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml => field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon.yml} (77%) rename web/themes/contrib/civictheme/config/install/{field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml => field.field.paragraph.civictheme_fast_fact_card.field_c_p_link.yml} (68%) rename web/themes/contrib/civictheme/config/install/{field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml => field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary.yml} (73%) rename web/themes/contrib/civictheme/config/install/{field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml => field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme.yml} (68%) rename web/themes/contrib/civictheme/config/install/{field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml => field.field.paragraph.civictheme_fast_fact_card.field_c_p_title.yml} (65%) rename web/themes/contrib/civictheme/config/install/{paragraphs.paragraphs_type.civictheme_infographic_card.yml => paragraphs.paragraphs_type.civictheme_fast_fact_card.yml} (81%) diff --git a/tests/behat/features/paragraph.civictheme_infographic_card.fields.feature b/tests/behat/features/paragraph.civictheme_fast_fact_card.fields.feature similarity index 96% rename from tests/behat/features/paragraph.civictheme_infographic_card.fields.feature rename to tests/behat/features/paragraph.civictheme_fast_fact_card.fields.feature index b3bb7f680c..d00ffdc340 100644 --- a/tests/behat/features/paragraph.civictheme_infographic_card.fields.feature +++ b/tests/behat/features/paragraph.civictheme_fast_fact_card.fields.feature @@ -1,4 +1,4 @@ -@p1 @civictheme @civictheme_card @civictheme_infographic_card +@p1 @civictheme @civictheme_card @civictheme_fast_fact_card Feature: Fast fact card fields @api diff --git a/web/themes/contrib/civictheme/civictheme.info.yml b/web/themes/contrib/civictheme/civictheme.info.yml index ee57a1a286..16ddb1a66d 100644 --- a/web/themes/contrib/civictheme/civictheme.info.yml +++ b/web/themes/contrib/civictheme/civictheme.info.yml @@ -154,7 +154,7 @@ config_devel: - core.entity_form_display.paragraph.civictheme_event_card.default - core.entity_form_display.paragraph.civictheme_event_card_ref.default - core.entity_form_display.paragraph.civictheme_iframe.default - - core.entity_form_display.paragraph.civictheme_infographic_card.default + - core.entity_form_display.paragraph.civictheme_fast_fact_card.default - core.entity_form_display.paragraph.civictheme_manual_list.default - core.entity_form_display.paragraph.civictheme_map.default - core.entity_form_display.paragraph.civictheme_message.default @@ -217,7 +217,7 @@ config_devel: - core.entity_view_display.paragraph.civictheme_event_card.default - core.entity_view_display.paragraph.civictheme_event_card_ref.default - core.entity_view_display.paragraph.civictheme_iframe.default - - core.entity_view_display.paragraph.civictheme_infographic_card.default + - core.entity_view_display.paragraph.civictheme_fast_fact_card.default - core.entity_view_display.paragraph.civictheme_manual_list.default - core.entity_view_display.paragraph.civictheme_map.default - core.entity_view_display.paragraph.civictheme_message.default @@ -382,11 +382,11 @@ config_devel: - field.field.paragraph.civictheme_iframe.field_c_p_url - field.field.paragraph.civictheme_iframe.field_c_p_vertical_spacing - field.field.paragraph.civictheme_iframe.field_c_p_width - - field.field.paragraph.civictheme_infographic_card.field_c_p_icon - - field.field.paragraph.civictheme_infographic_card.field_c_p_link - - field.field.paragraph.civictheme_infographic_card.field_c_p_summary - - field.field.paragraph.civictheme_infographic_card.field_c_p_theme - - field.field.paragraph.civictheme_infographic_card.field_c_p_title + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_link + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_title - field.field.paragraph.civictheme_manual_list.field_c_p_background - field.field.paragraph.civictheme_manual_list.field_c_p_content - field.field.paragraph.civictheme_manual_list.field_c_p_list_column_count @@ -611,7 +611,7 @@ config_devel: - paragraphs.paragraphs_type.civictheme_event_card - paragraphs.paragraphs_type.civictheme_event_card_ref - paragraphs.paragraphs_type.civictheme_iframe - - paragraphs.paragraphs_type.civictheme_infographic_card + - paragraphs.paragraphs_type.civictheme_fast_fact_card - paragraphs.paragraphs_type.civictheme_manual_list - paragraphs.paragraphs_type.civictheme_map - paragraphs.paragraphs_type.civictheme_message diff --git a/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_fast_fact_card.default.yml similarity index 65% rename from web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml rename to web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_fast_fact_card.default.yml index 91dce302b5..04d1ebe988 100644 --- a/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_infographic_card.default.yml +++ b/web/themes/contrib/civictheme/config/install/core.entity_form_display.paragraph.civictheme_fast_fact_card.default.yml @@ -2,18 +2,18 @@ langcode: en status: true dependencies: config: - - field.field.paragraph.civictheme_infographic_card.field_c_p_icon - - field.field.paragraph.civictheme_infographic_card.field_c_p_link - - field.field.paragraph.civictheme_infographic_card.field_c_p_summary - - field.field.paragraph.civictheme_infographic_card.field_c_p_theme - - field.field.paragraph.civictheme_infographic_card.field_c_p_title - - paragraphs.paragraphs_type.civictheme_infographic_card + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_link + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_title + - paragraphs.paragraphs_type.civictheme_fast_fact_card module: - link - media_library -id: paragraph.civictheme_infographic_card.default +id: paragraph.civictheme_fast_fact_card.default targetEntityType: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card mode: default content: field_c_p_icon: diff --git a/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml b/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_fast_fact_card.default.yml similarity index 66% rename from web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml rename to web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_fast_fact_card.default.yml index 86bd88b123..f4ce3a5901 100644 --- a/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_infographic_card.default.yml +++ b/web/themes/contrib/civictheme/config/install/core.entity_view_display.paragraph.civictheme_fast_fact_card.default.yml @@ -2,18 +2,18 @@ langcode: en status: true dependencies: config: - - field.field.paragraph.civictheme_infographic_card.field_c_p_icon - - field.field.paragraph.civictheme_infographic_card.field_c_p_link - - field.field.paragraph.civictheme_infographic_card.field_c_p_summary - - field.field.paragraph.civictheme_infographic_card.field_c_p_theme - - field.field.paragraph.civictheme_infographic_card.field_c_p_title - - paragraphs.paragraphs_type.civictheme_infographic_card + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_link + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme + - field.field.paragraph.civictheme_fast_fact_card.field_c_p_title + - paragraphs.paragraphs_type.civictheme_fast_fact_card module: - link - options -id: paragraph.civictheme_infographic_card.default +id: paragraph.civictheme_fast_fact_card.default targetEntityType: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card mode: default content: field_c_p_icon: diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon.yml similarity index 77% rename from web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml rename to web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon.yml index ccd3697d50..974d96d506 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_icon.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon.yml @@ -4,11 +4,11 @@ dependencies: config: - field.storage.paragraph.field_c_p_icon - media.type.civictheme_icon - - paragraphs.paragraphs_type.civictheme_infographic_card -id: paragraph.civictheme_infographic_card.field_c_p_icon + - paragraphs.paragraphs_type.civictheme_fast_fact_card +id: paragraph.civictheme_fast_fact_card.field_c_p_icon field_name: field_c_p_icon entity_type: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card label: Icon description: '' required: true diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_link.yml similarity index 68% rename from web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml rename to web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_link.yml index 597e8a1c96..84e5ff1b67 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_link.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_link.yml @@ -3,13 +3,13 @@ status: true dependencies: config: - field.storage.paragraph.field_c_p_link - - paragraphs.paragraphs_type.civictheme_infographic_card + - paragraphs.paragraphs_type.civictheme_fast_fact_card module: - link -id: paragraph.civictheme_infographic_card.field_c_p_link +id: paragraph.civictheme_fast_fact_card.field_c_p_link field_name: field_c_p_link entity_type: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card label: Link description: '' required: false diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary.yml similarity index 73% rename from web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml rename to web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary.yml index 98a7de9899..72917240cc 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_summary.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary.yml @@ -3,11 +3,11 @@ status: true dependencies: config: - field.storage.paragraph.field_c_p_summary - - paragraphs.paragraphs_type.civictheme_infographic_card -id: paragraph.civictheme_infographic_card.field_c_p_summary + - paragraphs.paragraphs_type.civictheme_fast_fact_card +id: paragraph.civictheme_fast_fact_card.field_c_p_summary field_name: field_c_p_summary entity_type: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card label: Summary description: 'Limited to the number of characters configured in the theme settings. Any characters past the character limit will not show for users.' required: false diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme.yml similarity index 68% rename from web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml rename to web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme.yml index 0e3bf349ec..560640020c 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_theme.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme.yml @@ -3,13 +3,13 @@ status: true dependencies: config: - field.storage.paragraph.field_c_p_theme - - paragraphs.paragraphs_type.civictheme_infographic_card + - paragraphs.paragraphs_type.civictheme_fast_fact_card module: - options -id: paragraph.civictheme_infographic_card.field_c_p_theme +id: paragraph.civictheme_fast_fact_card.field_c_p_theme field_name: field_c_p_theme entity_type: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card label: Theme description: '' required: true diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_title.yml similarity index 65% rename from web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml rename to web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_title.yml index f7096b697a..da45272782 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_infographic_card.field_c_p_title.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_fast_fact_card.field_c_p_title.yml @@ -3,11 +3,11 @@ status: true dependencies: config: - field.storage.paragraph.field_c_p_title - - paragraphs.paragraphs_type.civictheme_infographic_card -id: paragraph.civictheme_infographic_card.field_c_p_title + - paragraphs.paragraphs_type.civictheme_fast_fact_card +id: paragraph.civictheme_fast_fact_card.field_c_p_title field_name: field_c_p_title entity_type: paragraph -bundle: civictheme_infographic_card +bundle: civictheme_fast_fact_card label: Title description: '' required: true diff --git a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml index 9e037c59f8..459b4bc385 100644 --- a/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml +++ b/web/themes/contrib/civictheme/config/install/field.field.paragraph.civictheme_manual_list.field_c_p_list_items.yml @@ -5,7 +5,7 @@ dependencies: - field.storage.paragraph.field_c_p_list_items - paragraphs.paragraphs_type.civictheme_event_card - paragraphs.paragraphs_type.civictheme_event_card_ref - - paragraphs.paragraphs_type.civictheme_infographic_card + - paragraphs.paragraphs_type.civictheme_fast_fact_card - paragraphs.paragraphs_type.civictheme_manual_list - paragraphs.paragraphs_type.civictheme_navigation_card - paragraphs.paragraphs_type.civictheme_navigation_card_ref @@ -35,7 +35,7 @@ settings: target_bundles: civictheme_event_card: civictheme_event_card civictheme_event_card_ref: civictheme_event_card_ref - civictheme_infographic_card: civictheme_infographic_card + civictheme_fast_fact_card: civictheme_fast_fact_card civictheme_navigation_card: civictheme_navigation_card civictheme_navigation_card_ref: civictheme_navigation_card_ref civictheme_promo_card: civictheme_promo_card @@ -78,7 +78,7 @@ settings: civictheme_iframe: weight: -53 enabled: false - civictheme_infographic_card: + civictheme_fast_fact_card: weight: -54 enabled: true civictheme_manual_list: diff --git a/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml b/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_fast_fact_card.yml similarity index 81% rename from web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml rename to web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_fast_fact_card.yml index 00dd0201cf..48dbf88d2b 100644 --- a/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_infographic_card.yml +++ b/web/themes/contrib/civictheme/config/install/paragraphs.paragraphs_type.civictheme_fast_fact_card.yml @@ -1,7 +1,7 @@ langcode: en status: true dependencies: { } -id: civictheme_infographic_card +id: civictheme_fast_fact_card label: 'Fast fact card' icon_uuid: null icon_default: null diff --git a/web/themes/contrib/civictheme/includes/cards.inc b/web/themes/contrib/civictheme/includes/cards.inc index bf2192ff98..9b1177d068 100644 --- a/web/themes/contrib/civictheme/includes/cards.inc +++ b/web/themes/contrib/civictheme/includes/cards.inc @@ -205,7 +205,7 @@ function civictheme_preprocess_paragraph__civictheme_service_card(array &$variab /** * Implements template_preprocess_paragraph(). */ -function civictheme_preprocess_paragraph__civictheme_infographic_card(array &$variables): void { +function civictheme_preprocess_paragraph__civictheme_fast_fact_card(array &$variables): void { _civictheme_preprocess_paragraph__paragraph_field__theme($variables); _civictheme_preprocess_paragraph__paragraph_field__title($variables); _civictheme_preprocess_paragraph__paragraph_field__summary($variables); From af9ecdc556255797d2f9212cad728aafce096196 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Wed, 30 Jul 2025 17:32:41 +0530 Subject: [PATCH 06/14] [GOVCMSCT2-121] Added post update hook for civictheme_fast_fact_card. --- .../civictheme/civictheme.post_update.php | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/web/themes/contrib/civictheme/civictheme.post_update.php b/web/themes/contrib/civictheme/civictheme.post_update.php index 2f342e12de..a167d8a4f1 100644 --- a/web/themes/contrib/civictheme/civictheme.post_update.php +++ b/web/themes/contrib/civictheme/civictheme.post_update.php @@ -864,3 +864,51 @@ function civictheme_post_update_update_editor_allowed_field(): string { } return (string) new TranslatableMarkup('Allowed tags setting not set, aborting update.'); } + +/** + * Add civictheme_fast_fact_card paragraph type and enable it for manual list. + */ +function civictheme_post_update_add_fast_fact_card_paragraph(array &$sandbox): ?string { + $new_configs = [ + // Paragraph type definition. + 'paragraphs.paragraphs_type.civictheme_fast_fact_card' => 'paragraphs_type', + 'field.field.paragraph.civictheme_fast_fact_card.field_c_p_icon' => 'field_config', + 'field.field.paragraph.civictheme_fast_fact_card.field_c_p_link' => 'field_config', + 'field.field.paragraph.civictheme_fast_fact_card.field_c_p_summary' => 'field_config', + 'field.field.paragraph.civictheme_fast_fact_card.field_c_p_theme' => 'field_config', + 'field.field.paragraph.civictheme_fast_fact_card.field_c_p_title' => 'field_config', + 'core.entity_form_display.paragraph.civictheme_fast_fact_card.default' => 'entity_form_display', + 'core.entity_view_display.paragraph.civictheme_fast_fact_card.default' => 'entity_view_display', + ]; + + $config_path = \Drupal::service('extension.list.theme')->getPath('civictheme') . '/config/install'; + \Drupal::classResolver(CivicthemeUpdateHelper::class)->createConfigs($new_configs, $config_path); + + // Enable civictheme_fast_fact_card for civictheme_manual_list. + $field_config_name = 'field.field.paragraph.civictheme_manual_list.field_c_p_list_items'; + $config_factory = \Drupal::configFactory(); + $field_config = $config_factory->getEditable($field_config_name); + + if (!$field_config->isNew()) { + $handler_settings = $field_config->get('settings.handler_settings') ?: []; + // Ensure target_bundles exists. + if (!isset($handler_settings['target_bundles'])) { + $handler_settings['target_bundles'] = []; + } + $handler_settings['target_bundles']['civictheme_fast_fact_card'] = 'civictheme_fast_fact_card'; + + // Ensure target_bundles_drag_drop exists. + if (!isset($handler_settings['target_bundles_drag_drop'])) { + $handler_settings['target_bundles_drag_drop'] = []; + } + $handler_settings['target_bundles_drag_drop']['civictheme_fast_fact_card'] = [ + 'weight' => -54, + 'enabled' => TRUE, + ]; + + $field_config->set('settings.handler_settings', $handler_settings); + $field_config->save(); + } + + return (string) new TranslatableMarkup('Added civictheme_fast_fact_card paragraph type and enabled it for manual list.'); +} From 61dc9cc0d6c2a2d320a1f7d4e883c4e2d945b1e7 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Wed, 30 Jul 2025 19:22:59 +0530 Subject: [PATCH 07/14] [GOVCMSCT2-121] Fixed lint issue. --- web/themes/contrib/civictheme/civictheme.post_update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/themes/contrib/civictheme/civictheme.post_update.php b/web/themes/contrib/civictheme/civictheme.post_update.php index a167d8a4f1..afcce4b252 100644 --- a/web/themes/contrib/civictheme/civictheme.post_update.php +++ b/web/themes/contrib/civictheme/civictheme.post_update.php @@ -868,7 +868,7 @@ function civictheme_post_update_update_editor_allowed_field(): string { /** * Add civictheme_fast_fact_card paragraph type and enable it for manual list. */ -function civictheme_post_update_add_fast_fact_card_paragraph(array &$sandbox): ?string { +function civictheme_post_update_add_fast_fact_card_paragraph(array &$sandbox): string { $new_configs = [ // Paragraph type definition. 'paragraphs.paragraphs_type.civictheme_fast_fact_card' => 'paragraphs_type', From ac0c3a131d340edab60fd5db854846dd5db832a1 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Wed, 30 Jul 2025 19:40:57 +0530 Subject: [PATCH 08/14] [GOVCMSCT2-121] Fixed lint issue. --- web/themes/contrib/civictheme/civictheme.post_update.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/themes/contrib/civictheme/civictheme.post_update.php b/web/themes/contrib/civictheme/civictheme.post_update.php index afcce4b252..826ecf9cbf 100644 --- a/web/themes/contrib/civictheme/civictheme.post_update.php +++ b/web/themes/contrib/civictheme/civictheme.post_update.php @@ -867,8 +867,10 @@ function civictheme_post_update_update_editor_allowed_field(): string { /** * Add civictheme_fast_fact_card paragraph type and enable it for manual list. + * + * @SuppressWarnings(PHPMD.StaticAccess) */ -function civictheme_post_update_add_fast_fact_card_paragraph(array &$sandbox): string { +function civictheme_post_update_add_fast_fact_card_paragraph_type(): string { $new_configs = [ // Paragraph type definition. 'paragraphs.paragraphs_type.civictheme_fast_fact_card' => 'paragraphs_type', @@ -886,8 +888,7 @@ function civictheme_post_update_add_fast_fact_card_paragraph(array &$sandbox): s // Enable civictheme_fast_fact_card for civictheme_manual_list. $field_config_name = 'field.field.paragraph.civictheme_manual_list.field_c_p_list_items'; - $config_factory = \Drupal::configFactory(); - $field_config = $config_factory->getEditable($field_config_name); + $field_config = \Drupal::configFactory()->getEditable($field_config_name); if (!$field_config->isNew()) { $handler_settings = $field_config->get('settings.handler_settings') ?: []; From 76a1c3b06fce8873018213d486398d86b051b84b Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Thu, 14 Aug 2025 22:47:17 +0530 Subject: [PATCH 09/14] CivicTheme implementation to display a Fast Fact card. and bumped the uikit. --- package-lock.json | 6 +++--- package.json | 2 +- web/themes/contrib/civictheme/package-lock.json | 6 +++--- web/themes/contrib/civictheme/package.json | 2 +- .../paragraph--civictheme-fast-fact-card.html.twig | 7 +++++++ 5 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 web/themes/contrib/civictheme/templates/paragraphs/paragraph--civictheme-fast-fact-card.html.twig diff --git a/package-lock.json b/package-lock.json index 624e14ebf6..4ad32035d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "@civictheme/uikit": "github:civictheme/uikit#921eef60baf3dc4bd1aef23beb5c429d199e49b8" + "@civictheme/uikit": "github:civictheme/uikit#8570291656b635e11300e95a55edcb0124b706cd" } }, "node_modules/@civictheme/uikit": { "version": "1.11.0", - "resolved": "git+ssh://git@github.com/civictheme/uikit.git#921eef60baf3dc4bd1aef23beb5c429d199e49b8", - "integrity": "sha512-THiC6JTp5gGLEILHTAhCGaLMbHuQaunQS7mpe4j7e7drm8wkLj98b1AwC+NfotHOCePp6A14IVe5MWXTG56VFw==", + "resolved": "git+ssh://git@github.com/civictheme/uikit.git#8570291656b635e11300e95a55edcb0124b706cd", + "integrity": "sha512-n/ttW0qDmTbkFmOmwkbKOaVOsjVB77S9gEGWtUpKOyw6a2ZcPCRcA8LTx1FaeZiSrzIDi+iSbucL1DNhM4Ipvw==", "cpu": [ "x64", "arm", diff --git a/package.json b/package.json index b344b8f7c5..e0e2ba4dee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "@civictheme/uikit": "github:civictheme/uikit#921eef60baf3dc4bd1aef23beb5c429d199e49b8" + "@civictheme/uikit": "github:civictheme/uikit#8570291656b635e11300e95a55edcb0124b706cd" }, "scripts": { "uikit-change": "node scripts/civictheme-uikit-version-manager/index.mjs" diff --git a/web/themes/contrib/civictheme/package-lock.json b/web/themes/contrib/civictheme/package-lock.json index 29deab0ee7..2395eca79c 100644 --- a/web/themes/contrib/civictheme/package-lock.json +++ b/web/themes/contrib/civictheme/package-lock.json @@ -21,7 +21,7 @@ "win32" ], "dependencies": { - "@civictheme/uikit": "github:civictheme/uikit#921eef60baf3dc4bd1aef23beb5c429d199e49b8", + "@civictheme/uikit": "github:civictheme/uikit#8570291656b635e11300e95a55edcb0124b706cd", "@popperjs/core": "^2.11.8" }, "devDependencies": { @@ -97,8 +97,8 @@ }, "node_modules/@civictheme/uikit": { "version": "1.11.0", - "resolved": "git+ssh://git@github.com/civictheme/uikit.git#921eef60baf3dc4bd1aef23beb5c429d199e49b8", - "integrity": "sha512-trnsvERX4dW32i76cgjYo4PnOzB9zjonzh76tZKWoFGqrWsH2dvHz3/brXX2W05HW/0I86GvvNTm5442Q66WRg==", + "resolved": "git+ssh://git@github.com/civictheme/uikit.git#8570291656b635e11300e95a55edcb0124b706cd", + "integrity": "sha512-n/ttW0qDmTbkFmOmwkbKOaVOsjVB77S9gEGWtUpKOyw6a2ZcPCRcA8LTx1FaeZiSrzIDi+iSbucL1DNhM4Ipvw==", "cpu": [ "x64", "arm", diff --git a/web/themes/contrib/civictheme/package.json b/web/themes/contrib/civictheme/package.json index 27fcb677ca..3508ae0b80 100644 --- a/web/themes/contrib/civictheme/package.json +++ b/web/themes/contrib/civictheme/package.json @@ -39,7 +39,7 @@ }, "dependencies": { "@popperjs/core": "^2.11.8", - "@civictheme/uikit": "github:civictheme/uikit#921eef60baf3dc4bd1aef23beb5c429d199e49b8" + "@civictheme/uikit": "github:civictheme/uikit#8570291656b635e11300e95a55edcb0124b706cd" }, "devDependencies": { "@alexskrypnyk/scss-variables-extractor": "^0.1.1", diff --git a/web/themes/contrib/civictheme/templates/paragraphs/paragraph--civictheme-fast-fact-card.html.twig b/web/themes/contrib/civictheme/templates/paragraphs/paragraph--civictheme-fast-fact-card.html.twig new file mode 100644 index 0000000000..1e81f8ddc0 --- /dev/null +++ b/web/themes/contrib/civictheme/templates/paragraphs/paragraph--civictheme-fast-fact-card.html.twig @@ -0,0 +1,7 @@ +{# +/** + * @file + * CivicTheme implementation to display a Fast Fact card. + */ +#} +{% include 'civictheme:fast-fact-card' %} From 5c7b4f5235f8babd15ad16230a0d6a8181b12c61 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Thu, 14 Aug 2025 23:26:12 +0530 Subject: [PATCH 10/14] Updated behat test. --- .../features/paragraph.civictheme_event_card_ref.render.feature | 2 +- .../paragraph.civictheme_navigation_card_ref.render.feature | 2 +- .../features/paragraph.civictheme_promo_card_ref.render.feature | 2 +- .../features/paragraph.civictheme_snippet_ref.render.feature | 2 +- .../paragraph.civictheme_subject_card_ref.fields.feature | 2 +- .../paragraph.civictheme_subject_card_ref.render.feature | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/behat/features/paragraph.civictheme_event_card_ref.render.feature b/tests/behat/features/paragraph.civictheme_event_card_ref.render.feature index a2e463362f..6e0b31e774 100644 --- a/tests/behat/features/paragraph.civictheme_event_card_ref.render.feature +++ b/tests/behat/features/paragraph.civictheme_event_card_ref.render.feature @@ -59,7 +59,7 @@ Feature: Event reference card render And I should see 2 ".ct-event-card__location" elements And I should see 2 ".ct-event-card__image" elements And I should see 2 ".ct-event-card__title" elements - And I should see 2 ".ct-event-card__title__link" elements + And I should see 2 ".ct-event-card__title-link" elements And I should see 2 ".ct-event-card__summary" elements And I should see 2 ".ct-event-card__location" elements And I should see the text "[TEST] Referenced Event 1" diff --git a/tests/behat/features/paragraph.civictheme_navigation_card_ref.render.feature b/tests/behat/features/paragraph.civictheme_navigation_card_ref.render.feature index faa33e1359..347b635342 100644 --- a/tests/behat/features/paragraph.civictheme_navigation_card_ref.render.feature +++ b/tests/behat/features/paragraph.civictheme_navigation_card_ref.render.feature @@ -39,7 +39,7 @@ Feature: Navigation reference card render And I should see 2 ".ct-navigation-card__content" elements And I should see 2 ".ct-navigation-card__image" elements And I should see 2 ".ct-navigation-card__title" elements - And I should see 2 ".ct-navigation-card__title__link" elements + And I should see 2 ".ct-navigation-card__title-link" elements And I should see 2 ".ct-navigation-card__summary" elements And I should see the text "[TEST] Referenced Page 1" And I should see the text "Summary 1" diff --git a/tests/behat/features/paragraph.civictheme_promo_card_ref.render.feature b/tests/behat/features/paragraph.civictheme_promo_card_ref.render.feature index c501352235..f42f314c77 100644 --- a/tests/behat/features/paragraph.civictheme_promo_card_ref.render.feature +++ b/tests/behat/features/paragraph.civictheme_promo_card_ref.render.feature @@ -46,7 +46,7 @@ Feature: Promo reference card render And I should see 2 ".ct-promo-card__content" elements And I should see 2 ".ct-promo-card__image" elements And I should see 2 ".ct-promo-card__title" elements - And I should see 2 ".ct-promo-card__title__link" elements + And I should see 2 ".ct-promo-card__title-link" elements And I should see 2 ".ct-promo-card__summary" elements And I should see the text "[TEST] Referenced Page 1" And I should see the text "Summary 1" diff --git a/tests/behat/features/paragraph.civictheme_snippet_ref.render.feature b/tests/behat/features/paragraph.civictheme_snippet_ref.render.feature index 69ac8de325..6a8001dea9 100644 --- a/tests/behat/features/paragraph.civictheme_snippet_ref.render.feature +++ b/tests/behat/features/paragraph.civictheme_snippet_ref.render.feature @@ -36,7 +36,7 @@ Feature: Navigation reference card render And I should see 1 ".ct-snippet.ct-theme-dark" elements And I should see 2 ".ct-snippet__title" elements And I should see 2 ".ct-snippet__summary" elements - And I should see 2 ".ct-snippet__title__link" elements + And I should see 2 ".ct-snippet__title-link" elements And I should see 2 ".ct-snippet__tags" elements And I should see the text "[TEST] Referenced Page 1" And I should see the text "Summary 1" diff --git a/tests/behat/features/paragraph.civictheme_subject_card_ref.fields.feature b/tests/behat/features/paragraph.civictheme_subject_card_ref.fields.feature index ab82bdc33a..43dd1c797b 100644 --- a/tests/behat/features/paragraph.civictheme_subject_card_ref.fields.feature +++ b/tests/behat/features/paragraph.civictheme_subject_card_ref.fields.feature @@ -39,6 +39,6 @@ Feature: subject reference card render And I should see 2 ".ct-subject-card__content" elements And I should see 2 ".ct-subject-card__image" elements And I should see 2 ".ct-subject-card__title" elements - And I should see 2 ".ct-subject-card__title__link" elements + And I should see 2 ".ct-subject-card__title-link" elements And I should see the text "[TEST] Referenced Page 1" And I should see the text "[TEST] Referenced Page 2" diff --git a/tests/behat/features/paragraph.civictheme_subject_card_ref.render.feature b/tests/behat/features/paragraph.civictheme_subject_card_ref.render.feature index 442684204d..6e108aa2dc 100644 --- a/tests/behat/features/paragraph.civictheme_subject_card_ref.render.feature +++ b/tests/behat/features/paragraph.civictheme_subject_card_ref.render.feature @@ -39,6 +39,6 @@ Feature: Subject reference card render And I should see 2 ".ct-subject-card__content" elements And I should see 2 ".ct-subject-card__image" elements And I should see 2 ".ct-subject-card__title" elements - And I should see 2 ".ct-subject-card__title__link" elements + And I should see 2 ".ct-subject-card__title-link" elements And I should see the text "[TEST] Referenced Page 1" And I should see the text "[TEST] Referenced Page 2" From 6e76c02ef31c6d11dde2541669468db139869624 Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 15 Aug 2025 09:01:09 +0530 Subject: [PATCH 11/14] Fixed Failing test. --- .../behat/features/media.civictheme_remote_video.render.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/behat/features/media.civictheme_remote_video.render.feature b/tests/behat/features/media.civictheme_remote_video.render.feature index 9839e61c82..47c5c13ffa 100644 --- a/tests/behat/features/media.civictheme_remote_video.render.feature +++ b/tests/behat/features/media.civictheme_remote_video.render.feature @@ -29,5 +29,5 @@ Feature: CivicTheme remote video And I should see the text "Test Remote Video without transcript" And I should see the text "Test Remote Video with transcript" And I should see the text "View transcript" - And I click on ".ct-video-player__links__transcript .ct-button" element + And I click on ".ct-video-player__links-transcript a" element And I should see the text "[TEST] CivicTheme Remote Video Transcript" From 5d08d07fe6fff44ac8211ff4348d7d9b9f9459dd Mon Sep 17 00:00:00 2001 From: Stuart Rowlands Date: Sun, 14 Sep 2025 15:09:06 +1000 Subject: [PATCH 12/14] Add Quant Cloud migration configuration - Add quant.type labels to docker-compose services - Add GitHub Actions build-deploy workflow - Update Drupal settings for Quant Cloud environment variables - Make Elasticsearch compatible with ECS Fargate - Convert post-rollout tasks to entrypoint scripts --- .docker/cli.dockerfile | 1 + .docker/entrypoints/cli/00-fix-permissions.sh | 52 +++++++ .../cli/01-show-drevops-variables.sh | 7 + .../cli/02-notify-about-pre-deployment.sh | 11 ++ .docker/entrypoints/cli/03-provision-site.sh | 30 ++++ .../cli/04-send-deployment-notifications.sh | 12 ++ .../entrypoints/nginx/00-fix-permissions.sh | 52 +++++++ .docker/entrypoints/php/00-fix-permissions.sh | 52 +++++++ .docker/php.dockerfile | 1 + .dockerignore | 1 + .github/workflows/build-deploy.yml | 144 ++++++++++++++++++ docker-compose.yml | 3 + web/sites/default/settings.php | 13 +- 13 files changed, 373 insertions(+), 6 deletions(-) create mode 100755 .docker/entrypoints/cli/00-fix-permissions.sh create mode 100755 .docker/entrypoints/cli/01-show-drevops-variables.sh create mode 100755 .docker/entrypoints/cli/02-notify-about-pre-deployment.sh create mode 100755 .docker/entrypoints/cli/03-provision-site.sh create mode 100755 .docker/entrypoints/cli/04-send-deployment-notifications.sh create mode 100755 .docker/entrypoints/nginx/00-fix-permissions.sh create mode 100755 .docker/entrypoints/php/00-fix-permissions.sh create mode 100644 .github/workflows/build-deploy.yml diff --git a/.docker/cli.dockerfile b/.docker/cli.dockerfile index 9ee3362bb7..51c0579404 100644 --- a/.docker/cli.dockerfile +++ b/.docker/cli.dockerfile @@ -110,3 +110,4 @@ RUN cd /app/web/themes/contrib/civictheme \ # Compile sub-theme assets. RUN npm --prefix web/themes/custom/civictheme_demo install --no-audit --no-progress --unsafe-perm \ && cd /app/web/themes/custom/civictheme_demo && npm run build +COPY .docker/entrypoints/cli/* /quant-entrypoint.d/ diff --git a/.docker/entrypoints/cli/00-fix-permissions.sh b/.docker/entrypoints/cli/00-fix-permissions.sh new file mode 100755 index 0000000000..923e3529e6 --- /dev/null +++ b/.docker/entrypoints/cli/00-fix-permissions.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -e + +# Fix EFS volume permissions based on lagoon.persistent labels +# +# Two approaches based on container configuration: +# 1. VOLUME_USER set: Use secure permissions with UID/GID 1000 (requires container remapping) +# 2. VOLUME_USER unset: Fall back to world-writable (777/666) for compatibility + +echo "Fixing file permissions for EFS volumes..." + +# Check if containers have been configured with UID/GID remapping +if [ -n "$VOLUME_USER" ]; then + echo "🔒 VOLUME_USER detected: Using secure permissions with UID/GID 1000" + echo " (Assumes containers remap www-data to UID/GID 1000 for EFS compatibility)" + PERMISSION_MODE="secure" +else + echo "⚠️ VOLUME_USER not set: Using world-writable permissions for compatibility" + echo " (Consider setting VOLUME_USER and remapping container users to UID/GID 1000)" + PERMISSION_MODE="compatible" +fi + +# Persistent volume paths from docker-compose lagoon.persistent labels +for path in "/app/web/sites/default/files/"; do + if [ -d "$path" ]; then + echo "Fixing permissions for: $path" + + if [ "$PERMISSION_MODE" = "secure" ]; then + # Set secure directory permissions (755 = rwxr-xr-x) + find "$path" -type d -exec chmod 755 {} + 2>/dev/null || true + + # Set secure file permissions (644 = rw-r--r--) + find "$path" -type f -exec chmod 644 {} + 2>/dev/null || true + + echo "✓ Secure permissions applied: $path (dirs: 755, files: 644)" + else + # Compatible approach: World-writable fallback + + # Make directories world-writable (since we can't chown to unknown web server user) + find "$path" -type d -exec chmod 777 {} + 2>/dev/null || true + + # Make files world-readable/writable (since we can't chown to unknown web server user) + find "$path" -type f -exec chmod 666 {} + 2>/dev/null || true + + echo "✓ Compatible permissions applied: $path (dirs: 777, files: 666)" + fi + else + echo "Path not found (may not be mounted yet): $path" + fi +done + +echo "Permission fixing completed for 1 volumes ($PERMISSION_MODE mode)" diff --git a/.docker/entrypoints/cli/01-show-drevops-variables.sh b/.docker/entrypoints/cli/01-show-drevops-variables.sh new file mode 100755 index 0000000000..032b0fc6d8 --- /dev/null +++ b/.docker/entrypoints/cli/01-show-drevops-variables.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +# Post-rollout task: Show DrevOps variables. +# Generated from .lagoon.yml + +env -0 | sort -z | tr '\0' '\n' | grep ^DREVOPS_ || true diff --git a/.docker/entrypoints/cli/02-notify-about-pre-deployment.sh b/.docker/entrypoints/cli/02-notify-about-pre-deployment.sh new file mode 100755 index 0000000000..391ea7811d --- /dev/null +++ b/.docker/entrypoints/cli/02-notify-about-pre-deployment.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Post-rollout task: Notify about pre-deployment. +# Generated from .lagoon.yml + +if [ -n "$LAGOON_PR_NUMBER" ]; then export DREVOPS_NOTIFY_REF=$LAGOON_PR_NUMBER;export DREVOPS_NOTIFY_SHA=${LAGOON_PR_HEAD_SHA#origin/};export DREVOPS_NOTIFY_BRANCH=$LAGOON_PR_HEAD_BRANCH;else export DREVOPS_NOTIFY_REF=$LAGOON_GIT_BRANCH;export DREVOPS_NOTIFY_SHA=$LAGOON_GIT_SHA;export DREVOPS_NOTIFY_BRANCH=$LAGOON_GIT_BRANCH;fi +DREVOPS_NOTIFY_PROJECT=$LAGOON_PROJECT \ +DREVOPS_NOTIFY_ENVIRONMENT_URL=$LAGOON_ROUTE \ +DREVOPS_NOTIFY_EVENT=pre_deployment ./scripts/drevops/notify.sh || true + diff --git a/.docker/entrypoints/cli/03-provision-site.sh b/.docker/entrypoints/cli/03-provision-site.sh new file mode 100755 index 0000000000..db339f7563 --- /dev/null +++ b/.docker/entrypoints/cli/03-provision-site.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -e + +# Post-rollout task: Provision site +# Generated from .lagoon.yml +# COMMENTED OUT: This script contains rsync commands that won't work in Quant Cloud + +# if [ "$LAGOON_ENVIRONMENT_TYPE" = "production" ] || [ "$LAGOON_GIT_BRANCH" = "${DREVOPS_LAGOON_PRODUCTION_BRANCH:-main}" ]; then +# echo "==> Running in PRODUCTION environment." +# # Never unblock admin user in production. +# export DRUPAL_UNBLOCK_ADMIN=0 +# # Never sanitize DB in production. +# export DREVOPS_PROVISION_SANITIZE_DB_SKIP=1 +# fi +# +# # Deployments from UI are not able to bypass the value of +# # DREVOPS_PROVISION_OVERRIDE_DB set by the deploy-lagoon.sh +# # during previous deployments (it sets value to '0' to mitigate Lagoon bug +# # where environment variables cannot be deleted and have to be set to a value). +# # @see https://github.com/uselagoon/lagoon/issues/1922 +# # Explicitly set DB overwrite flag to the value from .env file for +# # deployments from the profile. +# if [ "${DREVOPS_PROVISION_USE_PROFILE}" = "1" ]; then +# export DREVOPS_PROVISION_OVERRIDE_DB="$(cat .env | grep ^DREVOPS_PROVISION_OVERRIDE_DB | cut -c31-)" +# fi +# ./scripts/drevops/provision.sh + +# NOTE: This provision script has been disabled because: +# - rsync commands try to connect to Lagoon SSH which is not available in Quant Cloud +# - Use DREVOPS_PROVISION_SKIP=1 environment variable to skip provision steps diff --git a/.docker/entrypoints/cli/04-send-deployment-notifications.sh b/.docker/entrypoints/cli/04-send-deployment-notifications.sh new file mode 100755 index 0000000000..4306c5be2a --- /dev/null +++ b/.docker/entrypoints/cli/04-send-deployment-notifications.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +# Post-rollout task: Send deployment notifications +# Generated from .lagoon.yml + +if [ -n "$LAGOON_PR_NUMBER" ]; then export DREVOPS_NOTIFY_REF=$LAGOON_PR_NUMBER; export DREVOPS_NOTIFY_SHA=${LAGOON_PR_HEAD_SHA#origin/}; export DREVOPS_NOTIFY_BRANCH=$LAGOON_PR_HEAD_BRANCH; else export DREVOPS_NOTIFY_REF=$LAGOON_GIT_BRANCH; export DREVOPS_NOTIFY_SHA=$LAGOON_GIT_SHA; export DREVOPS_NOTIFY_BRANCH=$LAGOON_GIT_BRANCH; fi +DREVOPS_NOTIFY_EVENT=post_deployment \ +DREVOPS_NOTIFY_PROJECT=$LAGOON_PROJECT \ +DREVOPS_NOTIFY_ENVIRONMENT_URL=$LAGOON_ROUTE \ +./scripts/drevops/notify.sh + diff --git a/.docker/entrypoints/nginx/00-fix-permissions.sh b/.docker/entrypoints/nginx/00-fix-permissions.sh new file mode 100755 index 0000000000..923e3529e6 --- /dev/null +++ b/.docker/entrypoints/nginx/00-fix-permissions.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -e + +# Fix EFS volume permissions based on lagoon.persistent labels +# +# Two approaches based on container configuration: +# 1. VOLUME_USER set: Use secure permissions with UID/GID 1000 (requires container remapping) +# 2. VOLUME_USER unset: Fall back to world-writable (777/666) for compatibility + +echo "Fixing file permissions for EFS volumes..." + +# Check if containers have been configured with UID/GID remapping +if [ -n "$VOLUME_USER" ]; then + echo "🔒 VOLUME_USER detected: Using secure permissions with UID/GID 1000" + echo " (Assumes containers remap www-data to UID/GID 1000 for EFS compatibility)" + PERMISSION_MODE="secure" +else + echo "⚠️ VOLUME_USER not set: Using world-writable permissions for compatibility" + echo " (Consider setting VOLUME_USER and remapping container users to UID/GID 1000)" + PERMISSION_MODE="compatible" +fi + +# Persistent volume paths from docker-compose lagoon.persistent labels +for path in "/app/web/sites/default/files/"; do + if [ -d "$path" ]; then + echo "Fixing permissions for: $path" + + if [ "$PERMISSION_MODE" = "secure" ]; then + # Set secure directory permissions (755 = rwxr-xr-x) + find "$path" -type d -exec chmod 755 {} + 2>/dev/null || true + + # Set secure file permissions (644 = rw-r--r--) + find "$path" -type f -exec chmod 644 {} + 2>/dev/null || true + + echo "✓ Secure permissions applied: $path (dirs: 755, files: 644)" + else + # Compatible approach: World-writable fallback + + # Make directories world-writable (since we can't chown to unknown web server user) + find "$path" -type d -exec chmod 777 {} + 2>/dev/null || true + + # Make files world-readable/writable (since we can't chown to unknown web server user) + find "$path" -type f -exec chmod 666 {} + 2>/dev/null || true + + echo "✓ Compatible permissions applied: $path (dirs: 777, files: 666)" + fi + else + echo "Path not found (may not be mounted yet): $path" + fi +done + +echo "Permission fixing completed for 1 volumes ($PERMISSION_MODE mode)" diff --git a/.docker/entrypoints/php/00-fix-permissions.sh b/.docker/entrypoints/php/00-fix-permissions.sh new file mode 100755 index 0000000000..923e3529e6 --- /dev/null +++ b/.docker/entrypoints/php/00-fix-permissions.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -e + +# Fix EFS volume permissions based on lagoon.persistent labels +# +# Two approaches based on container configuration: +# 1. VOLUME_USER set: Use secure permissions with UID/GID 1000 (requires container remapping) +# 2. VOLUME_USER unset: Fall back to world-writable (777/666) for compatibility + +echo "Fixing file permissions for EFS volumes..." + +# Check if containers have been configured with UID/GID remapping +if [ -n "$VOLUME_USER" ]; then + echo "🔒 VOLUME_USER detected: Using secure permissions with UID/GID 1000" + echo " (Assumes containers remap www-data to UID/GID 1000 for EFS compatibility)" + PERMISSION_MODE="secure" +else + echo "⚠️ VOLUME_USER not set: Using world-writable permissions for compatibility" + echo " (Consider setting VOLUME_USER and remapping container users to UID/GID 1000)" + PERMISSION_MODE="compatible" +fi + +# Persistent volume paths from docker-compose lagoon.persistent labels +for path in "/app/web/sites/default/files/"; do + if [ -d "$path" ]; then + echo "Fixing permissions for: $path" + + if [ "$PERMISSION_MODE" = "secure" ]; then + # Set secure directory permissions (755 = rwxr-xr-x) + find "$path" -type d -exec chmod 755 {} + 2>/dev/null || true + + # Set secure file permissions (644 = rw-r--r--) + find "$path" -type f -exec chmod 644 {} + 2>/dev/null || true + + echo "✓ Secure permissions applied: $path (dirs: 755, files: 644)" + else + # Compatible approach: World-writable fallback + + # Make directories world-writable (since we can't chown to unknown web server user) + find "$path" -type d -exec chmod 777 {} + 2>/dev/null || true + + # Make files world-readable/writable (since we can't chown to unknown web server user) + find "$path" -type f -exec chmod 666 {} + 2>/dev/null || true + + echo "✓ Compatible permissions applied: $path (dirs: 777, files: 666)" + fi + else + echo "Path not found (may not be mounted yet): $path" + fi +done + +echo "Permission fixing completed for 1 volumes ($PERMISSION_MODE mode)" diff --git a/.docker/php.dockerfile b/.docker/php.dockerfile index 3344c01866..c03f8af885 100644 --- a/.docker/php.dockerfile +++ b/.docker/php.dockerfile @@ -15,3 +15,4 @@ FROM uselagoon/php-8.3-fpm:25.1.0 RUN apk add --no-cache tzdata COPY --from=cli /app /app +COPY .docker/entrypoints/php/* /quant-entrypoint.d/ diff --git a/.dockerignore b/.dockerignore index 76b11c52c8..2cf5b5166f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -29,6 +29,7 @@ node_modules # Do not ignore other required files. !.docker/scripts +!.docker/entrypoints !.docker/config !.env !.eslintrc.json diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml new file mode 100644 index 0000000000..9d1a619859 --- /dev/null +++ b/.github/workflows/build-deploy.yml @@ -0,0 +1,144 @@ +name: Build and Push civictheme-monorepo-drupal to Quant Cloud +'on': + push: + branches: + - main + - master + - develop + - quant-cloud-migration + - feature/* + tags: + - '*' + pull_request: + branches: '*' + +concurrency: + group: build-and-push-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-push: + runs-on: sh-runner-1-arm64 + steps: + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Initialize Quant Cloud + uses: quantcdn/quant-cloud-init-action@v1.1.2 + id: init + with: + quant_organization: ${{ secrets.QUANT_ORGANIZATION }} + quant_api_key: ${{ secrets.QUANT_API_KEY }} + quant_application: civictheme-monorepo-drupal + master_branch_override: main + + - name: Override outputs for quant-cloud-migration branch + id: override-outputs + run: |- + # Override outputs for quant-cloud-migration branch to treat it as production + if [[ "${{ github.ref }}" == "refs/heads/quant-cloud-migration" ]]; then + echo "image_suffix=-latest" >> $GITHUB_OUTPUT + echo "image_suffix_clean=latest" >> $GITHUB_OUTPUT + echo "is_production=true" >> $GITHUB_OUTPUT + echo "environment_name=production" >> $GITHUB_OUTPUT + echo "environment_exists=true" >> $GITHUB_OUTPUT + echo "Overriding outputs for quant-cloud-migration branch: using -latest suffix and production environment" + else + # Use the original action outputs + echo "image_suffix=${{ steps.init.outputs.image_suffix }}" >> $GITHUB_OUTPUT + # Remove leading hyphen from image_suffix for image_suffix parameter + suffix="${{ steps.init.outputs.image_suffix }}" + clean_suffix="${suffix#-}" + echo "image_suffix_clean=$clean_suffix" >> $GITHUB_OUTPUT + echo "is_production=${{ steps.init.outputs.is_production }}" >> $GITHUB_OUTPUT + echo "environment_name=${{ steps.init.outputs.environment_name }}" >> $GITHUB_OUTPUT + echo "environment_exists=${{ steps.init.outputs.environment_exists }}" >> $GITHUB_OUTPUT + fi + + - name: Build and push cli image + uses: docker/build-push-action@v5 + with: + context: . + file: ./.docker/cli.dockerfile + platforms: linux/arm64 + push: true + tags: ${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:cli${{ steps.override-outputs.outputs.image_suffix }} + cache-from: |- + type=gha + type=registry,ref=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application }}:cli-cache + cache-to: type=gha,mode=max + build-args: CLI_IMAGE=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:cli${{ steps.override-outputs.outputs.image_suffix }} + + - name: Build and push nginx image + uses: docker/build-push-action@v5 + with: + context: . + file: ./.docker/nginx-drupal.dockerfile + platforms: linux/arm64 + push: true + tags: ${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:nginx${{ steps.override-outputs.outputs.image_suffix }} + cache-from: |- + type=gha + type=registry,ref=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application }}:nginx-cache + cache-to: type=gha,mode=max + build-args: CLI_IMAGE=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:cli${{ steps.override-outputs.outputs.image_suffix }} + + - name: Build and push php image + uses: docker/build-push-action@v5 + with: + context: . + file: ./.docker/php.dockerfile + platforms: linux/arm64 + push: true + tags: ${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:php${{ steps.override-outputs.outputs.image_suffix }} + cache-from: |- + type=gha + type=registry,ref=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application }}:php-cache + cache-to: type=gha,mode=max + build-args: CLI_IMAGE=${{ steps.init.outputs.stripped_endpoint }}/${{ secrets.QUANT_ORGANIZATION }}/${{ steps.init.outputs.quant_application + }}:cli${{ steps.override-outputs.outputs.image_suffix }} + + - name: Create environment if it doesn't exist + if: ${{ !startsWith(github.ref, 'refs/tags/') && steps.override-outputs.outputs.environment_exists == 'false' }} + uses: quantcdn/quant-cloud-environment-action@v1.2.1 + with: + api_key: ${{ secrets.QUANT_API_KEY }} + organization: ${{ secrets.QUANT_ORGANIZATION }} + app_name: ${{ steps.init.outputs.quant_application }} + environment_name: ${{ steps.override-outputs.outputs.environment_name }} + from_environment: production + image_suffix: ${{ steps.override-outputs.outputs.image_suffix_clean }} + + - name: Sync database from production to new environment + if: ${{ !startsWith(github.ref, 'refs/tags/') && steps.override-outputs.outputs.environment_exists == 'false' && steps.override-outputs.outputs.environment_name + != 'production' }} + uses: quantcdn/quant-cloud-environment-sync-action@v1.0.0 + with: + api_key: ${{ secrets.QUANT_API_KEY }} + organization: ${{ secrets.QUANT_ORGANIZATION }} + app_name: ${{ steps.init.outputs.quant_application }} + environment_name: ${{ steps.override-outputs.outputs.environment_name }} + source: production + type: database + wait: true + wait_interval: 10 + max_retries: 30 + + - name: Redeploy existing environment + if: ${{ !startsWith(github.ref, 'refs/tags/') && steps.override-outputs.outputs.environment_exists == 'true' }} + uses: quantcdn/quant-cloud-environment-state-action@v1 + with: + api_key: ${{ secrets.QUANT_API_KEY }} + organization: ${{ secrets.QUANT_ORGANIZATION }} + application: ${{ steps.init.outputs.quant_application }} + environment: ${{ steps.override-outputs.outputs.environment_name }} + action: redeploy diff --git a/docker-compose.yml b/docker-compose.yml index 64dd4cb475..9713050a54 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -143,6 +143,7 @@ services: ports: - "3306" # MariaDB port in container. Find port on host with `ahoy info` or `docker compose port mariadb 3306`. labels: + quant.type: mysql lagoon.type: mariadb # See https://docs.lagoon.sh/using-lagoon-advanced/service-types/ # Chrome container, used for browser testing. @@ -155,6 +156,7 @@ services: depends_on: - cli labels: + quant.type: none lagoon.type: none # Do not deploy in Lagoon. # Helper container to wait for services to become available. @@ -165,6 +167,7 @@ services: - mariadb command: mariadb:3306 labels: + quant.type: none lagoon.type: none # Do not deploy in Lagoon. networks: diff --git a/web/sites/default/settings.php b/web/sites/default/settings.php index e2079ec6b4..917edfcc99 100644 --- a/web/sites/default/settings.php +++ b/web/sites/default/settings.php @@ -69,7 +69,7 @@ $settings['file_private_path'] = 'sites/default/files/private'; // Base salt on the DB host name. -$settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: 'localhost'); +$settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: getenv('DB_HOST') ?: 'localhost'); // Expiration of cached pages. $config['system.performance']['cache']['page']['max_age'] = 900; @@ -98,6 +98,7 @@ // URL when accessed from Behat tests. '^nginx$', ]; +$settings['trusted_host_patterns'][] = '^.+\.apps\.quantgovsites\.com$'; // Modules excluded from config export. $settings['config_exclude_modules'] = []; @@ -114,11 +115,11 @@ [ 'default' => [ - 'database' => getenv('MYSQL_DATABASE') ?: getenv('MARIADB_DATABASE') ?: 'drupal', - 'username' => getenv('MYSQL_USERNAME') ?: getenv('MARIADB_USERNAME') ?: 'drupal', - 'password' => getenv('MYSQL_PASSWORD') ?: getenv('MARIADB_PASSWORD') ?: 'drupal', - 'host' => getenv('MYSQL_HOST') ?: getenv('MARIADB_HOST') ?: 'localhost', - 'port' => getenv('MYSQL_PORT') ?: getenv('MARIADB_PORT') ?: '3306', + 'database' => getenv('MYSQL_DATABASE') ?: getenv('MARIADB_DATABASE') ?: getenv('DB_DATABASE') ?: 'drupal', + 'username' => getenv('MYSQL_USERNAME') ?: getenv('MARIADB_USERNAME') ?: getenv('DB_USERNAME') ?: 'drupal', + 'password' => getenv('MYSQL_PASSWORD') ?: getenv('MARIADB_PASSWORD') ?: getenv('DB_PASSWORD') ?: 'drupal', + 'host' => getenv('MYSQL_HOST') ?: getenv('MARIADB_HOST') ?: getenv('DB_HOST') ?: 'localhost', + 'port' => getenv('MYSQL_PORT') ?: getenv('MARIADB_PORT') ?: getenv('DB_PORT') ?: '3306', 'prefix' => '', 'driver' => 'mysql', 'charset' => 'utf8mb4', From 15bd089d1e4f023154da0ff89a5e0b106df2e499 Mon Sep 17 00:00:00 2001 From: Stuart Rowlands Date: Thu, 25 Sep 2025 14:33:27 +1000 Subject: [PATCH 13/14] Add Quant Cloud migration configuration - Add quant.type labels to docker-compose services - Add GitHub Actions build-deploy workflow - Update Drupal settings for Quant Cloud environment variables - Make Elasticsearch compatible with ECS Fargate - Convert post-rollout tasks to entrypoint scripts - Add nginx configuration for CDN header handling - Add Quant Cloud scripts (provision and database backup) --- .../nginx/location_drupal_prepend_host.conf | 23 ++ .docker/entrypoints/cli/03-provision-site.sh | 10 + .docker/nginx-drupal.dockerfile | 5 +- .github/workflows/build-deploy.yml | 4 +- scripts/quant/download-db.sh | 227 ++++++++++++++++++ scripts/quant/provision-quant.sh | 224 +++++++++++++++++ 6 files changed, 491 insertions(+), 2 deletions(-) create mode 100644 .docker/config/nginx/location_drupal_prepend_host.conf create mode 100755 scripts/quant/download-db.sh create mode 100755 scripts/quant/provision-quant.sh diff --git a/.docker/config/nginx/location_drupal_prepend_host.conf b/.docker/config/nginx/location_drupal_prepend_host.conf new file mode 100644 index 0000000000..24a0a9ddd8 --- /dev/null +++ b/.docker/config/nginx/location_drupal_prepend_host.conf @@ -0,0 +1,23 @@ +# Set HTTP_HOST for PHP using canonical host from CDN headers +# Priority: HTTP_QUANT_ORIG_HOST > HTTP_X_FORWARDED_HOST > original Host header (preserving port) + +# Default to the incoming Host header so non-standard ports stay intact (e.g. :8080) +set $final_host $http_host; + +# Use X-Forwarded-Host when provided (reverse proxies) +if ($http_x_forwarded_host != "") { + set $final_host $http_x_forwarded_host; +} + +# Override with Quant-Orig-Host when available +if ($http_quant_orig_host != "") { + set $final_host $http_quant_orig_host; +} + +# Extract first host from comma-separated X-Forwarded-Host values +if ($final_host ~ "^([^,\s]+)") { + set $final_host $1; +} + +# Always pass the calculated host; without override it matches the original Host header +fastcgi_param HTTP_HOST $final_host; diff --git a/.docker/entrypoints/cli/03-provision-site.sh b/.docker/entrypoints/cli/03-provision-site.sh index db339f7563..b9cf8b32f0 100755 --- a/.docker/entrypoints/cli/03-provision-site.sh +++ b/.docker/entrypoints/cli/03-provision-site.sh @@ -28,3 +28,13 @@ set -e # NOTE: This provision script has been disabled because: # - rsync commands try to connect to Lagoon SSH which is not available in Quant Cloud # - Use DREVOPS_PROVISION_SKIP=1 environment variable to skip provision steps + +# Delegate Drupal provisioning to the Quant-aware script. The standard +# DrevOps provision script is not compatible with Quant Cloud because it relies +# on Lagoon-specific tooling (e.g., rsync to Lagoon SSH). +if [ -x "./scripts/quant/provision-quant.sh" ]; then + ./scripts/quant/provision-quant.sh +else + echo "Quant provisioning script missing or not executable." >&2 + exit 1 +fi diff --git a/.docker/nginx-drupal.dockerfile b/.docker/nginx-drupal.dockerfile index b67c5ea196..da6a654edc 100644 --- a/.docker/nginx-drupal.dockerfile +++ b/.docker/nginx-drupal.dockerfile @@ -17,4 +17,7 @@ ENV WEBROOT=${WEBROOT} RUN apk add --no-cache tzdata -COPY --from=cli /app /app +# Copy custom nginx configuration for CDN header handling +COPY .docker/config/nginx/location_drupal_prepend_host.conf /etc/nginx/conf.d/drupal/ +RUN chmod 0644 /etc/nginx/conf.d/drupal/location_drupal_prepend_host.conf +COPY --from=cli /app /app \ No newline at end of file diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index 9d1a619859..5aa91733a4 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -7,6 +7,8 @@ name: Build and Push civictheme-monorepo-drupal to Quant Cloud - develop - quant-cloud-migration - feature/* + - content/* + - pr-* tags: - '*' pull_request: @@ -18,7 +20,7 @@ concurrency: jobs: build-and-push: - runs-on: sh-runner-1-arm64 + runs-on: ubuntu-latest steps: - name: Checkout code diff --git a/scripts/quant/download-db.sh b/scripts/quant/download-db.sh new file mode 100755 index 0000000000..8b04c340e2 --- /dev/null +++ b/scripts/quant/download-db.sh @@ -0,0 +1,227 @@ +#!/usr/bin/env bash +# Download the latest Quant Cloud database backup, decompress it, and report paths. +set -euo pipefail + +if ! command -v qc >/dev/null 2>&1; then + echo "Quant CLI (qc) is required but was not found. Install it first." >&2 + exit 1 +fi + +QUANT_ORG_NAME="${QUANT_ORG_NAME:-salsa-digital}" + +if ! qc org select "${QUANT_ORG_NAME}" >/dev/null 2>&1; then + echo "Failed to select Quant organisation '${QUANT_ORG_NAME}'. Run \`qc org list\` to verify access." >&2 + exit 1 +fi + +echo "Downloading database from Quant Cloud. If you need Lagoon, run \`ahoy download-db-lagoon\`." + +QUANT_APP_NAME="${QUANT_APP_NAME:-${LAGOON_PROJECT:-qld-bsc}}" +# QUANT_APP_NAME is the canonical Quant application identifier; falls back to LAGOON_PROJECT for legacy workflows. +QUANT_ENVIRONMENT="${QUANT_ENVIRONMENT:-production}" +# Backward compatibility: expose LAGOON_PROJECT for legacy tooling until everything is Quant-aware. +if [ -z "${LAGOON_PROJECT:-}" ]; then + export LAGOON_PROJECT="${QUANT_APP_NAME}" +fi + +DREVOPS_DB_DIR="${DREVOPS_DB_DIR:-./.data}" +DREVOPS_DB_FILE="${DREVOPS_DB_FILE:-db.sql}" +QUANT_DOWNLOAD_DIR="${QUANT_DOWNLOAD_DIR:-./downloads}" +QUANT_BACKUP_POLL_INTERVAL="${QUANT_BACKUP_POLL_INTERVAL:-15}" +QUANT_BACKUP_TIMEOUT="${QUANT_BACKUP_TIMEOUT:-900}" +QUANT_BACKUP_DESCRIPTION="${QUANT_BACKUP_DESCRIPTION:-Database backup triggered by ahoy download-db on $(date -u +'%Y-%m-%dT%H:%M:%SZ')}" + +mkdir -p "${DREVOPS_DB_DIR}" "${QUANT_DOWNLOAD_DIR}" + +QC_BIN_REALPATH="$(python3 - <<'PY' +import os +import shutil +path = shutil.which('qc') +if not path: + raise SystemExit('qc binary not found') +print(os.path.realpath(path)) +PY +)" +QUANT_CLI_MODULE_DIR="$(dirname "${QC_BIN_REALPATH}")" +export QUANT_CLI_MODULE_DIR +export QUANT_APP_NAME QUANT_ENVIRONMENT QUANT_DOWNLOAD_DIR DREVOPS_DB_DIR DREVOPS_DB_FILE +export QUANT_BACKUP_POLL_INTERVAL QUANT_BACKUP_TIMEOUT QUANT_BACKUP_DESCRIPTION + +NODE_OUTPUT="$(node --input-type=module <<'NODE' +import fs from 'fs'; +import path from 'path'; +import { pipeline } from 'stream/promises'; +import { createGunzip } from 'zlib'; +import { pathToFileURL } from 'url'; + +const hasGzipMagicNumber = (filePath) => { + let fd; + try { + fd = fs.openSync(filePath, 'r'); + const buffer = Buffer.alloc(2); + const bytesRead = fs.readSync(fd, buffer, 0, 2, 0); + return bytesRead === 2 && buffer[0] === 0x1f && buffer[1] === 0x8b; + } catch (error) { + return false; + } finally { + if (fd !== undefined) { + fs.closeSync(fd); + } + } +}; + +const moduleDir = process.env.QUANT_CLI_MODULE_DIR; +if (!moduleDir) { + console.error('[quant] QUANT_CLI_MODULE_DIR not set. Cannot proceed.'); + process.exit(1); +} + +const toNumber = (value, fallback) => { + const num = Number(value); + return Number.isFinite(num) && num > 0 ? num : fallback; +}; + +const pollIntervalSec = toNumber(process.env.QUANT_BACKUP_POLL_INTERVAL, 15); +const timeoutSec = toNumber(process.env.QUANT_BACKUP_TIMEOUT, 900); +const downloadDir = process.env.QUANT_DOWNLOAD_DIR || './downloads'; +const decompressDir = process.env.DREVOPS_DB_DIR || './.data'; +const decompressFile = process.env.DREVOPS_DB_FILE || 'db.sql'; +const appName = process.env.QUANT_APP_NAME || process.env.QUANT_APPLICATION || process.env.LAGOON_PROJECT || ''; +const envName = process.env.QUANT_ENVIRONMENT || ''; +const description = process.env.QUANT_BACKUP_DESCRIPTION || `Database backup triggered by ahoy download-db on ${new Date().toISOString()}`; + +const { ApiClient } = await import(pathToFileURL(path.join(moduleDir, 'utils/api.js')).href); +const client = await ApiClient.create(); + +const orgId = client.defaultOrganizationId; +const appId = appName || client.defaultApplicationId; +const envId = envName || client.defaultEnvironmentId; + +if (!orgId || !appId || !envId) { + console.error('[quant] Missing organization, application, or environment context. Use `qc login` and ensure defaults are set.'); + process.exit(1); +} + +console.error(`[quant] Creating database backup for app "${appId}" environment "${envId}"...`); + +const createResp = await client.backupManagementApi.createBackup(orgId, appId, envId, 'database', { description }); +const backup = createResp.body || {}; +const backupId = backup.id || backup.backupId; + +if (!backupId) { + console.error('[quant] API did not return a backup ID.'); + process.exit(1); +} + +const normalizeStatus = (value) => (value || '').toLowerCase(); +let lastStatus = normalizeStatus(backup.status) || 'requested'; +console.error(`[quant] Backup requested (ID: ${backupId}). Initial status: ${lastStatus}.`); + +const pollIntervalMs = Math.max(5, pollIntervalSec) * 1000; +const timeoutMs = Math.max(pollIntervalMs, timeoutSec * 1000); +const start = Date.now(); + +while (true) { + const listResp = await client.backupManagementApi.listBackups(orgId, appId, envId, 'database'); + const backups = listResp.body?.backups ?? []; + const current = backups.find((b) => (b.backupId || b.id) === backupId); + + if (current) { + const status = normalizeStatus(current.status); + if (status !== lastStatus) { + console.error(`[quant] Backup status: ${status}`); + lastStatus = status; + } + if (status === 'completed') { + console.error('[quant] Backup completed.'); + break; + } + if (status === 'failed') { + console.error('[quant] Backup failed.'); + process.exit(1); + } + } else { + console.error('[quant] Backup not yet visible in list; waiting...'); + } + + if (Date.now() - start > timeoutMs) { + console.error(`[quant] Backup did not complete within ${Math.round(timeoutMs / 1000)} seconds.`); + process.exit(1); + } + + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); +} + +console.error('[quant] Requesting download URL...'); +const downloadResp = await client.backupManagementApi.downloadBackup(orgId, appId, envId, 'database', backupId); +const downloadData = downloadResp.body || {}; +const downloadUrl = downloadData.downloadUrl; +const filename = downloadData.filename || `${backupId}.sql.gz`; + +if (!downloadUrl) { + console.error('[quant] API did not return a download URL.'); + process.exit(1); +} + +const outputDir = path.resolve(downloadDir); +fs.mkdirSync(outputDir, { recursive: true }); +const downloadPath = path.join(outputDir, filename); + +console.error(`[quant] Downloading backup to ${downloadPath}...`); +const response = await fetch(downloadUrl); +if (!response.ok || !response.body) { + console.error(`[quant] Failed to download backup: HTTP ${response.status}`); + process.exit(1); +} +const fileStream = fs.createWriteStream(downloadPath); +await pipeline(response.body, fileStream); +console.error('[quant] Download complete.'); + +const stats = fs.statSync(downloadPath); + +const decompressedPath = path.resolve(decompressDir, decompressFile); +fs.mkdirSync(path.dirname(decompressedPath), { recursive: true }); +fs.rmSync(decompressedPath, { force: true }); + +const lowerCaseFilename = filename.toLowerCase(); +const backupIsLikelyGzip = lowerCaseFilename.endsWith('.gz') || lowerCaseFilename.endsWith('.gzip') || hasGzipMagicNumber(downloadPath); + +if (backupIsLikelyGzip) { + console.error(`[quant] Decompressing backup to ${decompressedPath}...`); + await pipeline( + fs.createReadStream(downloadPath), + createGunzip(), + fs.createWriteStream(decompressedPath) + ); + console.error('[quant] Decompression complete.'); +} else { + console.error(`[quant] Backup is already uncompressed; copying to ${decompressedPath}...`); + await pipeline(fs.createReadStream(downloadPath), fs.createWriteStream(decompressedPath)); + console.error('[quant] Copy complete.'); +} + +const toShellValue = (value) => { + if (value === undefined || value === null) { + return ''; + } + if (typeof value === 'number') { + return String(value); + } + return JSON.stringify(value); +}; + +console.log(`BACKUP_ID=${toShellValue(backupId)}`); +console.log(`DOWNLOAD_PATH=${toShellValue(downloadPath)}`); +console.log(`DECOMPRESSED_PATH=${toShellValue(decompressedPath)}`); +console.log(`DOWNLOAD_SIZE_BYTES=${toShellValue(stats.size)}`); +NODE +)" +if [ -z "${NODE_OUTPUT}" ]; then + echo "Failed to download backup from Quant Cloud." >&2 + exit 1 +fi + +eval "${NODE_OUTPUT}" + +echo "Quant backup ${BACKUP_ID} downloaded to ${DOWNLOAD_PATH}" +echo "Database decompressed to ${DECOMPRESSED_PATH}" diff --git a/scripts/quant/provision-quant.sh b/scripts/quant/provision-quant.sh new file mode 100755 index 0000000000..3ddb56b7bf --- /dev/null +++ b/scripts/quant/provision-quant.sh @@ -0,0 +1,224 @@ +#!/usr/bin/env bash +## +# Run Drupal provisioning steps tailored for Quant Cloud deployments. +# +# This script runs essential deployment tasks (database updates, configuration +# import, and cache rebuild) while ensuring Drush commands execute against the +# correct Quant site URL. +# +# shellcheck disable=SC1091 + +# Load project environment variables while preserving current exports. +t=$(mktemp) && export -p >"${t}" && set -a && . ./.env && if [ -f ./.env.local ]; then . ./.env.local; fi && set +a && . "${t}" && rm "${t}" && unset t + +set -eu +[ "${DREVOPS_DEBUG-}" = "1" ] && set -x + +# Helper output functions. +note() { printf " %s\n" "${1}"; } +info() { [ "${TERM:-}" != "dumb" ] && tput colors >/dev/null 2>&1 && printf "\033[34m[INFO] %s\033[0m\n" "${1}" || printf "[INFO] %s\n" "${1}"; } +pass() { [ "${TERM:-}" != "dumb" ] && tput colors >/dev/null 2>&1 && printf "\033[32m[ OK ] %s\033[0m\n" "${1}" || printf "[ OK ] %s\n" "${1}"; } +fail() { [ "${TERM:-}" != "dumb" ] && tput colors >/dev/null 2>&1 && printf "\033[31m[FAIL] %s\033[0m\n" "${1}" || printf "[FAIL] %s\n" "${1}"; } + +DREVOPS_PROVISION_SKIP="${DREVOPS_PROVISION_SKIP:-0}" + +if [ "${DREVOPS_PROVISION_SKIP}" = "1" ]; then + pass "Skipped Quant provisioning because DREVOPS_PROVISION_SKIP=1." + exit 0 +fi + +# Detect Quant Cloud environment (variables may be set but empty). +has_quant_environment=0 +if [ -v QUANT_ENV_TYPE ] || [ -v QUANT_ENV_NAME ] || [ -v QUANT_APP_NAME ]; then + has_quant_environment=1 +fi + +if [ "${has_quant_environment}" -ne 1 ]; then + info "Quant Cloud environment not detected; nothing to do." + exit 0 +fi + +info "Detected Quant Cloud environment." + +# Prepare Drush URI using QUANT_ROUTE when available. +drush_uri="" +if [ -v QUANT_ROUTE ] && [ -n "${QUANT_ROUTE}" ]; then + case "${QUANT_ROUTE}" in + http://*|https://*) + drush_uri="${QUANT_ROUTE%/}" + info "Using QUANT_ROUTE for Drush URI: ${drush_uri}" + ;; + *) + note "QUANT_ROUTE is set but is not a full URL. Drush will fall back to the default site context." + ;; + esac +elif [ -v QUANT_ROUTE ]; then + note "QUANT_ROUTE is defined but empty. Drush will fall back to the default site context." +else + note "QUANT_ROUTE not defined. Drush will fall back to the default site context." +fi + +drush_quant() { + if [ -n "${drush_uri}" ]; then + ./vendor/bin/drush -y --uri="${drush_uri}" "$@" + else + ./vendor/bin/drush -y "$@" + fi +} + +# Check whether a comma or space separated list contains the provided token. +contains_token() { + local needle="$1" + local haystack="$2" + local token trimmed + + if [ -z "${needle}" ] || [ -z "${haystack}" ]; then + return 1 + fi + + for token in ${haystack//,/ }; do + # Remove any whitespace characters from the token to allow comma-separated + # or space-separated lists. + trimmed="${token//[[:space:]]/}" + if [ -n "${trimmed}" ] && [ "${needle}" = "${trimmed}" ]; then + return 0 + fi + done + + return 1 +} + +# Resolve the configuration source directory for the current Quant environment. +resolve_config_source() { + local env_type="$1" + local env_name="$2" + local source="${default_config_dir}" + + # Normalise case and trim accidental whitespace. + env_type="${env_type,,}" + env_name="${env_name,,}" + + # Exclude these names from mapping to development by default. + # By convention, Quant won't use these, but keep guard-rails in place. + local exclude_from_dev="${QUANT_CONFIG_ENV_NAMES_EXCLUDE_FROM_DEVELOPMENT:-ci,local}" + + # The rule that determined the mapping; used for logging. + CONFIG_SOURCE_RULE="default" + + # 1) Explicit production mapping takes precedence. + if contains_token "${env_type}" "${production_types}" || contains_token "${env_name}" "${production_names}"; then + source="${production_config_dir}" + CONFIG_SOURCE_RULE="production" + + # 2) Explicit test mapping by name next. + elif contains_token "${env_name}" "${test_names}"; then + source="${test_config_dir}" + CONFIG_SOURCE_RULE="test" + + # 3) Explicit development mapping by type/name. + elif contains_token "${env_type}" "${development_types}" || contains_token "${env_name}" "${development_names}"; then + source="${development_config_dir}" + CONFIG_SOURCE_RULE="development-explicit" + + # 4) Fallback rule: anything not 'ci' or 'local' is development. + elif ! contains_token "${env_name}" "${exclude_from_dev}"; then + source="${development_config_dir}" + CONFIG_SOURCE_RULE="development-fallback" + else + CONFIG_SOURCE_RULE="excluded-from-development" + fi + + # Print both values so caller can capture without relying on subshell state. + printf '%s\n%s' "${source}" "${CONFIG_SOURCE_RULE}" +} + +# Determine if the provided configuration directory exists and contains YAML +# files. Partial or full imports should be skipped when the directory is empty +# to avoid Drush failures. +config_dir_has_files() { + local dir="$1" + + if [ ! -d "${dir}" ]; then + return 1 + fi + + if find "${dir}" -type f -name '*.yml' -print -quit | grep -q .; then + return 0 + fi + + return 1 +} + +info "Running Drupal database updates." +drush_quant updatedb || { fail "Database updates failed."; exit 1; } +pass "Database updates complete." + +default_config_dir="${QUANT_CONFIG_DIR_DEFAULT:-config/default}" +base_config_available=0 + +if config_dir_has_files "${default_config_dir}"; then + info "Importing Drupal configuration from ${default_config_dir}." + drush_quant config:import || { fail "Configuration import failed."; exit 1; } + pass "Configuration import complete." + base_config_available=1 +else + note "Configuration directory ${default_config_dir} is missing or empty; skipping all configuration imports." +fi + +# Apply environment-specific configuration overlays only when base configuration +# exists and has been imported. +quant_env_type="${QUANT_ENV_TYPE:-}" +quant_env_name="${QUANT_ENV_NAME:-}" + +if [ "${base_config_available}" -eq 1 ] && { [ -n "${quant_env_type}" ] || [ -n "${quant_env_name}" ]; }; then + production_config_dir="${QUANT_CONFIG_DIR_PRODUCTION:-${default_config_dir}}" + development_config_dir="${QUANT_CONFIG_DIR_DEVELOPMENT:-config/dev}" + test_config_dir="${QUANT_CONFIG_DIR_TEST:-config/test}" + + production_types="${QUANT_CONFIG_ENV_TYPES_PRODUCTION:-production}" + development_types="${QUANT_CONFIG_ENV_TYPES_DEVELOPMENT:-development}" + + production_names="${QUANT_CONFIG_ENV_NAMES_PRODUCTION:-production}" + development_names="${QUANT_CONFIG_ENV_NAMES_DEVELOPMENT:-develop}" + # Default to recognise both master and uat as test environments. + test_names="${QUANT_CONFIG_ENV_NAMES_TEST:-master,uat}" + + # Capture both the resolved source and the rule without leaking subshell state. + read -r config_source CONFIG_SOURCE_RULE <<<"$(resolve_config_source "${quant_env_type}" "${quant_env_name}")" + + # Always pass an absolute path to Drush to avoid CWD/docroot ambiguity. + if [ -n "${config_source}" ] && [ "${config_source#/}" = "${config_source}" ]; then + # Convert relative path to absolute from repository root. + config_source="$(pwd -P)/${config_source#./}" + fi + + info "Resolved config overlay mapping: type='${quant_env_type:-unset}', name='${quant_env_name:-unset}' -> '${config_source}' (rule: ${CONFIG_SOURCE_RULE:-default})." + + if [ -z "${config_source}" ]; then + note "Environment-specific configuration mapping did not resolve to a directory; skipping partial import." + elif [ "${config_source}" = "${default_config_dir}" ]; then + note "Environment-specific configuration maps to ${config_source} (rule: ${CONFIG_SOURCE_RULE:-default}); base configuration already imported." + elif config_dir_has_files "${config_source}"; then + message_suffix="" + if [ -n "${quant_env_name}" ]; then + message_suffix=", name: ${quant_env_name}" + fi + info "Importing environment-specific configuration from ${config_source} (type: ${quant_env_type:-unset}${message_suffix})." + drush_quant config:import --partial --source="${config_source}" || { + fail "Environment-specific configuration import failed."; exit 1; + } + pass "Environment-specific configuration import complete." + else + note "Environment-specific configuration directory ${config_source} is missing or empty; skipping partial import." + fi +elif [ "${base_config_available}" -eq 0 ]; then + note "Skipping environment-specific configuration import because base configuration is unavailable." +else + note "QUANT environment variables not provided; skipping environment-specific configuration import." +fi + +info "Rebuilding Drupal caches." +drush_quant cache:rebuild || { fail "Cache rebuild failed."; exit 1; } +pass "Cache rebuild complete." + +pass "Quant Cloud provisioning finished successfully." From f966a9032d75aa91b16051270ed5ebd94414cbbd Mon Sep 17 00:00:00 2001 From: Joshua Fernandes Date: Fri, 3 Oct 2025 08:26:12 +0530 Subject: [PATCH 14/14] Fixed quant merge conflict - diff-e65288356485a0927532b70464ad2d038dec4fbef60839c1855b2f06ff3cf88c --- web/sites/default/settings.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/sites/default/settings.php b/web/sites/default/settings.php index b98ad3a1c4..dfda31c4df 100644 --- a/web/sites/default/settings.php +++ b/web/sites/default/settings.php @@ -99,7 +99,6 @@ // URL when accessed from Behat tests. '^nginx$', ]; -$settings['trusted_host_patterns'][] = '^.+\.apps\.quantgovsites\.com$'; // Modules excluded from config export. $settings['config_exclude_modules'] = [];