diff --git a/.dialyzer-ignore b/.dialyzer-ignore
index 78a619e1bf..527272ec2d 100644
--- a/.dialyzer-ignore
+++ b/.dialyzer-ignore
@@ -13,6 +13,7 @@ apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The pattern 'fa
apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The test 5 == 'infinity' can never evaluate to 'true'
lib/block_scout_web/router.ex:1
lib/phoenix/router.ex:324
-lib/block_scout_web/views/layout_view.ex:143
+lib/block_scout_web/views/layout_view.ex:138: The call 'Elixir.Poison.Parser':'parse!'
+lib/block_scout_web/views/layout_view.ex:224: The call 'Elixir.Poison.Parser':'parse!'
lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:21
-lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:22
\ No newline at end of file
+lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:22
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9597989a84..6708a78be3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## Current
### Features
+- [#3184](https://github.com/poanetwork/blockscout/pull/3184) - Apps navbar menu item
### Fixes
- [#3178](https://github.com/poanetwork/blockscout/pull/3178) - Fix permanent fetching tokens... when read/write proxy tab is active
diff --git a/apps/block_scout_web/assets/css/components/_dropdown.scss b/apps/block_scout_web/assets/css/components/_dropdown.scss
index a44b5386f9..5264a73902 100644
--- a/apps/block_scout_web/assets/css/components/_dropdown.scss
+++ b/apps/block_scout_web/assets/css/components/_dropdown.scss
@@ -42,6 +42,12 @@ $dropdown-menu-item-hover-background: rgba($secondary, 0.1) !default;
&:focus {
background-color: $dropdown-menu-item-hover-background;
color: $dropdown-menu-item-hover-color;
+
+ .external-link-icon {
+ path {
+ fill: $header-icon-color-hover;
+ }
+ }
}
}
diff --git a/apps/block_scout_web/assets/css/components/_navbar.scss b/apps/block_scout_web/assets/css/components/_navbar.scss
index 24efbe84f1..d97f0483d5 100644
--- a/apps/block_scout_web/assets/css/components/_navbar.scss
+++ b/apps/block_scout_web/assets/css/components/_navbar.scss
@@ -260,3 +260,18 @@ $navbar-logo-width: auto !default;
transition: none !important;
}
}
+
+.external-link-icon {
+ float: right;
+ margin-top: -1px;
+
+ & {
+ &.active,
+ &:hover,
+ &:focus {
+ path {
+ fill: $header-icon-color-hover;
+ }
+ }
+ }
+}
diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs
index b5bd4087f6..097995e969 100644
--- a/apps/block_scout_web/config/config.exs
+++ b/apps/block_scout_web/config/config.exs
@@ -32,7 +32,9 @@ config :block_scout_web,
},
other_networks: System.get_env("SUPPORTED_CHAINS"),
webapp_url: System.get_env("WEBAPP_URL"),
- api_url: System.get_env("API_URL")
+ api_url: System.get_env("API_URL"),
+ apps_menu: if(System.get_env("APPS_MENU", "false") == "true", do: true, else: false),
+ external_apps: System.get_env("EXTERNAL_APPS")
config :block_scout_web, BlockScoutWeb.Counters.BlocksIndexedCounter, enabled: true
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/icons/_external_link.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/icons/_external_link.html.eex
new file mode 100644
index 0000000000..5f9f06e568
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/templates/icons/_external_link.html.eex
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
index d54f71fb41..12575322f6 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
@@ -103,6 +103,25 @@
<% end %>
+ <%= if Application.get_env(:block_scout_web, :apps_menu) == true do %>
+
+
+
+ <%= render BlockScoutWeb.IconsView, "_apps_icon.html" %>
+
+ <%= gettext("Apps") %>
+
+
+
+ <% end %>
" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
diff --git a/apps/block_scout_web/lib/block_scout_web/views/layout_view.ex b/apps/block_scout_web/lib/block_scout_web/views/layout_view.ex
index 03dee8da28..ab3e02818b 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/layout_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/layout_view.ex
@@ -216,6 +216,21 @@ defmodule BlockScoutWeb.LayoutView do
end
end
+ def external_apps_list do
+ if Application.get_env(:block_scout_web, :external_apps) do
+ try do
+ :block_scout_web
+ |> Application.get_env(:external_apps)
+ |> Parser.parse!(%{keys: :atoms!})
+ rescue
+ _ ->
+ []
+ end
+ else
+ []
+ end
+ end
+
defp validate_url(url) when is_binary(url) do
case URI.parse(url) do
%URI{host: nil} -> :error
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index c4a0a11936..904669752d 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -1258,14 +1258,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:145
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:164
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:181
msgid "Search"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:139
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:143
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:158
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@@ -1946,3 +1946,8 @@ msgstr ""
#: lib/block_scout_web/views/address_view.ex:350
msgid "Write Proxy"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
+msgid "Apps"
+msgstr ""
diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
index c4a0a11936..904669752d 100644
--- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -1258,14 +1258,14 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:145
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:164
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:181
msgid "Search"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:139
-#: lib/block_scout_web/templates/layout/_topnav.html.eex:143
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:158
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:162
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@@ -1946,3 +1946,8 @@ msgstr ""
#: lib/block_scout_web/views/address_view.ex:350
msgid "Write Proxy"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
+msgid "Apps"
+msgstr ""
diff --git a/docker/Makefile b/docker/Makefile
index e25b1f8e33..54803b94f0 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -220,6 +220,12 @@ endif
ifdef TXS_STATS_DAYS_TO_COMPILE_AT_INIT
BLOCKSCOUT_CONTAINER_PARAMS += -e 'TXS_STATS_DAYS_TO_COMPILE_AT_INIT=$(TXS_STATS_DAYS_TO_COMPILE_AT_INIT)'
endif
+ifdef APPS_MENU
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'APPS_MENU=$(APPS_MENU)'
+endif
+ifdef EXTERNAL_APPS
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXTERNAL_APPS=$(EXTERNAL_APPS)'
+endif
HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep ${DOCKER_IMAGE})
build: