Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dashboard providing obsolete action information #2042

Merged
merged 35 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b934726
Add obsoleteOnly and jsonPath options for action list command
XxshiftxX Jul 21, 2023
e990da1
Add exported obsolete-action file
XxshiftxX Jul 21, 2023
9bf51e3
Add dashboard project
XxshiftxX Jul 24, 2023
1661e67
Install tailwind
XxshiftxX Jul 24, 2023
5d970d2
Set default font to Pretendard
XxshiftxX Jul 24, 2023
746242a
Add env variables
XxshiftxX Jul 24, 2023
020583d
Add react-query
XxshiftxX Jul 24, 2023
984acc9
Add code for loading currentBlock and actions data
XxshiftxX Jul 24, 2023
a791cbd
Remove default styles
XxshiftxX Jul 24, 2023
f8fd42c
Implement dashboard
XxshiftxX Jul 24, 2023
3c85d7d
Add gh-action script for deploy gh-pages
XxshiftxX Jul 28, 2023
1de5bf8
Merge branch 'development' into add-obsolete-action-command
XxshiftxX Jul 31, 2023
e959c53
Merge branch 'development' into add-obsolete-action-command
moreal Aug 2, 2023
4fba8b4
Change dashboard title
XxshiftxX Aug 2, 2023
e22ba42
Move gh-pages into devDependencies
XxshiftxX Aug 2, 2023
84176eb
Fix obsoleteOnly option's description
XxshiftxX Aug 2, 2023
f1bc72b
Replace default README.md with right contents
XxshiftxX Aug 2, 2023
c544d94
Add example .env file
XxshiftxX Aug 3, 2023
03584cf
Add gh-action for deploing gh pages
XxshiftxX Aug 3, 2023
2b6f233
Fix lint
XxshiftxX Aug 3, 2023
17a9786
Fix indent
XxshiftxX Aug 3, 2023
fb18783
Add working-directory on gh-actions
XxshiftxX Aug 3, 2023
c9df134
Set homepage of github action
XxshiftxX Aug 3, 2023
7d4f149
Change gh-pages destination dir
XxshiftxX Aug 3, 2023
90c8d9c
Change package.json homepage
XxshiftxX Aug 3, 2023
94692a2
Fix base url on vite config
XxshiftxX Aug 3, 2023
b539e1c
Fix .env file name
XxshiftxX Aug 3, 2023
07f7695
Set working-directory for .env building
XxshiftxX Aug 3, 2023
2c9b0b4
Fix secret syntax
XxshiftxX Aug 3, 2023
fa820e8
Fix typo
XxshiftxX Aug 3, 2023
446600c
Restore deleted gh-pages publish code
XxshiftxX Aug 3, 2023
6ed0b0f
Make latest destination for gh-pages
XxshiftxX Aug 3, 2023
be96425
Delete unused file
XxshiftxX Aug 3, 2023
ff18207
Fix gh actions target branch
XxshiftxX Aug 3, 2023
95e74ba
Merge branch 'development' into add-obsolete-action-command
XxshiftxX Aug 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions .Lib9c.Tools/SubCommand/Action.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json.Nodes;
using Bencodex.Types;
using Cocona;
using Cocona.Help;
Expand All @@ -14,6 +16,12 @@ public class Action
[Obsolete("This function is deprecated. Please use `NineChronicles.Headless.Executable action list` command instead.")]
[Command(Description = "Lists all actions' type ids.")]
public void List(
[Option(
Description = "If true, show obsoleted or will be obsoleted actions only (Actions having ActionObsolete attribute only)"
)] bool obsoleteOnly = false,
[Option(
Description = "If true, make json file with results"
)] string jsonPath = null,
[Option(
Description = "If true, filter obsoleted actions since the --block-index option."
)] bool excludeObsolete = false,
Expand All @@ -22,29 +30,53 @@ public void List(
)] long blockIndex = 0
)
{
Type baseType = typeof(Nekoyume.Action.ActionBase);
var baseType = typeof(ActionBase);

bool IsTarget(Type type)
{
return baseType.IsAssignableFrom(type) &&
type.GetCustomAttribute<ActionTypeAttribute>() is { } &&
(
!excludeObsolete ||
!(type.GetCustomAttribute<ActionObsoleteAttribute>() is { } aoAttr) ||
aoAttr.ObsoleteIndex > blockIndex
);
if (!baseType.IsAssignableFrom(type) ||
type.GetCustomAttribute<ActionTypeAttribute>() is null)
{
return false;
}

var isObsoleteTarget = type.GetCustomAttribute<ActionObsoleteAttribute>() is not null;
var isObsolete = type.GetCustomAttribute<ActionObsoleteAttribute>() is { } attr &&
attr.ObsoleteIndex <= blockIndex;

if (obsoleteOnly) return isObsoleteTarget;
XxshiftxX marked this conversation as resolved.
Show resolved Hide resolved
if (excludeObsolete) return !isObsolete;

return true;
}

var assembly = baseType.Assembly;
var typeIds = assembly.GetTypes()
.Where(IsTarget)
.Select(type => type.GetCustomAttribute<ActionTypeAttribute>()?.TypeIdentifier)
.OfType<Text>()
.OrderBy(type => type);
.Select(type => ((IValue typeId, long? obsoleteAt))(
type.GetCustomAttribute<ActionTypeAttribute>()?.TypeIdentifier,
type.GetCustomAttribute<ActionObsoleteAttribute>()?.ObsoleteIndex
))
.Where(type => type.typeId is Text)
.OrderBy(type => ((Text)type.typeId).Value);

var jsonResult = new JsonArray();

foreach (var (typeIdValue, obsoleteAt) in typeIds)
{
var typeId = (Text)typeIdValue;
var json = new JsonObject { ["id"] = typeId.Value };
if (obsoleteAt != null) json.Add("obsoleteAt", obsoleteAt);
jsonResult.Add(json);

foreach (Text typeId in typeIds) {
Console.WriteLine(typeId.Value);
}

if (jsonPath != null)
{
using var stream = File.CreateText(jsonPath);
stream.WriteLine(jsonResult.ToString());
}
}

[PrimaryCommand]
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/gh-page.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: main

on:
push:
branches:
- development
- main

jobs:
publish-gh-pages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: Install Dependency
working-directory: ./Dashboard
run: yarn

- name: Build .env
working-directory: ./Dashboard
run: |
echo "VITE_OBSOLETE_DATA_PATH=${{ secrets.VITE_OBSOLETE_DATA_PATH }}" >> .env
echo "VITE_API_PATH=${{ secrets.VITE_API_PATH }}" >> .env

- name: Build Dashboard
working-directory: ./Dashboard
run: yarn build --outDir ../publish

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./publish
destination_dir: dashboard
7 changes: 7 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,19 @@ jobs:
run: |
mkdir publish
dotnet run --property WarningLevel=0 --project .Lib9c.Tools/Lib9c.Tools.csproj -- action list > publish/all_action_type_ids.txt
dotnet run --property WarningLevel=0 --project .Lib9c.Tools/Lib9c.Tools.csproj -- action list --obsolete-only --json-path=publish/obsolete_action_types.json
- name: Publish available action type ids
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./publish
destination_dir: ${{ github.ref_name }}
- name: Publish available action type ids for latest
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./publish
destination_dir: latest

update-submodule:
if: github.ref_type == 'branch' && startsWith(github.ref_name, 'release/')
Expand Down
2 changes: 2 additions & 0 deletions Dashboard/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_OBSOLETE_DATA_PATH=https://raw.githubusercontent.com/planetarium/lib9c/development/.github/exports/obsolete-actions.json
VITE_API_PATH=https://sample-api-server.test
18 changes: 18 additions & 0 deletions Dashboard/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
26 changes: 26 additions & 0 deletions Dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.env
3 changes: 3 additions & 0 deletions Dashboard/.prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
plugins: ['prettier-plugin-tailwindscss'],
};
13 changes: 13 additions & 0 deletions Dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Lib9c Dashboard

