第30回/GitHub/GitLabライクなアクティビティ表示
参考:
GitLabのソースコードリポジトリ:
GitHubはソース非公開
やること
ビジュアライズ表示に何を使っているかの調査
清水さん情報:
上記サイトの回答欄より、GitHubはD3.jsを使っていそう
GitHubのソースコードをChrome DevToolsで調査
TurboFrameなどを使ってそう
データ表示はSVG
Chrome DevToolsの該当箇所のElementをコピーすると以下のような形
code:svg
<div class="border py-2 graph-before-activity-overview">
<div class="js-calendar-graph mx-md-2 mx-3 d-flex flex-column flex-items-end flex-xl-items-center overflow-hidden pt-1 is-graph-loading graph-canvas ContributionCalendar height-full text-center days-selected" data-graph-url="/users/sanak/contributions" data-url="/sanak" data-from="2022-02-20 00:00:00 +0900" data-to="2023-02-25 23:59:59 +0900" data-org="">
<svg width="717" height="112" class="js-calendar-graph-svg">
<g transform="translate(15, 20)" data-hydro-click="{"event_type":"user_profile.click","payload":{"profile_user_id":629923,"target":"CONTRIBUTION_CALENDAR_SQUARE","user_id":629923,"originating_url":"https://github.com/sanak"}}" data-hydro-click-hmac="4168ded12034b6afee1a5f3cc2add81009d10d7d3baea608164009d9b1883cfc"> <g transform="translate(0, 0)">
<rect width="10" height="10" x="14" y="0" class="ContributionCalendar-day" data-date="2022-02-20" data-level="0" rx="2" ry="2">No contributions on Sunday, February 20, 2022</rect>
<rect width="10" height="10" x="14" y="13" class="ContributionCalendar-day" data-date="2022-02-21" data-level="0" rx="2" ry="2">No contributions on Monday, February 21, 2022</rect>
<rect width="10" height="10" x="14" y="26" class="ContributionCalendar-day" data-date="2022-02-22" data-level="1" rx="2" ry="2">1 contribution on Tuesday, February 22, 2022</rect>
GitLabの方は、以前はRails側でカレンダーを生成していたっぽい? (js-contrib-calendar で検索)
Gemファイルを削除している
変更点はフロントエンド側(JS/Vue)が多数
GitLab側もD3.jsを使っていそう
Qiita記事、React利用
継続して調査が必要
Redmineでの表示をどういうようにするか?
どこで表示するか?
ルートのActivity(活動)タブ
※ただし、ユーザー指定がある場合?
※現状、RedmineのActivity表示が、ユーザー操作を元にしたもので、整合性を取る必要があるかもしれない
MyPageのActivityブロック
何を表示するか?
1年間のヒートマップ表示
確認すべきこと
Redmineの中でデータの取得をどういう風にするか?
Redmine本家の方に起票しても
試しに、redmineのサンプルデータで管理者の1年分の Activity を取得したときのSQL。 結構大きい。tohosaku.icon
code:text
irb(main):004:0> u = User.first
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."type" = $1 ORDER BY "users"."id" ASC LIMIT $2 "type", "User"], ["LIMIT", 1
=>
...
irb(main):005:0> f = Redmine::Activity::Fetcher.new(u)
=>
...
irb(main):008:0> events = f.events(Time.current.prev_year, Time.current)
Issue Load (1.2ms) SELECT "issues".* FROM "issues" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" WHERE (issues.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='issue_tracking'))
Project Load (0.7ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" IN ($1, $2, $3, $4) "id", 1], "id", 2, "id", 3, ["id", 5 User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."type" = $1 AND "users"."id" IN ($2, $3) "type", "User"], "id", 2, ["id", 3 Tracker Load (0.6ms) SELECT "trackers".* FROM "trackers" WHERE "trackers"."id" = $1 "id", 1
IssueStatus Load (0.9ms) SELECT "issue_statuses".* FROM "issue_statuses" WHERE "issue_statuses"."id" IN ($1, $2) "id", 1], ["id", 5
Journal Load (3.0ms) SELECT DISTINCT "journals".* FROM "journals" LEFT OUTER JOIN journal_details ON journal_details.journal_id = journals.id INNER JOIN "issues" ON "issues"."id" = "journals"."journalized_id" INNER JOIN "projects" ON "projects"."id" = "issues"."project_id" WHERE (journals.journalized_type = 'Issue' AND (journal_details.prop_key = 'status_id' OR journals.notes <> '')) AND (journals.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='issue_tracking')) AND ((journals.private_notes = FALSE OR journals.user_id = 1 OR (projects.status <> 9 AND projects.status <> 10)))
Issue Load (0.6ms) SELECT "issues".* FROM "issues" WHERE "issues"."id" IN ($1, $2, $3, $4) "id", 1], "id", 2, "id", 6, ["id", 14 Project Load (0.4ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" IN ($1, $2, $3) "id", 1], "id", 5, ["id", 3 User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."type" = $1 AND "users"."id" IN ($2, $3) "type", "User"], "id", 1, ["id", 2 Changeset Load (1.9ms) SELECT "changesets".* FROM "changesets" INNER JOIN "repositories" ON "repositories"."id" = "changesets"."repository_id" INNER JOIN "projects" ON "projects"."id" = "repositories"."project_id" WHERE (changesets.committed_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='repository'))
News Load (1.2ms) SELECT "news".* FROM "news" INNER JOIN "projects" ON "projects"."id" = "news"."project_id" WHERE (news.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='news'))
Document Load (1.2ms) SELECT "documents".* FROM "documents" INNER JOIN "projects" ON "projects"."id" = "documents"."project_id" WHERE (documents.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='documents'))
Attachment Load (2.2ms) SELECT attachments.* FROM "attachments" LEFT JOIN documents ON attachments.container_type='Document' AND documents.id = attachments.container_id LEFT JOIN projects ON documents.project_id = projects.id WHERE (attachments.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='documents'))
Attachment Load (1.8ms) SELECT attachments.* FROM "attachments" LEFT JOIN versions ON attachments.container_type='Version' AND versions.id = attachments.container_id LEFT JOIN projects ON versions.project_id = projects.id OR ( attachments.container_type='Project' AND attachments.container_id = projects.id ) WHERE "attachments"."container_type" IN ($1, $2) AND (attachments.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='files')) "container_type", "Version"], ["container_type", "Project"
WikiContentVersion Load (2.0ms) SELECT wiki_content_versions.updated_on, wiki_content_versions.comments, wiki_content_versions.version, wiki_pages.title, wiki_content_versions.page_id, wiki_content_versions.author_id, wiki_content_versions.id FROM "wiki_content_versions" LEFT JOIN wiki_pages ON wiki_pages.id = wiki_content_versions.page_id LEFT JOIN wikis ON wikis.id = wiki_pages.wiki_id LEFT JOIN projects ON projects.id = wikis.project_id WHERE (wiki_content_versions.updated_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='wiki'))
Message Load (1.2ms) SELECT "messages".* FROM "messages" INNER JOIN "boards" ON "boards"."id" = "messages"."board_id" INNER JOIN "projects" ON "projects"."id" = "boards"."project_id" WHERE (messages.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='boards'))
Board Load (0.7ms) SELECT "boards".* FROM "boards" WHERE "boards"."id" IN ($1, $2) "id", 1], ["id", 3
Project Load (0.9ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" IN ($1, $2) "id", 1], ["id", 2
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."type" = $1 AND "users"."id" IN ($2, $3) "type", "User"], "id", 3, ["id", 1 TimeEntry Load (1.5ms) SELECT "time_entries".* FROM "time_entries" INNER JOIN "projects" ON "projects"."id" = "time_entries"."project_id" WHERE (time_entries.created_on BETWEEN '2022-04-22 07:15:18.773844' AND '2023-04-22 07:15:18.774103') AND (projects.status <> 9 AND projects.status <> 10 AND EXISTS (SELECT 1 AS one FROM enabled_modules em WHERE em.project_id = projects.id AND em.name='time_tracking'))
=>
[#<Issue:0x00007f2fdbef7a60
...
irb(main):009:0> events.map{|e| e.event_date}
=> Mon, 27 Mar 2023, Mon, 27 Mar 2023, Mon, 27 Mar 2023, Sun, 26 Mar 2023, Sun, 26 Mar 2023, Sun, 26 Mar 2023, Sun, 26 Mar 2023, Sat, 25 Mar 2023, Sat, 25 Mar 2023, Sat, 25 Mar 2023, Fri, 24 Mar 2023, Fri, 24 Mar 2023, Fri, 24 Mar 2023, Fri, 24 Mar 2023, Wed, 22 Mar 2023, Wed, 22 Mar 2023, Wed, 22 Mar 2023, Fri, 17 Mar 2023, Fri, 17 Mar 2023, Sun, 12 Mar 2023 上の events.map で、 event_data をキーにGROUP BYすると、各日の件数が分かる
が、今現状のActivity表示で毎回上記のSQLが流れると辛いかも