{"id":13513853,"url":"https://github.com/mojotech/torch","last_synced_at":"2025-05-13T19:17:02.562Z","repository":{"id":38361236,"uuid":"61840955","full_name":"mojotech/torch","owner":"mojotech","description":"A rapid admin generator for Elixir \u0026 Phoenix","archived":false,"fork":false,"pushed_at":"2025-04-21T16:01:42.000Z","size":3802,"stargazers_count":1142,"open_issues_count":14,"forks_count":81,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-04-28T10:55:44.532Z","etag":null,"topics":["admin","phoenix"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mojotech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-06-23T22:28:34.000Z","updated_at":"2025-04-18T12:58:08.000Z","dependencies_parsed_at":"2023-09-26T17:59:22.560Z","dependency_job_id":"be7fdc21-7a3d-482d-ac02-67ef764cf30a","html_url":"https://github.com/mojotech/torch","commit_stats":{"total_commits":450,"total_committers":34,"mean_commits":"13.235294117647058","dds":0.6244444444444445,"last_synced_commit":"86f4125743369b420d01e296411044132e9ed600"},"previous_names":["infinitered/torch"],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mojotech%2Ftorch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mojotech%2Ftorch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mojotech%2Ftorch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mojotech%2Ftorch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mojotech","download_url":"https://codeload.github.com/mojotech/torch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254010826,"owners_count":21999004,"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":["admin","phoenix"],"created_at":"2024-08-01T05:00:38.777Z","updated_at":"2025-05-13T19:17:02.525Z","avatar_url":"https://github.com/mojotech.png","language":"Elixir","readme":"[![License](https://img.shields.io/hexpm/l/torch.svg)](https://github.com/mojotech/torch/blob/master/LICENSE)\n[![Hex.pm](https://img.shields.io/hexpm/v/torch.svg)](https://hex.pm/packages/torch)\n[![Build Status](https://github.com/mojotech/torch/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/mojotech/torch/actions/workflows/ci.yml)\n[![Coverage Status](https://coveralls.io/repos/github/mojotech/torch/badge.svg?branch=master)](https://coveralls.io/github/mojotech/torch?branch=master)\n\n# Torch\n\n\u003e This version of Torch (5.x) only supports Phoenix 1.7 and above and is not fully backwards-compatible with\n\u003e previous versions of Torch.  See [UPGRADING](./UPGRADING.md) for more details.\n\n\u003e See [v4.0](https://github.com/mojotech/torch/tree/v4) if you need support for Phoenix 1.6\n\n\u003e See [v3.0](https://github.com/mojotech/torch/tree/v3) if you need support for Phoenix 1.5 and below\n\n\nTorch is a rapid admin generator for Phoenix applications. It creates custom templates and relies\non the Phoenix HTML generator under the hood.\n\n![image](https://user-images.githubusercontent.com/7085617/36333572-70e3907e-132c-11e8-9ad2-bd5e98aadc7c.png)\n\n## Requirements\n\n* [Phoenix Framework 1.7+](https://hex.pm/packages/phoenix)\n* [Elixir 1.14+](https://elixir-lang.org/install.html)\n* [OTP 24+](https://www.erlang.org/downloads)\n\n## Upgrading\n\nIf you are upgrading from Torch v4 (or earlier) you can find additional documentation in the [UPGRADING](UPGRADING.md) file.\n\n## Installation\n\nTo install Torch, perform the following steps:\n\n1. Add `torch` to your list of dependencies in `mix.exs`. Then, run `mix deps.get`:\n\n```elixir\ndef deps do\n  [\n    {:torch, \"~\u003e 5.5\"}\n  ]\nend\n```\n\n2. Add a `Plug.Static` plug to your `endpoint.ex`:\n\n```elixir\nplug(\n  Plug.Static,\n  at: \"/torch\",\n  from: {:torch, \"priv/static\"},\n  gzip: true,\n  cache_control_for_etags: \"public, max-age=86400\",\n  headers: [{\"access-control-allow-origin\", \"*\"}]\n)\n```\n\n3. Configure Torch by adding the following to your `config.exs`.\n\n```elixir\nconfig :torch,\n  otp_app: :my_app_name\n```\n\n4. Run `mix torch.install`\n\nNow you're ready to start generating your admin! :tada:\n\n## Usage\n\nTorch uses [Phoenix generators](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Html.html) under the hood. Torch injects it's own custom templates\ninto your `priv/static` directory, then runs the `mix phx.gen.html` task with the options\nyou passed in. Finally, it uninstalls the custom templates so they don't interfere with\nrunning the plain Phoenix generators.\n\nIn light of that fact, the `torch.gen.html` task takes all the same arguments as the `phx.gen.html`,\nbut does some extra configuration on either end. Checkout `mix help phx.gen.html` for more details\nabout the supported options and format.\n\nFor example, if we wanted to generate a blog with a `Post` model we could run the following command:\n\n```bash\n# mix torch.gen.html \u003cContext Module\u003e \u003cSchema Module\u003e \u003cSchema Table Name\u003e [\u003cColumn Name\u003e:\u003cColumn Type\u003e]+\n$ mix torch.gen.html Blog Post posts title:string body:text published_at:datetime published:boolean views:integer\n```\n\nThe output would look like:\n\n```\n* creating priv/templates/phx.gen.html/edit.html.heex\n* creating priv/templates/phx.gen.html/form.html.heex\n...\u003comitted for brevity\u003e...\n* injecting test/phx1_6/blog_test.exs\n* injecting test/support/fixtures/blog_fixtures.ex\n\nAdd the resource to your browser scope in lib/phx1_6_web/router.ex:\n\n    resources \"/posts\", PostController\n\n\nRemember to update your repository by running migrations:\n\n    $ mix ecto.migrate\n\nEnsure the following is added to your endpoint.ex:\n\n    plug(\n      Plug.Static,\n      at: \"/torch\",\n      from: {:torch, \"priv/static\"},\n      gzip: true,\n      cache_control_for_etags: \"public, max-age=86400\",\n      headers: [{\"access-control-allow-origin\", \"*\"}]\n    )\n\nAlso don't forget to add a link to layouts/torch.html if desired.\n\n    \u003cnav class=\"torch-nav\"\u003e\n      \u003c!-- nav links here --\u003e\n    \u003c/nav\u003e\n\n```\n\nTorch also installed an admin layout into your `my_app_web/templates/layout/torch.html.heex`.\nYou will want to update it to include your new navigation link:\n\n```html\n\u003cnav class=\"torch-nav\"\u003e\n  \u003ca href=\"/posts\"\u003ePosts\u003c/a\u003e\n\u003c/nav\u003e\n```\n\nThere may be times when you are adding Torch into an already existing system\nwhere your application already contains the modules and controllers and you just\nwant to use the Torch admin interface. Since the `torch.gen` mix tasks are just\nwrappers around the existing `phx.gen` tasks, you can use most of the same\nflags. To add an admin interface for `Posts` in the previous example, where the\nmodel and controller modules already exist, use the following command:\n\n```bash\n$ mix torch.gen.html Blog Post posts --no-schema --no-context --web Admin title:string body:text published_at:datetime published:boolean views:integer\n```\n\n### Torch.Pagination customization\n\nThe following assumes you the above example when running `torch.gen.html`.\n\nBy default, the Torch generators added the following code to your `Blog` context module:\n\n```elixir\n# blog.ex\n\n  use Torch.Pagination,\n    repo: MyApp.Repo,\n    model: MyApp.Blog.Post,\n    name: :posts\n\n```\n\nPlease refer to [the `Torch.Pagination` module for documentation](https://hexdocs.pm/torch/Torch.Pagination.html) on how to customize the pagination options for each model,\nor globally for your whole application.\n\n**NOTE** If you want to customize the pagination functions themselves for your application, do not use the default `Torch.Pagination` as described above; instead you will need to define your own `paginate_*/2` method that will return a `Scrivener.Page` object.  You can also define your own pagination system and functions as well, but that will require further customization of the generated Torch controllers as well.\n\n### Association filters\n\nTorch does not support association filters at this time. [Filtrex](https://github.com/rcdilorenzo/filtrex) does not yet support them.\n\nYou can checkout these two issues to see the latest updates:\n\nhttps://github.com/rcdilorenzo/filtrex/issues/55\n\nhttps://github.com/rcdilorenzo/filtrex/issues/38\n\nHowever, that does not mean you can't roll your own.\n\n**Example**\n\nWe have a `Accounts.User` model that `has_many :credentials, Accounts.Credential` and we want to support filtering users\nby `credentials.email`.\n\n1. Update the `Accounts` domain.\n\n```elixir\n# accounts.ex\n...\ndefp do_paginate_users(filter, params) do\n  credential_params = Map.get(params, \"credentials\")\n  params = Map.drop(params, [\"credentials\"])\n\n  User\n  |\u003e Filtrex.query(filter)\n  |\u003e credential_filters(credential_params)\n  |\u003e order_by(^sort(params))\n  |\u003e paginate(Repo, params, @pagination)\nend\n\ndefp credential_filters(query, nil), do: query\n\ndefp credential_filters(query, params) do\n  search_string = \"%#{params[\"email\"]}%\"\n\n  from(u in query,\n    join: c in assoc(u, :credentials),\n    where: like(c.email, ^search_string),\n    group_by: u.id\n  )\nend\n...\n```\n\n2. Update form filters.\n\n```eex\n# users/index.html.heex\n\u003cdiv class=\"field\"\u003e\n  \u003clabel\u003eCredential email\u003c/label\u003e\n  \u003c%= text_input(:credentials, :email, value: maybe(@conn.params, [\"credentials\", \"email\"])) %\u003e\n\u003c/div\u003e\n```\n\nNote: You'll need to install \u0026 import `Maybe` into your views `{:maybe, \"~\u003e 1.0.0\"}` for\nthe above `heex` to work.\n\n## Styling\n\nTorch generates two CSS themes you can use: `base.css` \u0026 `theme.css`.\nThe base styles are basically bare bones, and the theme styles look like the screenshot\nabove. Just change the stylesheet link in the `torch.html.heex` layout.\n\nIf you want to use the theme, but override the colors, you'll need to include your\nown stylesheet with the specific overrides.\n\n## Internationalization\n\nTorch comes with `.po` files for several locales. If you are using\nTorch and can provide us with translation files for other languages, please\nsubmit a Pull Request with the translation file. We'd love to add as many\ntranslations as possible.\n\nIf you wish to add your own customized translations, you can configure Torch to\nuse your own custom `MessagesBackend` and adding it in your Torch configuration\nsettings in `config.exs`. You can find the all messages that can be customized\nin the default [i18n/backend.ex](lib/torch/i18n/backend.ex) file.\n\nIf you are customizing a backend for a \"standard\" spoken language, please submit\nback a proper `.po` translation file for us to include in the official Torch\nreleases so other users can take advantage.\n\n**Example**\n\n```elixir\ndefmodule MyApp.CustomMessagesBackend do\n  def message(\"Contains\"), do: \"** CUSTOM Contains **\"\n  def message(\"Equals\"), do: \"** CUSTOM Equals ****\"\n  def message(\"\u003c Prev\"), do: \"\u003c--\"\n  def message(\"Next \u003e\"), do: \"--\u003e\"\n\n  # You can add a fallback so it won't break with newly added messages or\n  # messages you did not customize\n  def message(text), do: Torch.I18n.Backend.message(text)\nend\n```\n\n```elixir\n# config.exs\nconfig :torch,\n  otp_app: :my_app_name,\n  i18n_backend: MyApp.CustomMessagesBackend\n```\n\n# Development\n\n## Getting Started\n\nTorch currently uses Node 18 to build its assets.\n\n### Building the Torch asset bundles\n\nThe JavaScript bundle is output to `priv/static/torch.js`, and the CSS bundles are\noutput to `priv/static/base.css` and `priv/static/theme.css`.\n\nTo build the bundles navigate to the `assets` folder and run the following commands:\n\n```bash\n$ cd assets\n$ npm i\n$ npm run compile\n```\n","funding_links":[],"categories":["Elixir","\u003ca name=\"Elixir\"\u003e\u003c/a\u003eElixir"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmojotech%2Ftorch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmojotech%2Ftorch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmojotech%2Ftorch/lists"}