This commit is contained in:
Ryan Kulp
2025-05-23 14:45:15 -04:00
parent 26a8cc3f02
commit 273e62b856
6 changed files with 163 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
module Plugins
class Todoist < Base
def locals
{ tasks: }
end
class << self
def redirect_url
query = {
response_type: 'code',
client_id: Rails.application.credentials.plugins[:todoist][:client_id],
scope: 'data:read',
redirect_uri: "#{Rails.application.credentials.base_url}/plugin_settings/todoist/redirect"
}.to_query
"https://todoist.com/oauth/authorize?#{query}"
end
def fetch_access_token(code)
body = {
grant_type: "authorization_code",
client_id: Rails.application.credentials.plugins[:todoist][:client_id],
client_secret: Rails.application.credentials.plugins[:todoist][:client_secret],
redirect_uri: "#{Rails.application.credentials.base_url}/plugin_settings/todoist/redirect",
code: code
}
response = HTTParty.post("https://todoist.com/oauth/access_token", body:)
response.parsed_response['access_token']
end
def projects(access_token)
response = HTTParty.get('https://api.todoist.com/rest/v2/projects', headers: headers(access_token))
response.map { |m| { m['name'] => m['id'] } }&.push({ 'Today' => 'today' })
end
def headers(access_token) = { "Authorization" => "Bearer #{access_token}" }
end
private
def task_url = "https://api.todoist.com/rest/v2/tasks"
def tasks
fetch(task_url, query:, headers: Plugins::Todoist.headers(access_token))
.sort_by { Date.parse(it.dig('due', 'date') || (Date.today + 100.days).to_s) }
.reject { today_view? ? (it.dig('due', 'date').blank? || Date.parse(it.dig('due', 'date')) > today) : false }
.map do |it|
{
content: it['content'],
due: it.dig('due', 'date').present? ? Date.parse(it.dig('due', 'date')).strftime("%d %b") : it.dig('due', 'string')
}
end
end
def query = today_view? ? {} : { project_id: settings['todoist_project_id'] }
def access_token = settings.dig('todoist', 'access_token')
def today_view? = settings['todoist_project_id'] == 'today'
def today = user.datetime_now.end_of_day
end
end
+27
View File
@@ -0,0 +1,27 @@
<div class="view view--full">
<div class="layout">
<div class="columns">
<% todos.reverse.each_with_index do |doing_and_done, list_index| %>
<div class="column gap--large">
<span class="label label--large <%= 'label--gray-out' if list_index == 0 %>"><%= doing_and_done[:label].titleize %></span>
<% visible_items = doing_and_done[:items] %>
<% hidden_items_count = doing_and_done[:items].size - visible_items.size %>
<div class="list gap" data-list-limit="true" data-list-hidden-count="true" data-list-max-height="310">
<% visible_items.each_with_index do |item, idx| %>
<div class="item">
<div class="meta">
<span class="index"><%= idx + 1 %></span>
</div>
<div class="content">
<span class="label truncate-none <%= 'label--gray-out' if list_index == 0 %>"><%= item %></span>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<%= render 'plugins/todo_list/shared/title_bar', instance_name: instance_name %>
</div>
@@ -0,0 +1,23 @@
<div class="view view--half_horizontal">
<div class="layout layout--row">
<% todos.reverse.each_with_index do |doing_and_done, list_index| %>
<div class="grid grid--cols-1">
<span class="label <%= 'label--gray-out' if list_index == 0 %>"><%= doing_and_done[:label].titleize %></span>
<div class="list" data-list-limit="true" data-list-hidden-count="true" data-list-max-height="140">
<% doing_and_done[:items].each_with_index do |item, idx| %>
<div class="item">
<div class="meta">
<span class="index"><%= idx + 1 %></span>
</div>
<div class="content">
<span class="label truncate-none <%= 'label--gray-out' if list_index == 0 %>"><%= item %></span>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<%= render 'plugins/todo_list/shared/title_bar', instance_name: instance_name %>
</div>
+25
View File
@@ -0,0 +1,25 @@
<div class="view view--half_vertical">
<div class="layout layout--col gap--space-between">
<% todos.each_with_index do |doing_and_done, list_index| %>
<div class="list" data-list-limit="true" data-list-hidden-count="true" data-list-max-height="160">
<span class="label <%= 'label--gray-out' if list_index == 1 %>"><%= doing_and_done[:label].titleize %></span>
<% doing_and_done[:items].each_with_index do |item, idx| %>
<div class="item">
<div class="meta">
<span class="index"><%= idx + 1 %></span>
</div>
<div class="content">
<span class="label truncate-none <%= 'label--gray-out' if list_index == 1 %>"><%= item %></span>
</div>
</div>
<% end %>
<% hidden_items_count = doing_and_done[:items].size - 3 %>
</div>
<% if list_index == 0 %>
<div class="w-full b-h-gray-5"></div>
<% end %>
<% end %>
</div>
<%= render 'plugins/todo_list/shared/title_bar', instance_name: instance_name %>
</div>
+19
View File
@@ -0,0 +1,19 @@
<div class="view view--quadrant">
<div class="layout layout--col">
<div class="list" data-list-limit="true" data-list-hidden-count="true" data-list-max-height="150">
<% todos = todos.first %>
<% todos[:items].each_with_index do |item, idx| %>
<div class="item">
<div class="meta">
<span class="index"><%= idx + 1 %></span>
</div>
<div class="content">
<span class="label truncate-none"><%= item %></span>
</div>
</div>
<% end %>
</div>
</div>
<%= render 'plugins/todo_list/shared/title_bar', instance_name: instance_name %>
</div>
@@ -0,0 +1,6 @@
<div class="title_bar">
<img class="image" src="<%= Rails.application.credentials.base_url %>/images/plugins/todo_list--render.svg" />
<span class="title">Todo List</span>
<span class="instance"><%= instance_name %></span>
</div>