diff --git a/config/acquia_dev/config_ignore.settings.yml b/config/acquia_dev/config_ignore.settings.yml
index 8a1703ea7b..05bc18d297 100644
--- a/config/acquia_dev/config_ignore.settings.yml
+++ b/config/acquia_dev/config_ignore.settings.yml
@@ -4,7 +4,9 @@ ignored_config_entities:
- bos_city_score.settings
- bos_core.settings
- bos_emergency_alerts.settings
+ - 'bos_feedback_form:handlers.post_to_zencity.settings.*'
- bos_google_cloud.settings
+ - bos_google_cloud.prompts
- bos_mnl.settings
- bos_swiftype.settings
- 'core.entity_view_display.node.metrolist_development.*'
diff --git a/config/acquia_dev/samlauth.authentication.yml b/config/acquia_dev/samlauth.authentication.yml
index 463052cebc..14f9d2829e 100644
--- a/config/acquia_dev/samlauth.authentication.yml
+++ b/config/acquia_dev/samlauth.authentication.yml
@@ -25,10 +25,10 @@ sp_new_certificate: ''
sp_private_key: ''
metadata_valid_secs: 60
metadata_cache_http: false
-idp_entity_id: 'urn:test:sso:boston.gov'
-idp_single_sign_on_service: 'https://sso-test.boston.gov/idp/SSO.saml2'
-idp_single_log_out_service: 'https://sso-test.boston.gov/idp/startSLO.ping'
-idp_change_password_service: 'https://access-test.boston.gov/change-password'
+idp_entity_id: 'urn:sso:boston.gov'
+idp_single_sign_on_service: 'https://sso.boston.gov/idp/SSO.saml2'
+idp_single_log_out_service: 'https://sso.boston.gov/idp/startSLO.ping'
+idp_change_password_service: 'https://access.boston.gov/change-password'
idp_certs:
- 'key:iam_dir_sso_test_'
idp_cert_encryption: ''
diff --git a/config/acquia_prod/config_ignore.settings.yml b/config/acquia_prod/config_ignore.settings.yml
index c8cf50b5dc..b586d5a4b7 100644
--- a/config/acquia_prod/config_ignore.settings.yml
+++ b/config/acquia_prod/config_ignore.settings.yml
@@ -4,7 +4,9 @@ ignored_config_entities:
- bos_city_score.settings
- bos_core.settings
- bos_emergency_alerts.settings
+ - 'bos_feedback_form:handlers.post_to_zencity.settings.*'
- bos_google_cloud.settings
+ - bos_google_cloud.prompts
- bos_mnl.settings
- bos_swiftype.settings
- 'core.entity_view_display.node.metrolist_development.*'
diff --git a/config/acquia_prod/redirect_domain.domains.yml b/config/acquia_prod/redirect_domain.domains.yml
index 38bc5c91ea..d5839630a2 100644
--- a/config/acquia_prod/redirect_domain.domains.yml
+++ b/config/acquia_prod/redirect_domain.domains.yml
@@ -8,11 +8,11 @@ domain_redirects:
'budget:boston:gov':
-
sub_path: /*
- destination: www.boston.gov/finance/fiscal-year-2024
+ destination: www.boston.gov/finance/fiscal-year-2025
'budgets:boston:gov':
-
sub_path: /*
- destination: www.boston.gov/finance/fiscal-year-2024
+ destination: www.boston.gov/finance/fiscal-year-2025
'permits:boston:gov':
-
sub_path: /*
diff --git a/config/acquia_stage/config_ignore.settings.yml b/config/acquia_stage/config_ignore.settings.yml
index 98043526eb..2bf8e3317c 100644
--- a/config/acquia_stage/config_ignore.settings.yml
+++ b/config/acquia_stage/config_ignore.settings.yml
@@ -4,7 +4,9 @@ ignored_config_entities:
- bos_city_score.settings
- bos_core.settings
- bos_emergency_alerts.settings
+ - 'bos_feedback_form:handlers.post_to_zencity.settings.*'
- bos_google_cloud.settings
+ - bos_google_cloud.prompts
- bos_mnl.settings
- bos_swiftype.settings
- 'core.entity_view_display.node.metrolist_development.*'
diff --git a/config/acquia_stage/samlauth.authentication.yml b/config/acquia_stage/samlauth.authentication.yml
index 25f6cd96ad..33aeb584d0 100644
--- a/config/acquia_stage/samlauth.authentication.yml
+++ b/config/acquia_stage/samlauth.authentication.yml
@@ -25,10 +25,10 @@ sp_new_certificate: ''
sp_private_key: ''
metadata_valid_secs: 60
metadata_cache_http: false
-idp_entity_id: 'urn:test:sso:boston.gov'
-idp_single_sign_on_service: 'https://sso-test.boston.gov/idp/SSO.saml2'
-idp_single_log_out_service: 'https://sso-test.boston.gov/idp/startSLO.ping'
-idp_change_password_service: 'https://access-test.boston.gov/change-password'
+idp_entity_id: 'urn:sso:boston.gov'
+idp_single_sign_on_service: 'https://sso.boston.gov/idp/SSO.saml2'
+idp_single_log_out_service: 'https://sso.boston.gov/idp/startSLO.ping'
+idp_change_password_service: 'https://access.boston.gov/change-password'
idp_certs:
- 'key:iam_dir_sso_test_'
idp_cert_encryption: ''
diff --git a/config/default/block.block.bos_theme_feedbackform.yml b/config/default/block.block.bos_theme_feedbackform.yml
new file mode 100644
index 0000000000..d4f6b9d01f
--- /dev/null
+++ b/config/default/block.block.bos_theme_feedbackform.yml
@@ -0,0 +1,28 @@
+uuid: 9d6fda0b-6462-4ed5-a6cd-319a833771f1
+langcode: en
+status: true
+dependencies:
+ module:
+ - bos_feedback_form
+ - system
+ theme:
+ - bos_theme
+id: bos_theme_feedbackform
+theme: bos_theme
+region: content
+weight: 10
+provider: null
+plugin: feedback_form
+settings:
+ id: feedback_form
+ label: 'Feedback Form'
+ label_display: '0'
+ provider: bos_feedback_form
+ feedback_button_title: 'Provide Your Feedback'
+ feedback_wrapper_css: ta--c
+ feedback_button_css: ''
+visibility:
+ request_path:
+ id: request_path
+ negate: true
+ pages: "/buildinghousing/*\r\n/buildinghousing-map\r\n/metrolist*\r\n/metrolist/*\r\n/departments/mayors-office/green-new-deal-dashboard\r\n/admin*\r\n/user*\r\n/departments/registry-birth-death-and-marriage"
diff --git a/config/default/block.block.ml_listing_entry.yml b/config/default/block.block.ml_listing_entry.yml
index a988b52b40..c2103fda14 100644
--- a/config/default/block.block.ml_listing_entry.yml
+++ b/config/default/block.block.ml_listing_entry.yml
@@ -12,7 +12,7 @@ dependencies:
id: ml_listing_entry
theme: bos_theme
region: content
-weight: 0
+weight: -1
provider: null
plugin: webform_block
settings:
diff --git a/config/default/block.block.website_feedback_form.yml b/config/default/block.block.website_feedback_form.yml
index 0f46c8875d..400a2f43cf 100644
--- a/config/default/block.block.website_feedback_form.yml
+++ b/config/default/block.block.website_feedback_form.yml
@@ -1,6 +1,6 @@
uuid: ff051dac-f44d-4fd4-a7bd-203d54d670e0
langcode: en
-status: true
+status: false
dependencies:
config:
- webform.webform.website_feedback_form
@@ -12,7 +12,7 @@ dependencies:
id: website_feedback_form
theme: bos_theme
region: content
-weight: 0
+weight: 1
provider: null
plugin: webform_block
settings:
diff --git a/config/default/field.field.node.program_initiative_profile.field_components.yml b/config/default/field.field.node.program_initiative_profile.field_components.yml
index 7bbf8aedc5..4c9100e6b3 100644
--- a/config/default/field.field.node.program_initiative_profile.field_components.yml
+++ b/config/default/field.field.node.program_initiative_profile.field_components.yml
@@ -7,6 +7,7 @@ dependencies:
- node.type.program_initiative_profile
- paragraphs.paragraphs_type.3_column_w_image
- paragraphs.paragraphs_type.bos311
+ - paragraphs.paragraphs_type.bos_node_search
- paragraphs.paragraphs_type.bos_signup_emergency_alerts
- paragraphs.paragraphs_type.branded_links
- paragraphs.paragraphs_type.cabinet
@@ -76,8 +77,8 @@ settings:
group_of_links_mini_grid: group_of_links_mini_grid
hero_image: hero_image
iframe: iframe
- map: map
list: list
+ map: map
news_and_announcements: news_and_announcements
newsletter: newsletter
photo: photo
@@ -89,6 +90,7 @@ settings:
commission_summary: commission_summary
branded_links: branded_links
commission_search: commission_search
+ bos_node_search: bos_node_search
embed_view: embed_view
from_library: from_library
group_of_links_quick_links: group_of_links_quick_links
@@ -104,6 +106,9 @@ settings:
bos311:
weight: -95
enabled: true
+ bos_node_search:
+ weight: 81
+ enabled: true
bos_signup_emergency_alerts:
weight: -53
enabled: true
@@ -152,6 +157,18 @@ settings:
drawers:
weight: -86
enabled: true
+ election_area_results:
+ weight: 96
+ enabled: false
+ election_candidate_results:
+ weight: 97
+ enabled: false
+ election_card:
+ weight: 98
+ enabled: false
+ election_contest_results:
+ weight: 99
+ enabled: false
election_results:
weight: -51
enabled: false
@@ -254,6 +271,9 @@ settings:
quote:
weight: -55
enabled: false
+ roll_call_vote:
+ weight: 133
+ enabled: false
seamless_doc:
weight: -42
enabled: false
diff --git a/config/default/locale.settings.yml b/config/default/locale.settings.yml
index 98358ba6ad..a3086eb275 100644
--- a/config/default/locale.settings.yml
+++ b/config/default/locale.settings.yml
@@ -12,4 +12,4 @@ translation:
overwrite_not_customized: true
update_interval_days: 0
path: sites/default/files/translations
- import_enabled: true
+ import_enabled: false
diff --git a/config/default/webform.webform.metrolist_listing.yml b/config/default/webform.webform.metrolist_listing.yml
index 69b16dbf1a..9a2d9565eb 100644
--- a/config/default/webform.webform.metrolist_listing.yml
+++ b/config/default/webform.webform.metrolist_listing.yml
@@ -1369,7 +1369,7 @@ elements: |-
class:
- m-v600
style: 'float:right;margin-bottom:1rem;'
-css: "#seal {\r\n display:none;\r\n}\r\n\r\n.webform-submission-form .sel-c {\r\n display: block; \r\n}\r\n.webform-submission-form .webform-multiple-table td {\r\n border-bottom: solid 3px;\r\n padding-left: 1.5rem;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox {\r\n -webkit-box-align: center;\r\n -ms-flex-align: center;\r\n align-items: center;\r\n display: -webkit-box;\r\n display: -ms-flexbox;\r\n -js-display: flex;\r\n display: flex;\r\n margin: 0;\r\n position: relative;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox:not(:last-child) {\r\n margin: 0 0 8px;\r\n margin: 0 0 .5rem;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n color: #091f2f;\r\n font-family: Lora,Georgia,serif;\r\n font-size: calc(16px + 4 * ((100vw - 480px) / 960));\r\n line-height: 1.2;\r\n margin: 0 7px;\r\n width: calc(100% - 42px);\r\n text-transform: none;\r\n}\r\n\r\n.webform-submission-form .ml-contact-info .js-form-type-email label,\r\n.webform-submission-form .ml-contact-info .js-form-type-textfield label,\r\n.webform-submission-form .js-form-type-checkboxes label.cb-l, \r\n.webform-submission-form .fieldset-legend {\r\n color: #091f2f;\r\n font-family: Montserrat,Arial,sans-serif;\r\n font-size: calc(14px + 2 * ((100vw - 480px) / 960));\r\n font-weight: 700;\r\n line-height: 1.4;\r\n letter-spacing: 1px;\r\n text-transform: uppercase;\r\n display: block; \r\n}\r\n.webform-submission-form ul li {\r\n background: none;\r\n}\r\n.webform-submission-form .js-webform-multiple-add {\r\n margin: 1.5rem;\r\n}\r\n\r\n.webform-submission-form .js-webform-multiple-add .form-number {\r\n padding-top: 0; \r\n}\r\n\r\n.webform-submission-form .webform-options-display-three-columns {\r\n height: 11rem; \r\n}\r\n\r\n.webform-submission-form select.error {\r\n border-color: #d22d23; \r\n}\r\n\r\n.webform-submission-data--view-mode-preview #metrolist_listing--your_contact_information summary,\r\n.webform-submission-data--view-mode-preview #metrolist_listing--select_building summary {\r\n display:none;\r\n}\r\n\r\n.hide-till-confirm {\r\n display: none;\r\n}\r\n\r\n[data-webform-wizard-current-page=\"webform_preview\"] .hide-till-confirm {\r\n display: block;\r\n}\r\n\r\n\r\n@media screen and (min-width: 768px){\r\n .webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n margin: 0 1rem;\r\n }\r\n}\r\n\r\n@media screen and (min-width: 1440px){\r\n .webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n font-size: 20px;\r\n }\r\n\r\n .webform-submission-form .ml-contact-info .js-form-type-email label,\r\n .webform-submission-form .ml-contact-info .js-form-type-textfield label,\r\n .webform-submission-form .js-form-type-checkboxes label.cb-l, \r\n .webform-submission-form .fieldset-legend { \r\n font-size: 16px;\r\n }\r\n}\r\n\r\n@media screen {\r\n .webform-submission-metrolist-listing-form .form-actions {\r\n margin-bottom: 1rem;\r\n margin-top: 1rem;\r\n }\r\n details.webform-submission-information {\r\n border: 1px solid darkgray;\r\n padding: 0 8px;\r\n }\r\n .webform-submission-information summary {\r\n color: #1871bd;\r\n }\r\n input.webform-button--submit[value=Save] {\r\n display: none;\r\n }\r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information summary::before {\r\n content: \"This form has been submitted.\";\r\n color: #d22d23;\r\n font-family: Lora,serif;\r\n display: block;\r\n } \r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information summary::after {\r\n content: \"Please request a new form to edit this property or add a new property.\";\r\n color: #58585b;\r\n font-family: Lora,serif;\r\n display: block;\r\n } \r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information span.summary::after {\r\n content: \" (click for details)\";\r\n font-size: 75%;\r\n font-family: Lora,serif;\r\n color: initial;\r\n font-style: italic;\r\n } \r\n}\r\ndiv[id^=\"metrolist_listing--i_agree2\"],\r\ninput[id^=\"edit-select-building\"],\r\ninput[id^=\"edit-your-contact-information\"],\r\ndiv[id^=\"metrolist_listing--i_agree\"] label {\r\n display:none;\r\n}\r\n\r\nlabel[for=\"edit-i-agree-agree\"] {\r\n margin: 20px 0;\r\n}\r\n\r\n#edit-i-agree--description {\r\n line-height: 35px;\r\n}\r\n\r\n#edit-actions-01 {\r\n margin-top: -3px;\r\n}\r\n\r\n.form-item-update-public-listing-information {\r\n display: none !important;\r\n}\r\n\r\n#edit-actions-01-submit {\r\n position: relative;\r\n float: right;\r\n}\r\n\r\n.webform-submission-metrolist-listing-form {\r\n display: block !important\r\n}\r\n.cb-f-wf {\r\n margin-top: 1.5rem !important;\r\n \r\n}\r\n.cb-f-wf::before {\r\n position:relative !important;\r\n top: -3px !important;\r\n left: -3px !important;\r\n}\r\n.l-wf {\r\n min-height: 18px;\r\n padding-top: 10px;\r\n}\r\n.cb-l-ws {\r\n margin: 0 10px;\r\n height: 0px;\r\n text-align: center;\r\n}\r\n.cb-dh .cb-l-ws {\r\n height: 14px;\r\n}"
+css: "#seal {\r\n display:none;\r\n}\r\n\r\n.webform-submission-form .sel-c {\r\n display: block; \r\n}\r\n.webform-submission-form .webform-multiple-table td {\r\n border-bottom: solid 3px;\r\n padding-left: 1.5rem;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox {\r\n -webkit-box-align: center;\r\n -ms-flex-align: center;\r\n align-items: center;\r\n display: -webkit-box;\r\n display: -ms-flexbox;\r\n -js-display: flex;\r\n display: flex;\r\n margin: 0;\r\n position: relative;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox:not(:last-child) {\r\n margin: 0 0 8px;\r\n margin: 0 0 .5rem;\r\n}\r\n\r\n.webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n color: #091f2f;\r\n font-family: Lora,Georgia,serif;\r\n font-size: calc(16px + 4 * ((100vw - 480px) / 960));\r\n line-height: 1.2;\r\n margin: 0 7px;\r\n width: calc(100% - 42px);\r\n text-transform: none;\r\n}\r\n\r\n.webform-submission-form .ml-contact-info .js-form-type-email label,\r\n.webform-submission-form .ml-contact-info .js-form-type-textfield label,\r\n.webform-submission-form .js-form-type-checkboxes label.cb-l, \r\n.webform-submission-form .fieldset-legend {\r\n color: #091f2f;\r\n font-family: Montserrat,Arial,sans-serif;\r\n font-size: calc(14px + 2 * ((100vw - 480px) / 960));\r\n font-weight: 700;\r\n line-height: 1.4;\r\n letter-spacing: 1px;\r\n text-transform: uppercase;\r\n display: block; \r\n}\r\n.webform-submission-form ul li {\r\n background: none;\r\n}\r\n.webform-submission-form .js-webform-multiple-add {\r\n margin: 1.5rem;\r\n}\r\n\r\n.webform-submission-form .js-webform-multiple-add .form-number {\r\n padding-top: 0; \r\n}\r\n\r\n.webform-submission-form .webform-options-display-three-columns {\r\n height: 11rem; \r\n}\r\n\r\n.webform-submission-form select.error {\r\n border-color: #d22d23; \r\n}\r\n\r\n.webform-submission-data--view-mode-preview #metrolist_listing--your_contact_information summary,\r\n.webform-submission-data--view-mode-preview #metrolist_listing--select_building summary {\r\n display:none;\r\n}\r\n\r\n.hide-till-confirm {\r\n display: none;\r\n}\r\n\r\n[data-webform-wizard-current-page=\"webform_preview\"] .hide-till-confirm {\r\n display: block;\r\n}\r\n\r\n@media screen and (max-width: 767px){\r\n .webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n margin: 0 1rem;\r\n }\r\n .webform-submission-form {\r\n min-height:600px;\r\n }\r\n}\r\n\r\n@media screen and (min-width: 768px){\r\n .webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n margin: 0 1rem;\r\n }\r\n .webform-submission-form {\r\n min-height:530px;\r\n }\r\n}\r\n\r\n@media screen and (min-width: 1440px){\r\n .webform-submission-form .form-checkboxes .js-form-type-checkbox label {\r\n font-size: 20px;\r\n }\r\n\r\n .webform-submission-form .ml-contact-info .js-form-type-email label,\r\n .webform-submission-form .ml-contact-info .js-form-type-textfield label,\r\n .webform-submission-form .js-form-type-checkboxes label.cb-l, \r\n .webform-submission-form .fieldset-legend { \r\n font-size: 16px;\r\n }\r\n}\r\n\r\n@media screen {\r\n .webform-submission-metrolist-listing-form .form-actions {\r\n margin-bottom: 1rem;\r\n margin-top: 1rem;\r\n }\r\n details.webform-submission-information {\r\n border: 1px solid darkgray;\r\n padding: 0 8px;\r\n }\r\n .webform-submission-information summary {\r\n color: #1871bd;\r\n }\r\n input.webform-button--submit[value=Save] {\r\n display: none;\r\n }\r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information summary::before {\r\n content: \"This form has been submitted.\";\r\n color: #d22d23;\r\n font-family: Lora,serif;\r\n display: block;\r\n } \r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information summary::after {\r\n content: \"Please request a new form to edit this property or add a new property.\";\r\n color: #58585b;\r\n font-family: Lora,serif;\r\n display: block;\r\n } \r\n form:not(#webform-submission-metrolist-listing-edit-form) .webform-submission-information span.summary::after {\r\n content: \" (click for details)\";\r\n font-size: 75%;\r\n font-family: Lora,serif;\r\n color: initial;\r\n font-style: italic;\r\n } \r\n}\r\ndiv[id^=\"metrolist_listing--i_agree2\"],\r\ninput[id^=\"edit-select-building\"],\r\ninput[id^=\"edit-your-contact-information\"],\r\ndiv[id^=\"metrolist_listing--i_agree\"] label {\r\n display:none;\r\n}\r\n\r\nlabel[for=\"edit-i-agree-agree\"] {\r\n margin: 20px 0;\r\n}\r\n\r\n#edit-i-agree--description {\r\n line-height: 35px;\r\n}\r\n\r\n#edit-actions-01 {\r\n margin-top: -3px;\r\n}\r\n\r\n.form-item-update-public-listing-information {\r\n display: none !important;\r\n}\r\n\r\n#edit-actions-01-submit {\r\n position: relative;\r\n float: right;\r\n}\r\n\r\n.webform-submission-metrolist-listing-form {\r\n display: block !important\r\n}\r\n.cb-f-wf {\r\n margin-top: 1.5rem !important;\r\n \r\n}\r\n.cb-f-wf::before {\r\n position:relative !important;\r\n top: -3px !important;\r\n left: -3px !important;\r\n}\r\n.l-wf {\r\n min-height: 18px;\r\n padding-top: 10px;\r\n}\r\n.cb-l-ws {\r\n margin: 0 10px;\r\n height: 0px;\r\n text-align: center;\r\n}\r\n.cb-dh .cb-l-ws {\r\n height: 14px;\r\n}"
javascript: ''
settings:
ajax: true
diff --git a/config/local/samlauth.authentication.yml b/config/local/samlauth.authentication.yml
index ba1f700613..acaad2c69d 100644
--- a/config/local/samlauth.authentication.yml
+++ b/config/local/samlauth.authentication.yml
@@ -25,10 +25,10 @@ sp_new_certificate: ''
sp_private_key: ''
metadata_valid_secs: 60
metadata_cache_http: false
-idp_entity_id: 'urn:test:sso:boston.gov'
-idp_single_sign_on_service: 'https://sso-test.boston.gov/idp/SSO.saml2'
-idp_single_log_out_service: 'https://sso-test.boston.gov/idp/startSLO.ping'
-idp_change_password_service: 'https://access-test.boston.gov/change-password'
+idp_entity_id: 'urn:sso:boston.gov'
+idp_single_sign_on_service: 'https://sso.boston.gov/idp/SSO.saml2'
+idp_single_log_out_service: 'https://sso.boston.gov/idp/startSLO.ping'
+idp_change_password_service: 'https://access.boston.gov/change-password'
idp_certs:
- 'key:iam_dir_sso_test_'
idp_cert_encryption: ''
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.menu.yml b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.menu.yml
index b2745e3497..8714893f81 100644
--- a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.menu.yml
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.menu.yml
@@ -4,3 +4,10 @@ bos_google_cloud.configForm:
parent: bos_core.admin
route_name: bos_google_cloud.configForm
weight: 3
+
+bos_google_cloud.PromptTesterForm:
+ title: 'Gen-AI Prompt Tester'
+ description: 'Prompt Tester for bos_google_cloud'
+ parent: bos_google_cloud.configForm
+ route_name: bos_google_cloud.PromptTesterForm
+ weight: 0
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.task.yml b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.task.yml
index a611a77adb..64bd75cdcf 100644
--- a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.task.yml
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.links.task.yml
@@ -3,3 +3,9 @@ bos_google_cloud.configForm:
route_name: bos_google_cloud.configForm
base_route: bos_core.admin
weight: 2
+
+bos_google_cloud.PromptTesterForm:
+ title: 'Prompt Tester'
+ route_name: bos_google_cloud.PromptTesterForm
+ base_route: bos_google_cloud.configForm
+ weight: 0
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.routing.yml b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.routing.yml
index cecb91ddeb..6618d26bcd 100644
--- a/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.routing.yml
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/bos_google_cloud.routing.yml
@@ -6,6 +6,26 @@ bos_google_cloud.configForm:
requirements:
_permission: 'administer google cloud platform'
+bos_google_cloud.PromptTesterForm:
+ path: 'admin/config/system/boston/googlecloud/prompttester'
+ defaults:
+ _form: '\Drupal\bos_google_cloud\Form\PromptTesterForm'
+ _title: 'Prompt Testing'
+ requirements:
+ _permission: 'administer google cloud platform'
+ options:
+ _admin_route: TRUE
+
+bos_google_cloud.open_PromptTesterForm:
+ path: 'admin/config/system/boston/googlecloud/prompttester_modal'
+ defaults:
+ _controller: '\Drupal\bos_google_cloud\Controller\PromptTesterFormController::openModalForm'
+ _title: 'Prompt Testing - modal'
+ requirements:
+ _permission: 'administer google cloud platform'
+ options:
+ _admin_route: TRUE
+
bos_google_cloud.endpoint:
path: '/rest/bos_google_cloud/v1/{action}'
methods: [POST,GET]
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/GcApiEndpointTester.http b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/GcApiEndpointTester.http
index da0c19fd3c..d46629fb9c 100644
--- a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/GcApiEndpointTester.http
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/GcApiEndpointTester.http
@@ -112,6 +112,18 @@ Cookie: XDEBUG_SESSION=PHPSTORM
"prompt" : "poem"
}
+### GenAI Roll Call minute summarizer
+POST https://{{host}}/rest/bos_google_cloud/v1/summarize
+Content-Type: text/json
+Accept: */*
+Cookie: XDEBUG_SESSION=PHPSTORM
+
+{
+ "text": "Councilor Ciommo called Docket #0547, message and order for a loan of $445,000.00 (Four Hundred Forty Five Thousand Dollars) for developing land for burial purposes and for constructing paths and avenues and embellishing the grounds in city-owned cemeteries, for the purposes of city departments including the Parks and Recreation Department, from the Committee on Ways and Means. No objection being heard, the matter was before the body. On motion of Councilor Ciommo, the order was read a second time and passed.",
+ "prompt": "rollcall"
+}
+
+
### GenAI - Translate Chinese
POST https://{{host}}/rest/bos_google_cloud/v1/translate
Content-Type: text/json
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/PromptTesterFormController.php b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/PromptTesterFormController.php
new file mode 100644
index 0000000000..f3ed915ec0
--- /dev/null
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Controller/PromptTesterFormController.php
@@ -0,0 +1,67 @@
+formBuilder = $formBuilder;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+ * The Drupal service container.
+ *
+ * @return static
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('form_builder')
+ );
+ }
+
+ /**
+ * Callback for opening the modal form.
+ */
+ public function openModalForm() {
+ $response = new AjaxResponse();
+
+ // Get the modal form using the form builder.
+ $modal_form = $this->formBuilder->getForm('Drupal\bos_google_cloud\Form\PromptTesterForm');
+
+ // Add an AJAX command to open a modal dialog with the form as the content.
+ $response->addCommand(new OpenModalDialogCommand('Prompt Testing/Tuning', $modal_form, ['width' => '80%']));
+
+ return $response;
+ }
+
+}
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/ConfigForm.php b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/ConfigForm.php
index 0e3e971035..43d7744637 100644
--- a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/ConfigForm.php
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/ConfigForm.php
@@ -13,6 +13,7 @@
use Drupal\bos_google_cloud\Services\GcTranslation;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
/**
* Creates a config/admin form for bos_google_cloud module.
@@ -95,6 +96,29 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
'#type' => "fieldset",
'#title' => "Prompt Settings",
"#description" => "The following are prompts which can be defined for the various services.",
+ '#description_display' => 'before',
+ 'tester' => [
+ '#type' => "link",
+ '#title' => "Prompt Tester",
+ '#weight' => 100,
+ '#url' => Url::fromRoute('bos_google_cloud.open_PromptTesterForm'),
+ '#attributes' => [
+ 'class' => ['use-ajax', 'button'],
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ // Authentication section.
+ $authenticator = new GcAuthenticator();
+ $authenticator->buildForm($form['google_cloud']['authentication_wrapper']);
+
+ // Search section
+ /**
+ * @var $search \Drupal\bos_google_cloud\Services\GcSearch
+
+ ],
],
]
diff --git a/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/PromptTesterForm.php b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/PromptTesterForm.php
new file mode 100644
index 0000000000..de24b5f7e6
--- /dev/null
+++ b/docroot/modules/custom/bos_components/modules/bos_google_cloud/src/Form/PromptTesterForm.php
@@ -0,0 +1,275 @@
+ "",
+ "summarizer" => "Summarize",
+ "rewriter" => "Rewrite",
+ "translation" => "Translate",
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormId(): string {
+ return 'bos_google_cloud_PromptTesterForm';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, FormStateInterface $form_state): array {
+
+ if ($values = $form_state->getValues()) {
+ $type = $values["type"];
+ $prompt = $values["prompt"];
+ }
+ else {
+ $type = "select";
+ $prompt = "default";
+ }
+ $type_label = self::TYPEMAP[$type];
+
+ $form = [
+ 'PromptTesterForm' => [
+ '#tree' => FALSE,
+ '#type' => 'fieldset',
+ 'type' => [
+ '#type' => 'select',
+ '#title' => $this->t('Select AI Action'),
+ '#options' => [
+ 'select' => 'Select Action',
+ 'rewriter' => 'Rewrite',
+ 'summarizer' => 'Summarize',
+ 'translation' => 'Translate',
+ ],
+ '#default_value' => $type??"select",
+ '#ajax' => [
+ 'event' => 'change',
+ 'callback' => '::ajaxCallbackPrompts',
+ 'wrapper' => 'edit-testdata',
+ ]
+ ],
+ 'testdata' => [
+ '#type' => 'container',
+ '#attributes' => [
+ 'id' => ['edit-testdata'],
+ 'style' => ['visibility: hidden'],
+ ],
+ 'prompt' => [
+ '#type' => 'select',
+ '#title' => $this->t("The $type_label prompt to use"),
+ '#default_value' => $prompt??"default",
+ '#options' => $type=="select" ? [] : $this->fetchPrompts($type),
+ ],
+ 'text' => [
+ '#type' => 'textarea',
+ '#title' => $this->t("Text to $type_label"),
+ '#default_value' => "Paste or input text here",
+ ],
+ 'submit' => [
+ '#type' => 'button',
+ '#value' => ucwords($this->t($type_label)),
+ '#ajax' => [
+ 'callback' => '::ajaxCallbackProcess',
+ 'wrapper' => 'edit-testresults',
+ ],
+
+ ],
+ 'testresults' => [
+ '#type' => 'container',
+ '#attributes' => ['id' => ['edit-testresults']],
+ ],
+ ],
+ ],
+ ];
+ return $form;
+ }
+
+ /**
+ * Ajax callback to make the input area visible.
+ *
+ * @param array $form
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *
+ * @return array
+ */
+ public function ajaxCallbackPrompts(array $form, FormStateInterface $form_state): array {
+
+ $values = $form_state->getValues();
+ $type = $values["type"];
+ $type_label = self::TYPEMAP[$type];
+
+ if ($type != "select") {
+ // Make test form visible.
+ unset($form['PromptTesterForm']['testdata']['#attributes']['style']);
+ }
+
+ return $form['PromptTesterForm']['testdata'];
+
+ }
+
+ /**
+ * Ajax callback to run the desired test against google_cloud.
+ *
+ * @param array $form
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *
+ * @return array
+ * @throws \Exception
+ */
+ public function ajaxCallbackProcess(array $form, FormStateInterface $form_state): array {
+
+ $values = $form_state->getValues();
+ $type = $values["type"];
+ $type_label = self::TYPEMAP[$type];
+
+ switch($type) {
+ case "rewriter":
+ /**
+ * @var \Drupal\bos_google_cloud\Services\GcTextRewriter $processor
+ */
+ $processor = \Drupal::service("bos_google_cloud.GcTextRewriter");
+ $processor->setExpiry(GcCacheAI::CACHE_EXPIRY_NO_CACHE);
+ $result = $processor->execute(["text"=>$values["text"], "prompt"=>$values["prompt"]]);
+ break;
+
+ case "summarizer":
+ /**
+ * @var GcTextSummarizer $processor
+ */
+ $processor = \Drupal::service("bos_google_cloud.GcTextSummarizer");
+ $processor->setExpiry(GcCacheAI::CACHE_EXPIRY_NO_CACHE);
+ $result = $processor->execute(["text" => $values["text"], "prompt"=> $values["prompt"]]);
+ break;
+
+ case "translation":
+ /**
+ * @var \Drupal\bos_google_cloud\Services\GcTranslation $processor
+ */
+ $processor = \Drupal::service("bos_google_cloud.GcTranslate");
+ $processor->setExpiry(GcCacheAI::CACHE_EXPIRY_NO_CACHE);
+ $result = $processor->execute(["text"=>$values["text"], "lang"=>$values["prompt"], "prompt"=>"default"]);
+ break;
+ }
+
+ $form["PromptTesterForm"]["testdata"] = $this->ajaxCallbackPrompts($form, $form_state);
+
+ $result = $result ?? "No result from google_cloud (Vertex)";
+ $response = $processor->response();
+ $request = $processor->request();
+ $fullprompt = $request["body"]["contents"][0]["parts"];
+ $prompt = array_pop($fullprompt)["text"];
+ $fullprompt = implode("
- ", array_column($fullprompt, "text"));
+
+ $ai_engine = $response["ai_engine"] ?? "gemini-pro";
+
+ $requestSafety = [];
+ foreach($request["body"]["safetySettings"] as $safe) {
+ $requestSafety[] = "{$safe["category"]} threshold: {$safe["threshold"]}";
+ }
+ $requestSafety = implode("
", $requestSafety);
+
+ $responseSafety = [];
+ foreach($response[$ai_engine]["ratings"] as $safety) {
+ if (!empty($safety["category"])) {
+ $responseSafety[] = "{$safety["category"]} probability: {$safety["probabilityScore"]} ({$safety["probability"]})";
+ $responseSafety[] = "{$safety["category"]} severity: {$safety["severityScore"]} ({$safety["severity"]})";
+ }
+ else {
+ $responseSafety[] = "OVERALL probability: {$safety["probabilityScore"]} ({$safety["probability"]})";
+ $responseSafety[] = "OVERALL severity: {$safety["severityScore"]} ({$safety["severity"]})";
+ }
+ }
+ $responseSafety = implode("
", $responseSafety);
+
+ $responseMetadata = [];
+ if ($response[$ai_engine]["usageMetadata"]) {
+ $responseMetadata[] = "Prompt Token Count: " . $response[$ai_engine]["usageMetadata"]["promptTokenCount"] ?? "N/A";
+ $responseMetadata[] = "Candidates Token Count: " . $response[$ai_engine]["usageMetadata"]["candidatesTokenCount"] ?? "N/A";
+ $responseMetadata[] = "Total Token Count: " . $response[$ai_engine]["usageMetadata"]["totalTokenCount"] ?? "N/A";
+ }
+ $responseMetadata[] = "Analysis time: " . (intval(($response["elapsedTime"] ?? 0) * 10000) / 10000) . " sec";
+ $responseMetadata = implode("
", $responseMetadata);
+
+ $engineConfig = [];
+ $engineConfig[] = "Temperature: {$request["body"]["generationConfig"]["temperature"]}";
+ $engineConfig[] = "Max Tokens: {$request["body"]["generationConfig"]["maxOutputTokens"]}";
+ $engineConfig[] = "TopK: {$request["body"]["generationConfig"]["topK"]}";
+ $engineConfig[] = "TopP: {$request["body"]["generationConfig"]["topP"]}";
+ $engineConfig = implode("
", $engineConfig);
+
+ $form["PromptTesterForm"]["testdata"]["testresults"] = [
+ "#type" => "container",
+ '#attributes' => ['id' => ['edit-testresults']],
+ "output" => [
+ "#type" => "fieldset",
+ "#title" => Markup::create("$type_label results"),
+ "outputtext" => [
+ "#markup" => Markup::create($result)
+ ],
+ "moreinfo" => [
+ "#type" => "details",
+ "#title" => "More Information",
+ "info" => [
+ "#markup" => "
Action | $type_label |
Full Prompt | $fullprompt |
AI Engine | $ai_engine ({$request["endpoint"]}) |
AI Engine Config | $engineConfig |
AI Post-Performance Data | " . ($responseMetadata??"N/a") . " |
Safety Parameters | " . ($requestSafety??"N/a") . " |
Reported Safety | " . ($responseSafety??"N/a") . " |