Lib9c Dashboard is web application provides Lib9c's various information (etc. Action Obsoletion, ...).

## Quick Start

1. Copy `.env.example` with name `.env` and fill with valid value.
2. Run `yarn install`
3. Run `yarn dev`

## Build

Just run `yarn build` then result of build will be created at `/dist`
13 changes: 13 additions & 0 deletions Dashboard/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Obsolete Dashboard</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
39 changes: 39 additions & 0 deletions Dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "dashboard",
"private": true,
"version": "0.0.0",
"type": "module",
"homepage": "http://planetarium.github.io/lib9c/dashboard",
"scripts": {
"dev": "vite",
"predeploy": "yarn build",
"deploy": "gh-pages -d build",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-query": "^4.32.0",
"axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.14",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"gh-pages": "^5.0.0",
"postcss": "^8.4.27",
"prettier": "^3.0.0",
"prettier-plugin-tailwindcss": "^0.4.1",
"tailwindcss": "^3.3.3",
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}
6 changes: 6 additions & 0 deletions Dashboard/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
84 changes: 84 additions & 0 deletions Dashboard/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useQueries } from "@tanstack/react-query";
import axios from "axios";
import { useMemo } from "react";

interface Block { index: number }
interface Action { id: string, obsoleteAt: number }

const fetchLatestBlock = async () => {
const response = await axios.get<Block>(`${import.meta.env.VITE_API_PATH}/api/blocks/latest`);
return response.data;
};

