{"id":17321412,"url":"https://github.com/tompave/fun_with_flags_ui","last_synced_at":"2025-05-15T09:06:59.396Z","repository":{"id":20262000,"uuid":"88380430","full_name":"tompave/fun_with_flags_ui","owner":"tompave","description":"Web dashboard for the FunWithFlags Elixir package","archived":false,"fork":false,"pushed_at":"2025-04-01T22:15:21.000Z","size":3142,"stargazers_count":135,"open_issues_count":7,"forks_count":31,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T06:39:13.325Z","etag":null,"topics":["elixir","feature-flags","feature-toggles","phoenix-framework","plug","web-dashboard"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tompave.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-15T23:47:15.000Z","updated_at":"2025-04-01T22:15:24.000Z","dependencies_parsed_at":"2024-06-18T17:03:01.011Z","dependency_job_id":"2d0811e4-6eea-4cb2-be59-5c2dba5a9ca6","html_url":"https://github.com/tompave/fun_with_flags_ui","commit_stats":{"total_commits":246,"total_committers":6,"mean_commits":41.0,"dds":0.07317073170731703,"last_synced_commit":"a8569c993e0bb050c22ba6dc1759e6b64140bed5"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompave%2Ffun_with_flags_ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompave%2Ffun_with_flags_ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompave%2Ffun_with_flags_ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompave%2Ffun_with_flags_ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tompave","download_url":"https://codeload.github.com/tompave/fun_with_flags_ui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254302003,"owners_count":22048005,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","feature-flags","feature-toggles","phoenix-framework","plug","web-dashboard"],"created_at":"2024-10-15T13:37:22.584Z","updated_at":"2025-05-15T09:06:57.217Z","avatar_url":"https://github.com/tompave.png","language":"Elixir","readme":"# FunWithFlags.UI\n\n[![Mix Tests](https://github.com/tompave/fun_with_flags_ui/workflows/Mix%20Tests/badge.svg)](https://github.com/tompave/fun_with_flags_ui/actions?query=branch%3Amaster)\n[![Code Quality](https://github.com/tompave/fun_with_flags_ui/actions/workflows/quality.yml/badge.svg?branch=master)](https://github.com/tompave/fun_with_flags_ui/actions/workflows/quality.yml?query=branch%3Amaster)  \n[![Hex.pm](https://img.shields.io/hexpm/v/fun_with_flags_ui.svg)](https://hex.pm/packages/fun_with_flags_ui)\n\nA Web dashboard for the [FunWithFlags](https://github.com/tompave/fun_with_flags) Elixir package.\n\n![](https://raw.githubusercontent.com/tompave/fun_with_flags_ui/master/demo/demo.gif)\n\n\n## How to run\n\n`FunWithFlags.UI` is just a plug and it can be run in a number of ways.\nIt's primarily meant to be embedded in a host Plug application, either Phoenix or another Plug app.\n\n### Mounted in Phoenix\n\nThe router plug can be mounted inside the Phoenix router with [`Phoenix.Router.forward/4`](https://hexdocs.pm/phoenix/Phoenix.Router.html#forward/4).\n\n```elixir\ndefmodule MyPhoenixAppWeb.Router do\n  use MyPhoenixAppWeb, :router\n\n  pipeline :mounted_apps do\n    plug :accepts, [\"html\"]\n    plug :put_secure_browser_headers\n  end\n\n  scope path: \"/feature-flags\" do\n    pipe_through :mounted_apps\n    forward \"/\", FunWithFlags.UI.Router, namespace: \"feature-flags\"\n  end\nend\n```\n\nNote: There is no need to add `:protect_from_forgery` to the `:mounted_apps` pipeline because this package already implements CSRF protection. In order to enable it, your host application must use the `Plug.Session` plug, which is usually configured in the endpoint module in Phoenix.\n\n### Mounted in another Plug application\n\nSince it's just a plug, it can also be mounted into any other Plug application using [`Plug.Router.forward/2`](https://hexdocs.pm/plug/Plug.Router.html#forward/2).\n\n```elixir\ndefmodule Another.App do\n  use Plug.Router\n  forward \"/feature-flags\", to: FunWithFlags.UI.Router, init_opts: [namespace: \"feature-flags\"]\nend\n```\n\nNote: If your plug router uses `Plug.CSRFProtection`, `FunWithFlags.UI.Router` should be added before your CSRF protection plug because it already implements its own CSRF protection. If you declare `FunWithFlags.UI.Router` after, your CSRF plug will likely block GET requests for the JS assets of the dashboard.\n\n### Standalone\n\nAgain, because it's just a plug, it can be run [standalone](https://hexdocs.pm/plug/readme.html#supervised-handlers).\n\nIf you clone the repository, the library comes with two convenience functions to accomplish this:\n\n```elixir\n# Simple, let Cowboy sort out the supervision tree:\n{:ok, pid} = FunWithFlags.UI.run_standalone()\n\n# Uses some explicit supervision configuration:\n{:ok, pid} = FunWithFlags.UI.run_supervised()\n```\n\nThese functions come in handy for local development, and are _not_ necessary when embedding the Plug into a host application.\n\nPlease note that even though the `FunWithFlags.UI` module implements the `Application` behavior and comes with a proper `start/2` callback, this is not enabled by design and, in fact, the Mixfile doesn't declare an entry module.\n\nIf you really need to run it standalone in a reliable manner, you are encouraged to write your own supervision setup.\n\n### Security\n\nFor obvious reasons, you don't want to make this web control panel publicly accessible.\n\nThe library itself doesn't provide any auth functionality because, as a Plug, it is easier to wrap it into the authentication and authorization logic of the host application.\n\nThe easiest thing to do is to protect it with HTTP Basic Auth, provided by Plug itself.\n\nFor example, in Phoenix:\n\n```diff\ndefmodule MyPhoenixAppWeb.Router do\n  use MyPhoenixAppWeb, :router\n+ import Plug.BasicAuth\n\n  pipeline :mounted_apps do\n    plug :accepts, [\"html\"]\n    plug :put_secure_browser_headers\n+   plug :basic_auth, username: \"foo\", password: \"bar\"\n  end\n\n  scope path: \"/feature-flags\" do\n    pipe_through :mounted_apps\n    forward \"/\", FunWithFlags.UI.Router, namespace: \"feature-flags\"\n  end\nend\n```\n\n## Caveats\n\nWhile the base `fun_with_flags` library is quite relaxed in terms of valid flag names, group names and actor identifers, this web dashboard extension applies some more restrictive rules.\nThe reason is that all `fun_with_flags` cares about is that some flag and group names can be represented as an Elixir Atom, while actor IDs are just strings. Since you can use that API in your code, the library will only check that the parameters have the right type.\n\nThings change on the web, however. Think about the binary `\"Ook? Ook!\"`. In code, it can be accepted as a valid flag name:\n\n```elixir\n{:ok, true} = FunWithFlags.enable(:\"Ook? Ook!\", for_group: :\"weird, huh?\")\n```\n\nOn the web, however, the question mark makes working with URLs a bit tricky: in `http://localhost:8080/flags/Ook?%20Ook!`, the flag name will be `Ook` and the rest will be a query string.\n\nFor this reason this library enforces some stricter rules when creating flags and groups. Blank values are not allowed, `?` neither, and flag names must match `/^w+$/`.\n\n\n## Installation\n\nThe package can be installed by adding `fun_with_flags_ui` to your list of dependencies in `mix.exs`.  \nIt requires [`fun_with_flags`](https://hex.pm/packages/fun_with_flags), see its [installation documentation](https://github.com/tompave/fun_with_flags#installation) for more details.\n\n```elixir\ndef deps do\n  [{:fun_with_flags_ui, \"~\u003e 1.1\"}]\nend\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftompave%2Ffun_with_flags_ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftompave%2Ffun_with_flags_ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftompave%2Ffun_with_flags_ui/lists"}