From b22b4cfa33fbcc23750c1b016e460cf4656061a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Mon, 3 Jun 2024 16:47:57 +0100 Subject: [PATCH 01/17] fix(dbus): refresh AvailableProducts property --- service/lib/agama/dbus/software/product.rb | 8 ++++++++ service/test/agama/dbus/software/product_test.rb | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/service/lib/agama/dbus/software/product.rb b/service/lib/agama/dbus/software/product.rb index ba983232ec..7171dc2e88 100644 --- a/service/lib/agama/dbus/software/product.rb +++ b/service/lib/agama/dbus/software/product.rb @@ -23,7 +23,9 @@ require "suse/connect" require "agama/dbus/base_object" require "agama/dbus/interfaces/issues" +require "agama/dbus/clients/locale" require "agama/registration" +require "agama/ui_locale" module Agama module DBus @@ -241,6 +243,7 @@ def register_callbacks # software related issues. backend.registration.on_change { issues_properties_changed } backend.registration.on_change { registration_properties_changed } + UILocale.new(Clients::Locale.instance) { product_properties_changed } end def registration_properties_changed @@ -248,6 +251,11 @@ def registration_properties_changed interfaces_and_properties[REGISTRATION_INTERFACE], []) end + def product_properties_changed + dbus_properties_changed(PRODUCT_INTERFACE, + interfaces_and_properties[PRODUCT_INTERFACE], []) + end + # Result from calling to SUSE connect. # # @raise [Exception] if an unexpected error is found. diff --git a/service/test/agama/dbus/software/product_test.rb b/service/test/agama/dbus/software/product_test.rb index 72e1ee7438..4a1fc94f0e 100644 --- a/service/test/agama/dbus/software/product_test.rb +++ b/service/test/agama/dbus/software/product_test.rb @@ -24,6 +24,8 @@ require "agama/config" require "agama/registration" require "agama/software/manager" +require "agama/ui_locale" +require "agama/dbus/clients/locale" require "suse/connect" describe Agama::DBus::Software::Product do @@ -37,8 +39,16 @@ let(:target_dir) { Dir.mktmpdir } + let(:locale_client) do + instance_double( + Agama::DBus::Clients::Locale, + ui_locale: "en_US.UTF-8", on_ui_locale_change: nil + ) + end + before do stub_const("Agama::Software::Manager::TARGET_DIR", target_dir) + allow(Agama::DBus::Clients::Locale).to receive(:instance).and_return(locale_client) allow(config).to receive(:products).and_return(products) allow(subject).to receive(:dbus_properties_changed) allow(Agama::ProductReader).to receive(:new).and_call_original @@ -49,7 +59,7 @@ end let(:products) do - { "Tumbleweed" => {}, "ALP-Dolomite" => {} } + { "Tumbleweed" => {}, "MicroOS" => {} } end it "defines Product D-Bus interface" do @@ -83,7 +93,7 @@ context "if the current product is registered" do before do - subject.select_product("Leap16") + subject.select_product("MicroOS") allow(backend.registration).to receive(:reg_code).and_return("123XX432") end From 28bf29685189332dbbde861a92738ff7bad2eafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 21 Jun 2024 13:56:17 +0100 Subject: [PATCH 02/17] feat(dbus): use a explicit method to change the locale --- service/lib/agama/dbus/clients/software.rb | 2 + service/lib/agama/dbus/clients/storage.rb | 2 + service/lib/agama/dbus/clients/with_locale.rb | 42 +++++++++++++++ service/lib/agama/dbus/interfaces/locale.rb | 52 +++++++++++++++++++ service/lib/agama/dbus/manager.rb | 8 +++ service/lib/agama/dbus/manager_service.rb | 3 -- service/lib/agama/dbus/software/manager.rb | 8 +++ service/lib/agama/dbus/software/product.rb | 2 - service/lib/agama/dbus/software_service.rb | 40 -------------- service/lib/agama/dbus/storage/manager.rb | 6 +++ service/lib/agama/dbus/storage_service.rb | 3 -- service/lib/agama/manager.rb | 16 ++++++ service/lib/agama/software/manager.rb | 40 ++++++++++++++ service/lib/agama/storage/manager.rb | 9 ++++ .../agama/{ui_locale.rb => with_locale.rb} | 23 ++------ .../test/agama/dbus/software/product_test.rb | 9 ++-- 16 files changed, 193 insertions(+), 72 deletions(-) create mode 100644 service/lib/agama/dbus/clients/with_locale.rb create mode 100644 service/lib/agama/dbus/interfaces/locale.rb rename service/lib/agama/{ui_locale.rb => with_locale.rb} (62%) diff --git a/service/lib/agama/dbus/clients/software.rb b/service/lib/agama/dbus/clients/software.rb index aba2860f11..4e89a1c92a 100644 --- a/service/lib/agama/dbus/clients/software.rb +++ b/service/lib/agama/dbus/clients/software.rb @@ -21,6 +21,7 @@ require "agama/dbus/clients/base" require "agama/dbus/clients/with_issues" +require "agama/dbus/clients/with_locale" require "agama/dbus/clients/with_progress" require "agama/dbus/clients/with_service_status" @@ -29,6 +30,7 @@ module DBus module Clients # D-Bus client for software configuration class Software < Base + include WithLocale include WithIssues include WithProgress include WithServiceStatus diff --git a/service/lib/agama/dbus/clients/storage.rb b/service/lib/agama/dbus/clients/storage.rb index 03e3406f6e..f6201d1dc0 100644 --- a/service/lib/agama/dbus/clients/storage.rb +++ b/service/lib/agama/dbus/clients/storage.rb @@ -21,6 +21,7 @@ require "agama/dbus/clients/base" require "agama/dbus/clients/with_service_status" +require "agama/dbus/clients/with_locale" require "agama/dbus/clients/with_progress" require "agama/dbus/clients/with_issues" @@ -29,6 +30,7 @@ module DBus module Clients # D-Bus client for storage configuration class Storage < Base + include WithLocale include WithServiceStatus include WithProgress include WithIssues diff --git a/service/lib/agama/dbus/clients/with_locale.rb b/service/lib/agama/dbus/clients/with_locale.rb new file mode 100644 index 0000000000..08d9fd208a --- /dev/null +++ b/service/lib/agama/dbus/clients/with_locale.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright (c) [2024] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +module Agama + module DBus + module Clients + # Mixin for clients of services that define the Locale D-Bus interface + # + # Provides a method to interact with the API of the Locale interface. + # + # @note This mixin is expected to be included in a class inherited from {Clients::Base} and + # it requires a #dbus_object method that returns a {::DBus::Object} implementing the + # Locale interface. + module WithLocale + # Changes the service locale + # + # @param locale [String] new locale + def locale=(locale) + dbus_object.SetLocale(locale) + end + end + end + end +end diff --git a/service/lib/agama/dbus/interfaces/locale.rb b/service/lib/agama/dbus/interfaces/locale.rb new file mode 100644 index 0000000000..e961f55c24 --- /dev/null +++ b/service/lib/agama/dbus/interfaces/locale.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +# Copyright (c) [2024] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" +require "dbus" + +Yast.import "WFM" + +module Agama + module DBus + module Interfaces + # Mixin to define the Locale interface. + # + # @note This mixin is expected to be included in a class that inherits from {DBus::BaseObject} + # and it requires a #locale= method that sets the service's locale. + module Locale + include Yast::I18n + include Yast::Logger + + LOCALE_INTERFACE = "org.opensuse.Agama1.Locale" + + def self.included(base) + base.class_eval do + dbus_interface LOCALE_INTERFACE do + dbus_method :SetLocale, "in locale:s" do |locale| + self.locale = locale + end + end + end + end + end + end + end +end diff --git a/service/lib/agama/dbus/manager.rb b/service/lib/agama/dbus/manager.rb index 61b4df984f..19a69c359c 100644 --- a/service/lib/agama/dbus/manager.rb +++ b/service/lib/agama/dbus/manager.rb @@ -24,6 +24,7 @@ require "agama/dbus/base_object" require "agama/dbus/with_service_status" require "agama/dbus/interfaces/progress" +require "agama/dbus/interfaces/locale" require "agama/dbus/interfaces/service_status" require "agama/autoyast/converter" @@ -34,6 +35,7 @@ class Manager < BaseObject include WithServiceStatus include Interfaces::Progress include Interfaces::ServiceStatus + include Interfaces::Locale PATH = "/org/opensuse/Agama/Manager1" private_constant :PATH @@ -141,6 +143,12 @@ def service_status backend.service_status end + def locale=(locale) + safe_run do + busy_while { backend.locale = locale } + end + end + private # @return [Agama::Manager] diff --git a/service/lib/agama/dbus/manager_service.rb b/service/lib/agama/dbus/manager_service.rb index 7a9c9bf432..0f16e08fbd 100644 --- a/service/lib/agama/dbus/manager_service.rb +++ b/service/lib/agama/dbus/manager_service.rb @@ -28,7 +28,6 @@ require "agama/dbus/manager" require "agama/dbus/users" require "agama/dbus/storage/proposal" -require "agama/ui_locale" module Agama module DBus @@ -74,8 +73,6 @@ def start export # We need locale for data from users locale_client = Clients::Locale.instance - # TODO: test if we need to pass block with additional actions - @ui_locale = UILocale.new(locale_client) manager.on_progress_change { dispatch } # make single thread more responsive manager.startup_phase end diff --git a/service/lib/agama/dbus/software/manager.rb b/service/lib/agama/dbus/software/manager.rb index 21faf5e536..1ebd0b0088 100644 --- a/service/lib/agama/dbus/software/manager.rb +++ b/service/lib/agama/dbus/software/manager.rb @@ -24,6 +24,7 @@ require "agama/dbus/clients/locale" require "agama/dbus/clients/network" require "agama/dbus/interfaces/issues" +require "agama/dbus/interfaces/locale" require "agama/dbus/interfaces/progress" require "agama/dbus/interfaces/service_status" require "agama/dbus/with_service_status" @@ -37,6 +38,7 @@ class Manager < BaseObject include Interfaces::Progress include Interfaces::ServiceStatus include Interfaces::Issues + include Interfaces::Locale PATH = "/org/opensuse/Agama/Software1" private_constant :PATH @@ -134,6 +136,12 @@ def finish busy_while { backend.finish } end + def locale=(locale) + busy_while do + backend.locale = locale + end + end + private # @return [Agama::Software] diff --git a/service/lib/agama/dbus/software/product.rb b/service/lib/agama/dbus/software/product.rb index 7171dc2e88..eda6405367 100644 --- a/service/lib/agama/dbus/software/product.rb +++ b/service/lib/agama/dbus/software/product.rb @@ -25,7 +25,6 @@ require "agama/dbus/interfaces/issues" require "agama/dbus/clients/locale" require "agama/registration" -require "agama/ui_locale" module Agama module DBus @@ -243,7 +242,6 @@ def register_callbacks # software related issues. backend.registration.on_change { issues_properties_changed } backend.registration.on_change { registration_properties_changed } - UILocale.new(Clients::Locale.instance) { product_properties_changed } end def registration_properties_changed diff --git a/service/lib/agama/dbus/software_service.rb b/service/lib/agama/dbus/software_service.rb index cc0404fdf1..636bbf300b 100644 --- a/service/lib/agama/dbus/software_service.rb +++ b/service/lib/agama/dbus/software_service.rb @@ -24,7 +24,6 @@ require "agama/dbus/clients/locale" require "agama/dbus/software" require "agama/software" -require "agama/ui_locale" require "yast" Yast.import "Pkg" @@ -58,10 +57,6 @@ def start # for some reason the the "export" method must be called before # registering the language change callback to work properly export - @ui_locale = UILocale.new(Clients::Locale.instance) do |locale| - # call the language change handler - locale_handler(locale) - end end # Exports the software object through the D-Bus service @@ -94,41 +89,6 @@ def dbus_objects Agama::DBus::Software::Proposal.new(logger) ] end - - # Language change callback handler, activate new locale in the libzypp backend - # @param locale [String] the new locale - def locale_handler(locale) - language, = locale.split(".") - - # set the locale in the Language module, when changing the repository - # (product) it calls Pkg.SetTextLocale(Language.language) internally - Yast::Language.Set(language) - - # set libzypp locale (for communication only, Pkg.SetPackageLocale - # call can be used for *installing* the language packages) - Yast::Pkg.SetTextLocale(language) - - # refresh all enabled repositories to download the missing translation files - Yast::Pkg.SourceGetCurrent(true).each do |src| - Yast::Pkg.SourceForceRefreshNow(src) - end - - # remember the currently selected packages and patterns by YaST - # (ignore the automatic selections done by the solver) - # - # NOTE: we will need to handle also the tabooed and soft-locked objects - # when we allow to set them via UI or CLI - selected = Y2Packager::Resolvable.find(status: :selected, transact_by: :appl_high) - - # save and reload all repositories to activate the new translations - Yast::Pkg.SourceSaveAll - Yast::Pkg.SourceFinishAll - Yast::Pkg.SourceRestore - Yast::Pkg.SourceLoad - - # restore back the selected objects - selected.each { |s| Yast::Pkg.ResolvableInstall(s.name, s.kind) } - end end end end diff --git a/service/lib/agama/dbus/storage/manager.rb b/service/lib/agama/dbus/storage/manager.rb index 78c9c830c6..f8f1799ca3 100644 --- a/service/lib/agama/dbus/storage/manager.rb +++ b/service/lib/agama/dbus/storage/manager.rb @@ -25,6 +25,7 @@ require "y2storage/storage_manager" require "agama/dbus/base_object" require "agama/dbus/interfaces/issues" +require "agama/dbus/interfaces/locale" require "agama/dbus/interfaces/progress" require "agama/dbus/interfaces/service_status" require "agama/dbus/storage/devices_tree" @@ -48,6 +49,7 @@ class Manager < BaseObject # rubocop:disable Metrics/ClassLength include WithServiceStatus include ::DBus::ObjectManager include DBus::Interfaces::Issues + include DBus::Interfaces::Locale include DBus::Interfaces::Progress include DBus::Interfaces::ServiceStatus @@ -354,6 +356,10 @@ def iscsi_delete(path) dbus_method(:Delete, "in node:o, out result:u") { |n| iscsi_delete(n) } end + def locale=(locale) + backend.locale = locale + end + private # @return [Agama::Storage::Manager] diff --git a/service/lib/agama/dbus/storage_service.rb b/service/lib/agama/dbus/storage_service.rb index 37da268335..f4ee03f1ba 100644 --- a/service/lib/agama/dbus/storage_service.rb +++ b/service/lib/agama/dbus/storage_service.rb @@ -24,7 +24,6 @@ require "agama/dbus/clients/locale" require "agama/dbus/storage" require "agama/storage" -require "agama/ui_locale" module Agama module DBus @@ -53,8 +52,6 @@ def bus # Starts storage service. It does more then just #export method. def start export - # TODO: test if we need to pass block with additional actions - @ui_locale = UILocale.new(Clients::Locale.instance) end # Exports the storage proposal object through the D-Bus service diff --git a/service/lib/agama/manager.rb b/service/lib/agama/manager.rb index 956f46c5b0..4a48e64a16 100644 --- a/service/lib/agama/manager.rb +++ b/service/lib/agama/manager.rb @@ -23,6 +23,7 @@ require "agama/config" require "agama/network" require "agama/proxy_setup" +require "agama/with_locale" require "agama/with_progress" require "agama/installation_phase" require "agama/service_status_recorder" @@ -43,6 +44,7 @@ module Agama # other services via D-Bus (e.g., `org.opensuse.Agama.Software1`). class Manager include WithProgress + include WithLocale include Helpers include Yast::I18n @@ -79,6 +81,20 @@ def startup_phase service_status.idle end + def locale=(locale) + service_status.busy + change_process_locale(locale) + start_progress_with_descriptions( + _("Load software translations"), + _("Load storage translations") + ) + progress.step { software.locale = locale } + progress.step { storage.locale = locale } + ensure + service_status.idle + finish_progress + end + # Runs the config phase def config_phase service_status.busy diff --git a/service/lib/agama/software/manager.rb b/service/lib/agama/software/manager.rb index 3a8ef6734e..79e4b0141b 100644 --- a/service/lib/agama/software/manager.rb +++ b/service/lib/agama/software/manager.rb @@ -32,9 +32,11 @@ require "agama/software/product_builder" require "agama/software/proposal" require "agama/software/repositories_manager" +require "agama/with_locale" require "agama/with_progress" require "agama/with_issues" +Yast.import "Language" Yast.import "Package" Yast.import "Packages" Yast.import "PackageCallbacks" @@ -53,6 +55,7 @@ module Software # It shoud be splitted in separate and smaller classes. class Manager # rubocop:disable Metrics/ClassLength include Helpers + include WithLocale include WithIssues include WithProgress include Yast::I18n @@ -390,6 +393,43 @@ def product_issues issues end + # Change the locale and activate new locale in the libzypp backend + # + # @param locale [String] the new locale + def locale=(locale) + change_process_locale(locale) + language, = locale.split(".") + + # set the locale in the Language module, when changing the repository + # (product) it calls Pkg.SetTextLocale(Language.language) internally + Yast::Language.Set(language) + + # set libzypp locale (for communication only, Pkg.SetPackageLocale + # call can be used for *installing* the language packages) + Yast::Pkg.SetTextLocale(language) + + # refresh all enabled repositories to download the missing translation files + Yast::Pkg.SourceGetCurrent(true).each do |src| + Yast::Pkg.SourceForceRefreshNow(src) + end + + # remember the currently selected packages and patterns by YaST + # (ignore the automatic selections done by the solver) + # + # NOTE: we will need to handle also the tabooed and soft-locked objects + # when we allow to set them via UI or CLI + selected = Y2Packager::Resolvable.find(status: :selected, transact_by: :appl_high) + + # save and reload all repositories to activate the new translations + Yast::Pkg.SourceSaveAll + Yast::Pkg.SourceFinishAll + Yast::Pkg.SourceRestore + Yast::Pkg.SourceLoad + + # restore back the selected objects + selected.each { |s| Yast::Pkg.ResolvableInstall(s.name, s.kind) } + end + private # @return [Agama::Config] diff --git a/service/lib/agama/storage/manager.rb b/service/lib/agama/storage/manager.rb index 75046fb9d3..1d725a6b98 100644 --- a/service/lib/agama/storage/manager.rb +++ b/service/lib/agama/storage/manager.rb @@ -31,6 +31,7 @@ require "agama/storage/finisher" require "agama/storage/proposal_settings_reader" require "agama/issue" +require "agama/with_locale" require "agama/with_issues" require "agama/with_progress" require "agama/security" @@ -43,6 +44,7 @@ module Agama module Storage # Manager to handle storage configuration class Manager + include WithLocale include WithIssues include WithProgress include Yast::I18n @@ -171,6 +173,13 @@ def actions Actions.new(logger, staging.actiongraph).all end + # Changes the service's locale + # + # @param locale [String] new locale + def locale=(locale) + change_process_locale(locale) + end + private PROPOSAL_ID = "storage_proposal" diff --git a/service/lib/agama/ui_locale.rb b/service/lib/agama/with_locale.rb similarity index 62% rename from service/lib/agama/ui_locale.rb rename to service/lib/agama/with_locale.rb index 4f21dd046e..6ec4cd7773 100644 --- a/service/lib/agama/ui_locale.rb +++ b/service/lib/agama/with_locale.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) [2022] SUSE LLC +# Copyright (c) [2024] SUSE LLC # # All Rights Reserved. # @@ -24,27 +24,12 @@ Yast.import "WFM" module Agama - # Object responsible for managing changes of localization produced by D-Bus backend. - class UILocale + # Mixin that implements methods for handling with the localization + module WithLocale include Yast::I18n include Yast::Logger - # creates new UILocale object that will handle change of UI locale. - # - # @param [Agama::DBus::Clients::Locale] locale_client to communicate with dbus service - # @yield block is callback that is called when ui locale is changed - # to allow user to call methods that needs retranslation - def initialize(locale_client, &block) - @client = locale_client - change_locale(@client.ui_locale) - @client.on_ui_locale_change do |locale| - change_locale(locale) - block.call(locale) if block_given? - end - end - - private - def change_locale(locale) + def change_process_locale(locale) language, encoding = locale.split(".") Yast::WFM.SetLanguage(language, encoding) # explicitly set ENV to get localization also from libraries like libstorage diff --git a/service/test/agama/dbus/software/product_test.rb b/service/test/agama/dbus/software/product_test.rb index 4a1fc94f0e..8ca3d45787 100644 --- a/service/test/agama/dbus/software/product_test.rb +++ b/service/test/agama/dbus/software/product_test.rb @@ -24,7 +24,6 @@ require "agama/config" require "agama/registration" require "agama/software/manager" -require "agama/ui_locale" require "agama/dbus/clients/locale" require "suse/connect" @@ -40,10 +39,10 @@ let(:target_dir) { Dir.mktmpdir } let(:locale_client) do - instance_double( - Agama::DBus::Clients::Locale, - ui_locale: "en_US.UTF-8", on_ui_locale_change: nil - ) + instance_double( + Agama::DBus::Clients::Locale, + ui_locale: "en_US.UTF-8", on_ui_locale_change: nil + ) end before do From aa19a27ce68012bcfd6e898285a0caa1ce248315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 21 Jun 2024 14:44:21 +0100 Subject: [PATCH 03/17] feat(rust): use the SetLocale function --- rust/agama-lib/src/proxies.rs | 10 ++++++++++ rust/agama-server/src/l10n/web.rs | 11 +++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/rust/agama-lib/src/proxies.rs b/rust/agama-lib/src/proxies.rs index d7e5944bbd..240327ab59 100644 --- a/rust/agama-lib/src/proxies.rs +++ b/rust/agama-lib/src/proxies.rs @@ -182,3 +182,13 @@ trait Issues { #[dbus_proxy(property)] fn all(&self) -> zbus::Result>; } + +#[dbus_proxy( + interface = "org.opensuse.Agama1.Locale", + default_service = "org.opensuse.Agama.Manager1", + default_path = "/org/opensuse/Agama/Manager1" +)] +trait Locale { + /// SetLocale method + fn set_locale(&self, locale: &str) -> zbus::Result<()>; +} diff --git a/rust/agama-server/src/l10n/web.rs b/rust/agama-server/src/l10n/web.rs index 1647a50a1d..dfdab552de 100644 --- a/rust/agama-server/src/l10n/web.rs +++ b/rust/agama-server/src/l10n/web.rs @@ -7,7 +7,9 @@ use crate::{ error::Error, web::{Event, EventsSender}, }; -use agama_lib::{error::ServiceError, localization::LocaleProxy}; +use agama_lib::{ + error::ServiceError, localization::LocaleProxy, proxies::LocaleProxy as ManagerLocaleProxy, +}; use agama_locale_data::LocaleId; use axum::{ extract::State, @@ -24,6 +26,7 @@ use tokio::sync::RwLock; struct LocaleState<'a> { locale: Arc>, proxy: LocaleProxy<'a>, + manager_proxy: ManagerLocaleProxy<'a>, events: EventsSender, } @@ -37,9 +40,11 @@ pub async fn l10n_service( let id = LocaleId::default(); let locale = L10n::new_with_locale(&id).unwrap(); let proxy = LocaleProxy::new(&dbus).await?; + let manager_proxy = ManagerLocaleProxy::new(&dbus).await?; let state = LocaleState { locale: Arc::new(RwLock::new(locale)), proxy, + manager_proxy, events, }; @@ -144,7 +149,9 @@ async fn set_config( .try_into() .map_err(|_e| LocaleError::UnknownLocale(ui_locale.to_string()))?; data.translate(&locale)?; - changes.ui_locale = Some(locale.to_string()); + let locale_string = locale.to_string(); + state.manager_proxy.set_locale(&locale_string).await?; + changes.ui_locale = Some(locale_string); _ = state.events.send(Event::LocaleChanged { locale: locale.to_string(), From b56d3d51638bdb44e6ae83de64e33d380eb06fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 21 Jun 2024 14:44:54 +0100 Subject: [PATCH 04/17] feat: AvailableProducts is now a D-Bus method --- rust/agama-lib/src/software/proxies.rs | 3 +-- service/lib/agama/dbus/software/product.rb | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/agama-lib/src/software/proxies.rs b/rust/agama-lib/src/software/proxies.rs index cdb79b4829..f7762c1d43 100644 --- a/rust/agama-lib/src/software/proxies.rs +++ b/rust/agama-lib/src/software/proxies.rs @@ -80,8 +80,7 @@ trait SoftwareProduct { /// SelectProduct method fn select_product(&self, id: &str) -> zbus::Result<(u32, String)>; - /// AvailableProducts property - #[dbus_proxy(property)] + /// AvailableProducts method fn available_products(&self) -> zbus::Result>; /// SelectedProduct property diff --git a/service/lib/agama/dbus/software/product.rb b/service/lib/agama/dbus/software/product.rb index eda6405367..1c85087b8c 100644 --- a/service/lib/agama/dbus/software/product.rb +++ b/service/lib/agama/dbus/software/product.rb @@ -91,7 +91,9 @@ def select_product(id) private_constant :PRODUCT_INTERFACE dbus_interface PRODUCT_INTERFACE do - dbus_reader :available_products, "a(ssa{sv})" + dbus_method :AvailableProducts, "out result:a(ssa{sv})" do + [available_products] + end dbus_reader :selected_product, "s" From 7aa964e0108cb3bc5630ae87992a226f1d552da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Tue, 25 Jun 2024 12:54:47 +0100 Subject: [PATCH 05/17] chore(rust): make rustfmt happy --- rust/agama-server/src/network/model.rs | 2 -- rust/agama-server/src/network/nm/dbus.rs | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust/agama-server/src/network/model.rs b/rust/agama-server/src/network/model.rs index c6d6f3ba56..739a7b6c47 100644 --- a/rust/agama-server/src/network/model.rs +++ b/rust/agama-server/src/network/model.rs @@ -1314,7 +1314,6 @@ impl fmt::Display for InfinibandTransportMode { } } - #[derive(Default, Debug, PartialEq, Clone, Serialize)] pub enum TunMode { #[default] @@ -1329,7 +1328,6 @@ pub struct TunConfig { pub owner: Option, } - /// Represents a network change. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/rust/agama-server/src/network/nm/dbus.rs b/rust/agama-server/src/network/nm/dbus.rs index d5eba9a5b2..b0e66c0b77 100644 --- a/rust/agama-server/src/network/nm/dbus.rs +++ b/rust/agama-server/src/network/nm/dbus.rs @@ -543,9 +543,8 @@ fn infiniband_config_from_dbus(conn: &OwnedNestedHash) -> Option HashMap<&str, zvariant::Value> { - let mut tun_config: HashMap<&str, zvariant::Value> = HashMap::from([ - ("mode", Value::new(config.mode.clone() as u32)), - ]); + let mut tun_config: HashMap<&str, zvariant::Value> = + HashMap::from([("mode", Value::new(config.mode.clone() as u32))]); if let Some(group) = &config.group { tun_config.insert("group", group.into()); @@ -563,7 +562,6 @@ fn tun_config_from_dbus(conn: &OwnedNestedHash) -> Option { let mut tun_config = TunConfig::default(); - if let Some(mode) = tun.get("mode") { tun_config.mode = match mode.downcast_ref::()? { 2 => TunMode::Tap, From 114f718014e1471a4c6dfa335b42392333d85c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Tue, 25 Jun 2024 09:45:44 +0100 Subject: [PATCH 06/17] fix(web): move the LogsButton to the sidebar --- web/src/MainLayout.jsx | 5 ++- web/src/components/core/InstallerOptions.jsx | 3 +- web/src/components/core/LogsButton.jsx | 42 +++++++++++--------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/web/src/MainLayout.jsx b/web/src/MainLayout.jsx index 19c7ffc44d..bc9eac5b34 100644 --- a/web/src/MainLayout.jsx +++ b/web/src/MainLayout.jsx @@ -29,7 +29,7 @@ import { Toolbar, ToolbarContent, ToolbarGroup, ToolbarItem } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; -import { About, InstallerOptions } from "~/components/core"; +import { About, InstallerOptions, LogsButton } from "~/components/core"; import { _ } from "~/i18n"; import { rootRoutes } from "~/router"; import { useProduct } from "~/context/product"; @@ -81,6 +81,9 @@ const ChangeProductButton = () => { + + + ); }; diff --git a/web/src/components/core/InstallerOptions.jsx b/web/src/components/core/InstallerOptions.jsx index 6150fb50c1..fde46a51f3 100644 --- a/web/src/components/core/InstallerOptions.jsx +++ b/web/src/components/core/InstallerOptions.jsx @@ -25,7 +25,7 @@ import React, { useState } from "react"; import { useLocation } from "react-router-dom"; import { Button, Card, CardBody, Flex } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; -import { LogsButton, Popup } from "~/components/core"; +import { Popup } from "~/components/core"; import { InstallerLocaleSwitcher, InstallerKeymapSwitcher } from "~/components/l10n"; import { _ } from "~/i18n"; @@ -64,7 +64,6 @@ export default function InstallerOptions() { - {_("Close")} diff --git a/web/src/components/core/LogsButton.jsx b/web/src/components/core/LogsButton.jsx index a1ba96fa07..5034198a55 100644 --- a/web/src/components/core/LogsButton.jsx +++ b/web/src/components/core/LogsButton.jsx @@ -24,7 +24,7 @@ import { useInstallerClient } from "~/context/installer"; import { useCancellablePromise } from "~/utils"; import { Alert, Button } from "@patternfly/react-core"; -import { Icon } from "~/components/layout"; +import { Popup } from "~/components/core"; import { _ } from "~/i18n"; const FILENAME = "agama-installation-logs.tar.bzip2"; @@ -88,35 +88,41 @@ const LogsButton = ({ ...props }) => { .finally(() => setIsCollecting(false)); }; + const close = () => setError(false); + return ( <> - {isCollecting && - } + + {isCollecting && + } - {error && - } + {error && + } + + {_("Close")} + + ); }; From e68b697d1ebba42d7bb6fa454e47be44973ff920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Tue, 25 Jun 2024 12:47:48 +0100 Subject: [PATCH 07/17] feat(web): fix language switching --- web/src/components/core/InstallerOptions.jsx | 68 ++++++++++++++++++-- web/src/context/installerL10n.jsx | 4 +- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/web/src/components/core/InstallerOptions.jsx b/web/src/components/core/InstallerOptions.jsx index fde46a51f3..2e8803c2ff 100644 --- a/web/src/components/core/InstallerOptions.jsx +++ b/web/src/components/core/InstallerOptions.jsx @@ -23,11 +23,13 @@ import React, { useState } from "react"; import { useLocation } from "react-router-dom"; -import { Button, Card, CardBody, Flex } from "@patternfly/react-core"; +import { Button, Flex, Form, FormGroup, FormSelect, FormSelectOption } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; import { Popup } from "~/components/core"; -import { InstallerLocaleSwitcher, InstallerKeymapSwitcher } from "~/components/l10n"; import { _ } from "~/i18n"; +import { useInstallerL10n } from "~/context/installerL10n"; +import supportedLanguages from "~/languages.json"; +import { useL10n } from "~/context/l10n"; /** * @typedef {import("@patternfly/react-core").ButtonProps} ButtonProps @@ -39,8 +41,18 @@ import { _ } from "~/i18n"; * @todo Write documentation */ export default function InstallerOptions() { + const { + language: initialLanguage, + keymap: initialKeymap, + changeLanguage, + changeKeymap + } = useInstallerL10n(); + const [language, setLanguage] = useState(initialLanguage); + const [keymap, setKeymap] = useState(initialKeymap); + const { keymaps } = useL10n(); const location = useLocation(); const [isOpen, setIsOpen] = useState(false); + const [inProgress, setInProgress] = useState(false); // FIXME: Installer options should be available in the login too. if (location.pathname.includes("login")) return; @@ -48,6 +60,15 @@ export default function InstallerOptions() { const open = () => setIsOpen(true); const close = () => setIsOpen(false); + const onSubmit = async (e) => { + e.preventDefault(); + setInProgress(true); + changeKeymap(keymap); + changeLanguage(language) + .then(close) + .catch(() => setInProgress(false)); + }; + return ( <>