const fetchActions = async () => {
const response = await axios.get<Action[]>(import.meta.env.VITE_OBSOLETE_DATA_PATH);
return response.data;
}

function App() {
const [latestBlockQuery, actionsQuery] = useQueries({
queries: [
{ queryKey: ['latestBlock'], queryFn: fetchLatestBlock },
{ queryKey: ['actions'], queryFn: fetchActions },
],
});
const isLoading = latestBlockQuery.isLoading || actionsQuery.isLoading;
const isError = latestBlockQuery.isError || actionsQuery.isError;

const currentBlock = useMemo(
() => latestBlockQuery.data?.index ?? 0,
[latestBlockQuery.data],
);
const actions = useMemo(
() => actionsQuery.data?.sort((a, b) => b.obsoleteAt - a.obsoleteAt) ?? [],
[actionsQuery.data],
);

if (isLoading) return <></>;
if (isError) return <></>;

const isObsoleted = (data: Action) => currentBlock > data.obsoleteAt;

return (
<div className="container mx-auto pt-16 pb-16">
<div className="header pb-8">
<h1 className="text-5xl font-bold mb-2">Dashboard</h1>
<p>
You can check NineChronicles actions that will be obsoleted soon here.
</p>
</div>

<p className="text-xl mb-4">
The latest block is <span className="font-extrabold">#{currentBlock}</span>
</p>

<div className="grid grid-cols-[120px_1fr_2fr] gap-2 text-lg">
<>
<p className="text-sm text-slate-500 font-bold">#Block Index</p>
<p className="text-sm text-slate-500 font-bold">Action ID</p>
<p className="text-sm text-slate-500 font-bold">Remain blocks</p>
</>

{actions.map((action) => (
<>
<p className={`font-bold ${isObsoleted(action) ? 'text-slate-400 line-through' : ''}`}>
#{action.obsoleteAt}
</p>
<p className={isObsoleted(action) ? 'text-slate-400' : ''}>
{action.id}
</p>
<p className={isObsoleted(action) ? 'text-slate-400' : ''}>
{isObsoleted(action)
? <span className="text-sm">Obsoleted</span>
: <span>{action.obsoleteAt - currentBlock} blocks remain</span>
}
</p>
</>
))
}
</div>
</div>
);
}

export default App;
Loading
Loading