Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zorbash committed Mar 7, 2020
0 parents commit 017b7c3
Show file tree
Hide file tree
Showing 48 changed files with 2,013 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.git/
_build/
deps/
tmp/
log/
releases/
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Release archives
/releases/

/log/
# Since we are building assets from assets/,
# we ignore priv/static. You may want to comment
# this depending on your deployment strategy.
/priv/static/

# Local config file
.env

2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
erlang 21.3.2
elixir 1.9
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM elixir:1.9-slim as builder

RUN apt-get -qq update
RUN apt-get -qq install git build-essential python

WORKDIR /app

RUN mix local.hex --force && \
mix local.rebar --force && \
mix hex.info

ENV MIX_ENV prod

ADD . .
RUN mix deps.get
RUN mix release --quiet --overwrite

FROM debian:buster-slim

RUN apt-get -qq update
RUN apt-get -qq install locales libssl1.1 libtinfo5 xdg-utils

WORKDIR /app
COPY --from=builder /app/_build/prod/rel/tefter_cli .

CMD ["./bin/tefter_cli", "start"]
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CLI

The command-line client for [Tefter](https://tefter.io).

## Features

### Search

![search](https://i.imgur.com/y6KtJ2g.png)

### Aliases

![aliases](https://i.imgur.com/LB6LbHP.png)

### Bookmarks

![bookmarks](https://i.imgur.com/kVvM4kN.png)

**Filtering**

![filtering](https://i.imgur.com/LCWynDP.png)

**Commands**

![commands](https://i.imgur.com/6arscF3.png)

**Modals**

Use the `:s` command to display more details about the bookmark under the cursor.

![modals](https://i.imgur.com/p5YIIza.png)

## Usage

![usage](https://i.imgur.com/dGbncJY.png)

## Running Locally

First, ensure you have the following versions of Elixir and OTP installed on your machine.

```
erlang 21.3.2
elixir 1.9
```

Then, run:

```shell
git clone git@github.com:tefter/cli.git
mix deps.get
mix run --no-halt
```

## Releasing

You can build portable [releases](https://hexdocs.pm/mix/Mix.Tasks.Release.html) per platform,
which include the Erlang VM and don't require installing Erlang / Elixir on the target system.

### Linux

Run:

```shell
./bin/release_linux
```

### MacOS

Run:

```shell
./bin/release_macos
```
16 changes: 16 additions & 0 deletions bin/release_linux
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

docker build -t cli .
docker cp $(docker create cli:latest):/app ./releases/tefter_linux_x86_64

cat > ./releases/tefter_linux_x86_64/tefter <<- "EOF"
./bin/tefter_cli start
EOF

chmod u+x ./releases/tefter_linux_x86_64/tefter
cd releases
tar -zcf linux_x86_64.tar.gz ./tefter_linux_x86_64/

rm -rf ./tefter_linux_x86_64

echo Done!
18 changes: 18 additions & 0 deletions bin/release_macos
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

os="$(uname -s)"

test "$os" != 'Darwin' && (echo 'MacOS released must be built on a MacOS system, sorry.'; exit 1)

MIX_ENV=prod mix release --quiet --overwrite

cat > _build/prod/rel/tefter_cli/tefter <<- "EOF"
./bin/tefter_cli start
EOF

chmod u+x _build/prod/rel/tefter_cli/tefter
cd _build/prod/rel/tefter_cli
echo $PWD
zip -rq ./../../../../releases/macos.zip .

echo Done!
38 changes: 38 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for
# third-party users, it should be done in your "mix.exs" file.

# You can configure your application as:
#
# config :tefter_cli, key: :value
#
# and access this configuration in your application as:
#
# Application.get_env(:tefter_cli, :key)
#
# You can also configure a third-party app:
#
config :logger,
backends: [
{LoggerFileBackend, :dev}
]

config :logger, :dev,
path: "log/dev.log",
level: :debug

config :porcelain, goon_warn_if_missing: false

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
import_config "#{Mix.env()}.exs"
1 change: 1 addition & 0 deletions config/dev.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use Mix.Config
7 changes: 7 additions & 0 deletions config/prod.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use Mix.Config

config :logger, backends: []

config :logger, :dev,
path: "log/dev.log",
level: :error
49 changes: 49 additions & 0 deletions lib/tefter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule Tefter do
@moduledoc """
API client for Tefter
See: https://tefter.io/docs/api
"""

use Tesla

alias TefterCli.Authentication

plug(Tefter.BaseUrlMiddleware, &base_url/0)
plug(Tesla.Middleware.Headers, [{"accept", "application/json"}])
plug(Tefter.TefterAuthenticationMiddleware, &Authentication.token/0)
plug(Tesla.Middleware.JSON)

def suggestions(%{query: prefix}) do
get("/suggestions", query: %{prefix: prefix})
end

def aliases do
get("/aliases")
end

def create_bookmark(%{url: url}) do
post("/api/bookmarks", %{url: url})
end

def delete_bookmark(%{id: id}) do
delete("/bookmarks/#{id}")
end

def bookmarks do
get("/bookmarks")
end

def bookmarks_export do
get("/export/bookmarks")
end

def create_alias(%{url: url, alias: alias}) do
post("/aliases/create_from_extension", %{url: url, name: alias})
end

def delete_alias(%{id: id}) do
delete("/aliases/#{id}")
end

def base_url, do: "https://tefter.io"
end
5 changes: 5 additions & 0 deletions lib/tefter/base_url_middleware.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defmodule Tefter.BaseUrlMiddleware do
def call(env, next, fun) do
Tesla.Middleware.BaseUrl.call(env, next, fun.())
end
end
9 changes: 9 additions & 0 deletions lib/tefter/tesla_authentication_middleware.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Tefter.TefterAuthenticationMiddleware do
@auth_header "X-User-Token"

def call(env, next, fun) do
env
|> Tesla.put_header(@auth_header, fun.())
|> Tesla.run(next)
end
end
9 changes: 9 additions & 0 deletions lib/tefter_cli.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule TefterCli do
@moduledoc """
Documentation for TefterCli.
"""

@version "0.1.0"

def version, do: @version
end
46 changes: 46 additions & 0 deletions lib/tefter_cli/app.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule TefterCli.App do
@moduledoc """
The main module of the application.
It delegates rendering and state updates to a module per tab.
"""

@behaviour Ratatouille.App

alias Ratatouille.Runtime.{Subscription}
alias TefterCli.App.State
alias TefterCli.Views.{Search, Bookmarks, Lists, Aliases, Authentication, Help}

@tabs [:search, :aliases, :bookmarks, :help]

@impl true
def init(_), do: State.init()

@impl true
def update(state, msg), do: State.update(state, msg)

@impl true
def render(%{token: nil} = state), do: Authentication.render(state)
def render(%{tab: :search} = state), do: Search.render(state)
def render(%{tab: :bookmarks} = state), do: Bookmarks.render(state)
def render(%{tab: :aliases} = state), do: Aliases.render(state)
def render(%{tab: :lists} = state), do: Lists.render(state)
def render(%{tab: :help} = state), do: Help.render(state)

@doc "Returns the available application tabs"
def tabs, do: @tabs

@impl true
def subscribe(%{token: nil}), do: Subscription.interval(500, :check_token)
def subscribe(_), do: Subscription.interval(100_000, :check_token)

@doc "Returns the module responsible for the given tab"
def view(type) do
case type do
:search -> Search
:bookmarks -> Bookmarks
:lists -> Lists
:aliases -> Aliases
:help -> Help
end
end
end
Loading

0 comments on commit 017b7c3

Please sign in to comment.