Skip to content

Commit

Permalink
Merge pull request #129 from darrenburns/layout-fixes
Browse files Browse the repository at this point in the history
Some UI fixes
  • Loading branch information
darrenburns authored Nov 12, 2024
2 parents c5e7e47 + 22c1cd3 commit cf4f5c3
Show file tree
Hide file tree
Showing 43 changed files with 2,950 additions and 2,923 deletions.
Binary file modified .coverage
Binary file not shown.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ Some notable features include:
- customizable keybindings
- user-defined themes
- run Python code before and after requests
- configuration
- extensive configuration
- "open in $EDITOR"
- import curl commands by pasting them into the URL bar
- import OpenAPI specs
- a command palette for quickly accessing functionality

Visit the [website](https://posting.sh) for more information, the roadmap, and the user guide.
Expand Down
11 changes: 11 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 2.1.0 [11th November 2024]

### Added

- Import curl command by pasting it into the URL bar.

### Changed

- Collection browser width now adjusts based on content, so it doesn't waste a lot of space on larger screens.
- Info tab now shows "Request not saved to disk" if a request has not been saved to disk, rather than "None" or nothing at all.

## 2.0.0 [18th October 2024]

### Added
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ The table below lists all available configuration options and their environment

| Config Key (Env Var) | Values (Default) | Description |
|----------------------|------------------|-------------|
| `theme` (`POSTING_THEME`) | `"posting"`, `"galaxy"`, `"monokai"`, `"solarized-light"`, `"nautilus"`, `"nebula"`, `"alpine"`, `"cobalt"`, `"twilight"`, `"hacker"` (Default: `"posting"`) | Sets the theme of the application. |
| `theme` (`POSTING_THEME`) | `"posting"`, `"galaxy"`, `"monokai"`, `"solarized-light"`, `"nautilus"`, `"nebula"`, `"alpine"`, `"cobalt"`, `"twilight"`, `"hacker"` (Default: `"galaxy"`) | Sets the theme of the application. |
| `load_user_themes` (`POSTING_LOAD_USER_THEMES`) | `true`, `false` (Default: `true`) | If enabled, load user themes from the theme directory, allowing them to be specified in config and selected via the command palette. |
| `load_builtin_themes` (`POSTING_LOAD_BUILTIN_THEMES`) | `true`, `false` (Default: `true`) | If enabled, load builtin themes, allowing them to be specified in config and selected via the command palette. |
| `theme_directory` (`POSTING_THEME_DIRECTORY`) | (Default: `${XDG_DATA_HOME}/posting/themes`) | The directory containing user themes. |
Expand Down
10 changes: 8 additions & 2 deletions docs/guide/importing.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
## Overview

Posting currently supports importing from OpenAPI specs.
Posting supports importing from external sources.

Support for other API formats will be added in future updates.
## Importing from curl

!!! example "This feature is experimental."

You can import a curl command by pasting it into the URL bar.

This will fill out the request details in the UI based on the curl command you pasted, overwriting any existing values.

## Importing from OpenAPI

Expand Down
11 changes: 8 additions & 3 deletions docs/overrides/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -1665,10 +1665,12 @@ <h2 id="feature-title-1" class="feature-title">
</p>

<p class="feature-description">
Want to edit a request body in <span data-text="nvim" class="gradient-text subtle-purple-glow monospace">nvim</span> or browse a JSON response in <span data-text="fx" class="gradient-text subtle-purple-glow monospace">fx</span>? No problem!
Posting lets you use the tools you love.
Edit a request body in <span data-text="nvim" class="gradient-text subtle-purple-glow monospace">nvim</span> or browse a JSON response in <span data-text="fx" class="gradient-text subtle-purple-glow monospace">fx</span>? No problem!
</p>

<p class="feature-description">
Import <span data-text="curl" class="gradient-text subtle-purple-glow monospace">curl</span> requests into Posting by simply pasting into the URL bar.
</p>

<!-- move the version control text to a different section -->
<!-- <p class="feature-description">
After saving a request, check it into <span data-text="version control" class="gradient-text subtle-purple-glow">version control</span> - requests live on your file system, in diffable and easy to read YAML files.
Expand All @@ -1688,6 +1690,9 @@ <h2 class="feature-title">Environments</h2>
<p class="feature-description">
Load variables from one or more <span data-text="dotenv" class="gradient-text subtle-purple-glow">dotenv</span> environment files, or allow access to <span data-text="environment variables" class="gradient-text subtle-purple-glow">environment variables</span>.
</p>
<p class="feature-description">
Edit variables in your favorite editor, and Posting will <span data-text="hot reload" class="gradient-text subtle-purple-glow">hot reload</span> them.
</p>
</div>
<div class="feature-image">
<video src="assets/environments.mp4" alt="Environments in action in the URL bar" autoplay loop muted playsinline></video>
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "posting"
version = "2.0.1"
version = "2.1.0"
description = "The modern API client that lives in your terminal."
authors = [
{ name = "Darren Burns", email = "[email protected]" }
Expand Down
6 changes: 3 additions & 3 deletions src/posting/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,16 +699,16 @@ def on_curl_message(self, event: CurlMessage):
request_model = curl_import.to_request_model()
except Exception as e:
self.notify(
title="Could not parse curl request",
message=f"An error occurred: {e}",
title="Import error",
message=f"Couldn't import curl command.",
timeout=5,
severity="error",
)
else:
self.load_request_model(request_model)
self.notify(
title="Curl request imported",
message=f"Successfully imported curl request to {curl_import.url}",
message=f"Successfully imported request to {curl_import.url}",
timeout=3,
)

Expand Down
15 changes: 12 additions & 3 deletions src/posting/importing/curl.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,14 @@ def __init__(self, curl_command: str):
)
parser.add_argument("-e", "--referer", help="Referrer URL")
parser.add_argument("-A", "--user-agent", help="User-Agent to send to server")
parser.add_argument(
"--digest",
action="store_true",
help="Use HTTP Digest Authentication",
)
parser.add_argument("url", nargs="?")

args = parser.parse_intermixed_args(tokens)
args, extras = parser.parse_known_intermixed_args(tokens)
# Extract components
self.method = cast(
HttpRequestMethod,
Expand All @@ -92,6 +97,7 @@ def __init__(self, curl_command: str):
self.insecure = args.insecure
self.referer = args.referer
self.user_agent = args.user_agent
self.use_digest = args.digest

# Determine if the data is form data
self.is_form_data = False
Expand Down Expand Up @@ -163,8 +169,11 @@ def _extract_auth_from_headers(self) -> tuple[Auth | None, list[tuple[str, str]]
# First check the -u/--user parameter
if self.user:
username, _, password = self.user.partition(":")
# Default to empty password if none provided
auth = Auth.basic_auth(username, password)
# Use digest auth if --digest flag was provided, otherwise use basic auth
if self.use_digest:
auth = Auth.digest_auth(username, password)
else:
auth = Auth.basic_auth(username, password)

# Look for auth headers that might override the -u parameter
for name, value in self.headers:
Expand Down
1 change: 0 additions & 1 deletion src/posting/posting.scss
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ DataTable {


TextArea {
height: 1fr;
border: none;
&:focus {
border: none;
Expand Down
3 changes: 2 additions & 1 deletion src/posting/widgets/collection/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ class RequestPreview(VerticalScroll):
dock: bottom;
height: auto;
max-height: 50%;
width: 100%;
padding: 0 1;
border-top: solid $accent 35%;
&.hidden {
Expand Down Expand Up @@ -575,8 +576,8 @@ class CollectionBrowser(Vertical):
width: auto;
max-width: 33%;
& Tree {
min-width: 20;
background: transparent;
width: auto;
}
#empty-collection-label {
Expand Down
27 changes: 17 additions & 10 deletions src/posting/widgets/request/request_metadata.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from textual.app import ComposeResult
from textual.containers import VerticalScroll
from textual.reactive import Reactive, reactive
from textual.widgets import Input, Label, Static
from textual.widgets import Input, Label

from posting.collection import RequestModel
from posting.widgets.text_area import PostingTextArea
from posting.widgets.text_area import PostingTextArea, ReadOnlyTextArea
from posting.widgets.variable_input import VariableInput


Expand All @@ -17,15 +17,18 @@ class RequestMetadata(VerticalScroll):
margin-bottom: 1;
}
& PostingTextArea {
max-height: 3;
margin-bottom: 1;
}
& Button {
dock: bottom;
width: 1fr;
}
& #request-path {
& PostingTextArea#request-path {
color: $text-muted;
margin: 0;
padding: 0;
height: auto;
max-height: 2;
}
}
"""
Expand All @@ -37,20 +40,24 @@ def watch_request(self, request: RequestModel | None) -> None:
if request is None:
self.request_name_input.value = ""
self.request_description_textarea.text = ""
self.request_path_label.update("")
self.request_path_text_area.text = "Request not saved to disk."
else:
self.request_name_input.value = request.name or ""
self.request_description_textarea.text = request.description
self.request_path_label.update(str(request.path) or "")
self.request_path_text_area.text = (
str(request.path) if request.path else "Request not saved to disk."
)

def compose(self) -> ComposeResult:
self.can_focus = False
yield Label("Name [dim]optional[/dim]")
yield VariableInput(placeholder="Enter a name...", id="name-input")
yield Label("Description [dim]optional[/dim]")
yield PostingTextArea(id="description-textarea")

yield Static("", id="request-path")
yield Label("Path [dim]read-only[/dim]")
yield ReadOnlyTextArea(
"Request not saved to disk.", select_on_focus=True, id="request-path"
)

@property
def request_name_input(self) -> Input:
Expand All @@ -61,8 +68,8 @@ def request_description_textarea(self) -> PostingTextArea:
return self.query_one("#description-textarea", PostingTextArea)

@property
def request_path_label(self) -> Static:
return self.query_one("#request-path", Static)
def request_path_text_area(self) -> ReadOnlyTextArea:
return self.query_one("#request-path", ReadOnlyTextArea)

@property
def request_name(self) -> str:
Expand Down
7 changes: 6 additions & 1 deletion src/posting/widgets/request/url_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ class UrlInput(PostingInput):
Enter the URL to send a request to. Refer to variables from the environment (loaded via `--env`) using `$variable` or `${variable}` syntax.
Resolved variables will be highlighted green. Move the cursor over a variable to preview the value.
Base URL suggestions are loaded based on the URLs found in the currently open collection.
Press `ctrl+l` to quickly focus this bar from elsewhere.""",
Press `ctrl+l` to quickly focus this bar from elsewhere.
You can also import a `curl` command by pasting it into the URL bar.
This will fill out the request details in the UI based on the curl command you pasted, overwriting any existing values.
It's recommended you create a new request before pasting a curl command, to avoid overwriting.
""",
)

DEFAULT_CSS = """\
Expand Down
6 changes: 6 additions & 0 deletions src/posting/widgets/text_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ def __init__(
read_only: bool = True,
show_line_numbers: bool = False,
max_checkpoints: int = 50,
select_on_focus: bool = False,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
Expand All @@ -401,6 +402,7 @@ def __init__(
classes=classes,
disabled=disabled,
)
self.select_on_focus = select_on_focus

@dataclass
class VisualModeToggled(Message):
Expand Down Expand Up @@ -520,6 +522,10 @@ def action_cursor_half_page_up(self) -> None:
self.scroll_relative(y=-half_height, animate=False)
self.move_cursor(target)

def on_focus(self) -> None:
if self.select_on_focus:
self.select_all()


class TextEditor(Vertical):
soft_wrap: Reactive[bool] = reactive(True, init=False)
Expand Down
Loading

0 comments on commit cf4f5c3

Please sign in to comment.