From 645a88e7e35d15cec6106709c42b071bec045e0d Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Aug 2023 02:52:07 +0800 Subject: ... --- BackEnd/Timeline.Tests/Timeline.Tests.csproj | 20 +- BackEnd/Timeline.Tests/packages.lock.json | 307 ++++++++-------- BackEnd/Timeline/Timeline.csproj | 18 +- BackEnd/Timeline/packages.lock.json | 171 ++++----- FrontEnd/.eslintignore | 1 + FrontEnd/src/App.tsx | 4 - FrontEnd/src/migrating/admin/Admin.tsx | 27 ++ FrontEnd/src/migrating/admin/AdminNav.tsx | 29 ++ FrontEnd/src/migrating/admin/MoreAdmin.tsx | 7 + FrontEnd/src/migrating/admin/UserAdmin.tsx | 301 ++++++++++++++++ FrontEnd/src/migrating/admin/index.css | 33 ++ FrontEnd/src/migrating/admin/index.tsx | 7 + FrontEnd/src/migrating/center/CenterBoards.tsx | 131 +++++++ FrontEnd/src/migrating/center/TimelineBoard.tsx | 390 +++++++++++++++++++++ .../src/migrating/center/TimelineCreateDialog.tsx | 57 +++ FrontEnd/src/migrating/center/index.css | 43 +++ FrontEnd/src/migrating/center/index.tsx | 60 ++++ FrontEnd/src/services/alert.ts | 4 +- FrontEnd/src/views/admin/Admin.tsx | 27 -- FrontEnd/src/views/admin/AdminNav.tsx | 29 -- FrontEnd/src/views/admin/MoreAdmin.tsx | 7 - FrontEnd/src/views/admin/UserAdmin.tsx | 304 ---------------- FrontEnd/src/views/admin/index.css | 33 -- FrontEnd/src/views/admin/index.tsx | 7 - FrontEnd/src/views/center/CenterBoards.tsx | 131 ------- FrontEnd/src/views/center/TimelineBoard.tsx | 390 --------------------- FrontEnd/src/views/center/TimelineCreateDialog.tsx | 57 --- FrontEnd/src/views/center/index.css | 43 --- FrontEnd/src/views/center/index.tsx | 60 ---- FrontEnd/src/views/common/button/LoadingButton.css | 2 +- FrontEnd/src/views/search/index.css | 15 - FrontEnd/src/views/search/index.tsx | 131 ------- FrontEnd/tsconfig.json | 3 + 33 files changed, 1336 insertions(+), 1513 deletions(-) create mode 100644 FrontEnd/src/migrating/admin/Admin.tsx create mode 100644 FrontEnd/src/migrating/admin/AdminNav.tsx create mode 100644 FrontEnd/src/migrating/admin/MoreAdmin.tsx create mode 100644 FrontEnd/src/migrating/admin/UserAdmin.tsx create mode 100644 FrontEnd/src/migrating/admin/index.css create mode 100644 FrontEnd/src/migrating/admin/index.tsx create mode 100644 FrontEnd/src/migrating/center/CenterBoards.tsx create mode 100644 FrontEnd/src/migrating/center/TimelineBoard.tsx create mode 100644 FrontEnd/src/migrating/center/TimelineCreateDialog.tsx create mode 100644 FrontEnd/src/migrating/center/index.css create mode 100644 FrontEnd/src/migrating/center/index.tsx delete mode 100644 FrontEnd/src/views/admin/Admin.tsx delete mode 100644 FrontEnd/src/views/admin/AdminNav.tsx delete mode 100644 FrontEnd/src/views/admin/MoreAdmin.tsx delete mode 100644 FrontEnd/src/views/admin/UserAdmin.tsx delete mode 100644 FrontEnd/src/views/admin/index.css delete mode 100644 FrontEnd/src/views/admin/index.tsx delete mode 100644 FrontEnd/src/views/center/CenterBoards.tsx delete mode 100644 FrontEnd/src/views/center/TimelineBoard.tsx delete mode 100644 FrontEnd/src/views/center/TimelineCreateDialog.tsx delete mode 100644 FrontEnd/src/views/center/index.css delete mode 100644 FrontEnd/src/views/center/index.tsx delete mode 100644 FrontEnd/src/views/search/index.css delete mode 100644 FrontEnd/src/views/search/index.tsx diff --git a/BackEnd/Timeline.Tests/Timeline.Tests.csproj b/BackEnd/Timeline.Tests/Timeline.Tests.csproj index 57694c2b..3983bc0b 100644 --- a/BackEnd/Timeline.Tests/Timeline.Tests.csproj +++ b/BackEnd/Timeline.Tests/Timeline.Tests.csproj @@ -8,15 +8,21 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + + - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/BackEnd/Timeline.Tests/packages.lock.json b/BackEnd/Timeline.Tests/packages.lock.json index cc7108a4..cb747b24 100644 --- a/BackEnd/Timeline.Tests/packages.lock.json +++ b/BackEnd/Timeline.Tests/packages.lock.json @@ -4,15 +4,15 @@ "net7.0": { "coverlet.collector": { "type": "Direct", - "requested": "[3.2.0, )", - "resolved": "3.2.0", - "contentHash": "xjY8xBigSeWIYs4I7DgUHqSNoGqnHi7Fv7/7RZD02rvZyG3hlsjnQKiVKVWKgr9kRKgmV+dEfu8KScvysiC0Wg==" + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==" }, "FluentAssertions": { "type": "Direct", - "requested": "[6.10.0, )", - "resolved": "6.10.0", - "contentHash": "Da3YsiRDnOHKBfxutjnupL1rOX0K/jnG6crn5AgwukeqZ/yi+HNCOFshic01ke0ztZFWzpfQMXH8fO9aAbG0Gw==", + "requested": "[6.11.0, )", + "resolved": "6.11.0", + "contentHash": "aBaagwdNtVKkug1F3imGXUlmoBd8ZUZX8oQ5niThaJhF79SpESe1Gzq7OFuZkQdKD5Pa4Mone+jrbas873AT4g==", "dependencies": { "System.Configuration.ConfigurationManager": "4.4.0" } @@ -30,31 +30,31 @@ }, "Microsoft.AspNetCore.SignalR.Client": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "kyxW20UJwTf1VZuiK8jWhz9tx1NhfzCG5KoOlHDnpr0dy2utlHil9xgdlsAC5V46K1Dser3DZDbCn0Qq8x4K1w==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "tXSCmD/oZimbnzOfVSz8CGrKy/OLDvWJ87Hp1Yg8IkG/8ek3532Hk8Ujf/gNjZy1jRLT2s4jcQS7iwGguhvi3g==", "dependencies": { - "Microsoft.AspNetCore.Http.Connections.Client": "7.0.3", - "Microsoft.AspNetCore.SignalR.Client.Core": "7.0.3" + "Microsoft.AspNetCore.Http.Connections.Client": "7.0.9", + "Microsoft.AspNetCore.SignalR.Client.Core": "7.0.9" } }, "Microsoft.AspNetCore.TestHost": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "wS+gBqK8O6ASpGjEoRdxKR4qb/Hqt+RumM1bMfKxkjYpsBl4UMh8ClmXzU42omn3sWCpPqxZIBSIO3F4zEYPzQ==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "QHbCXxCpVEKFyZ80JspVjIkjy6LsavJXGUc1qHN3bJk4SipVMTM8rq/lhYM8Gu1xJJX8pH/AqguFa391Nx9RTw==", "dependencies": { "System.IO.Pipelines": "7.0.0" } }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.5.0, )", - "resolved": "17.5.0", - "contentHash": "IJ4eSPcsRbwbAZehh1M9KgejSy0u3d0wAdkJytfCh67zOaCl5U3ltruUEe15MqirdRqGmm/ngbjeaVeGapSZxg==", + "requested": "[17.6.3, )", + "resolved": "17.6.3", + "contentHash": "MglaNTl646dC2xpHKotSk1xscmHO5uV3x3NK057IUA9BM3Wgl16WMEb9ptGczk518JfLd1+Th5OAYwnoWgHQQQ==", "dependencies": { - "Microsoft.CodeCoverage": "17.5.0", - "Microsoft.TestPlatform.TestHost": "17.5.0" + "Microsoft.CodeCoverage": "17.6.3", + "Microsoft.TestPlatform.TestHost": "17.6.3" } }, "Moq": { @@ -68,20 +68,20 @@ }, "xunit": { "type": "Direct", - "requested": "[2.4.2, )", - "resolved": "2.4.2", - "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", + "requested": "[2.5.0, )", + "resolved": "2.5.0", + "contentHash": "f2V5wuAdoaq0mRTt9UBmPbVex9HcwFYn+y7WaKUz5Xpakcrv7lhtQWBJUWNY4N3Z+o+atDBLyAALM1QWx04C6Q==", "dependencies": { - "xunit.analyzers": "1.0.0", - "xunit.assert": "2.4.2", - "xunit.core": "[2.4.2]" + "xunit.analyzers": "1.2.0", + "xunit.assert": "2.5.0", + "xunit.core": "[2.5.0]" } }, "xunit.runner.visualstudio": { "type": "Direct", - "requested": "[2.4.5, )", - "resolved": "2.4.5", - "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" + "requested": "[2.5.0, )", + "resolved": "2.5.0", + "contentHash": "+Gp9vuC2431yPyKB15YrOTxCuEAErBQUTIs6CquumX1F073UaPHGW0VE/XVJLMh9W4sXdz3TBkcHdFWZrRn2Hw==" }, "AutoMapper": { "type": "Transitive", @@ -93,10 +93,10 @@ }, "AutoMapper.Extensions.Microsoft.DependencyInjection": { "type": "Transitive", - "resolved": "12.0.0", - "contentHash": "XCJ4E3oKrbRl1qY9Mr+7uyC0xZj1+bqQjmQRWTiTKiVuuXTny+7YFWHi20tPjwkMukLbicN6yGlDy5PZ4wyi1w==", + "resolved": "12.0.1", + "contentHash": "+g/K+Vpe3gGMKGzjslMOdqNlkikScDjWfVvmWTayrDHaG/n2pPmFBMa+jKX1r/h6BDGFdkyRjAuhFE3ykW+r1g==", "dependencies": { - "AutoMapper": "12.0.0", + "AutoMapper": "[12.0.1]", "Microsoft.Extensions.Options": "6.0.0" } }, @@ -110,43 +110,43 @@ }, "Markdig": { "type": "Transitive", - "resolved": "0.30.4", - "contentHash": "9LL7Mzubwf6QmOTZIqf+vERiinqPA1H+irBA38POhr93W/it00AvFWaCtF80+8VJTooFmcAJyZT2f60t1f88eQ==" + "resolved": "0.31.0", + "contentHash": "CEdZ3KyFfz5IPMrofhCOSrc4O2KNvSXSMXt3fv0W5AFCsk6a/JhKZuTBxGSadNt8n4zyyd/xXfoUMvr4ZbZ4Fw==" }, "Microsoft.AspNetCore.Connections.Abstractions": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "uR20YarXQQfazLUtfn2KBNRgROtsvsNRRku9+s0o1MpkVn6aWhJ0udzMdTUZ3hrXo/VP3UoRbi9f4OYlJF0DLA==", + "resolved": "7.0.9", + "contentHash": "T/A7MkuL0g4r/oNuASR2gIukWoG2360/tuS9RoiU1dOwTlMYthHJaK8NEpswMihcImCDryiHp5dJCPTZHIs9TQ==", "dependencies": { - "Microsoft.Extensions.Features": "7.0.3", + "Microsoft.Extensions.Features": "7.0.9", "System.IO.Pipelines": "7.0.0" } }, "Microsoft.AspNetCore.Http.Connections.Client": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "t2+AReXjZeL47pq50gg/gfmX3u0jK++LL8pg0IoyG9IjhlFKl/okZcvXWp/mMPKRyMmpKJvVb++tQLMyIOEYlw==", + "resolved": "7.0.9", + "contentHash": "41NrQVGv+M5KpujoaUwPs8DGaQrkvhJvaotuvdyvsuTPlcpzqBy+bmQs2eUXEpOfFxOWL9uqZcwLpoOkCOn3/A==", "dependencies": { - "Microsoft.AspNetCore.Http.Connections.Common": "7.0.3", - "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.AspNetCore.Http.Connections.Common": "7.0.9", + "Microsoft.Extensions.Logging.Abstractions": "7.0.1", "Microsoft.Extensions.Options": "7.0.1" } }, "Microsoft.AspNetCore.Http.Connections.Common": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "egbJZ83GxjFt6WWD9Oab6lLf4eRHyxA0mRzBX/2GIX4nXoLt0vvIk9LciCRhwWHjFkVj8zOBfjEQ58RXfKOs4Q==", + "resolved": "7.0.9", + "contentHash": "GnhaII0AWIAuUTJ3TT02yUOAPlVP4p7zxi40ysQYSLUiD6dEODJc9d3ugFgM8EMnrgYiKw6fbLyn4dixls8CCg==", "dependencies": { - "Microsoft.AspNetCore.Connections.Abstractions": "7.0.3" + "Microsoft.AspNetCore.Connections.Abstractions": "7.0.9" } }, "Microsoft.AspNetCore.SignalR.Client.Core": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "QOwhLtPcuHEqT/pkxF6qRnclaG28Pq4nlvimlEMpEAuiq/+PIM2TX/pGuZ3CO+yrWwuSlqA7Jg6AWA3hoUleuw==", + "resolved": "7.0.9", + "contentHash": "+rWA87MIbhUQi2fKJUTc9cRJgvHfZJdJ32gnIUxCHZtvwAHtfLG7Lc7KnJXiur6yLtG0CqLOANSfBXr/OOUqQw==", "dependencies": { - "Microsoft.AspNetCore.SignalR.Common": "7.0.3", - "Microsoft.AspNetCore.SignalR.Protocols.Json": "7.0.3", + "Microsoft.AspNetCore.SignalR.Common": "7.0.9", + "Microsoft.AspNetCore.SignalR.Protocols.Json": "7.0.9", "Microsoft.Extensions.DependencyInjection": "7.0.0", "Microsoft.Extensions.Logging": "7.0.0", "System.Threading.Channels": "7.0.0" @@ -154,33 +154,33 @@ }, "Microsoft.AspNetCore.SignalR.Common": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "Pm4+wwzr7ULOQrq6tlLuLMdtY2YYtXkHz90oMM+CSpV1SKlvfLabRSevd4No2U7PVykAan7kYgKN8HSxTYf1RA==", + "resolved": "7.0.9", + "contentHash": "u+mm77kNAm2qDjyXhZJnNDY1g0W6Tql4TbLClITMIK54KmOn+lzTsdpFBb41qJ1Jr1Qj+nC0yAXffEga008T6g==", "dependencies": { - "Microsoft.AspNetCore.Connections.Abstractions": "7.0.3", + "Microsoft.AspNetCore.Connections.Abstractions": "7.0.9", "Microsoft.Extensions.Options": "7.0.1" } }, "Microsoft.AspNetCore.SignalR.Protocols.Json": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "+DUVF6FdhMC4v7g/QaNor7hVBCy7+FHjC6h2HByvHxqJSj7i1y/m/4hg8nOTMhrj9BDbPeGK0b9NRrtrM83QmQ==", + "resolved": "7.0.9", + "contentHash": "0kUF1Vqd+Z42ihHjSShSQfayheIZENn1WamPMd/PB9+upEYP8jJDr+8MtCeYNwzxhmzu2UqfgeTeWJ96SZpzhQ==", "dependencies": { - "Microsoft.AspNetCore.SignalR.Common": "7.0.3" + "Microsoft.AspNetCore.SignalR.Common": "7.0.9" } }, "Microsoft.AspNetCore.SpaServices.Extensions": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "dh2ZmM+4Y3b3pCBndGuvpBIp1OOOK+CeZruphDKoFWgmxfN/RYmV0QvOS3u1McVb1yFmcVcXgVx0DEW5+WRkFg==", + "resolved": "7.0.9", + "contentHash": "qPuCTxQD832rs6vH5W8nVowU+BiWh45uH8+WnhEFiqgjGAGO8gw9Yf2aO4m0+VBi60kLwM8KYwYyLlpm0A8tbA==", "dependencies": { "Microsoft.Extensions.FileProviders.Physical": "7.0.0" } }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.5.0", - "contentHash": "6FQo0O6LKDqbCiIgVQhJAf810HSjFlOj7FunWaeOGDKxy8DAbpHzPk4SfBTXz9ytaaceuIIeR6hZgplt09m+ig==" + "resolved": "17.6.3", + "contentHash": "Gorg6F1dOxlI28yHYKhbQ3pOOfHeW6sUfsmwFQFaIV+xttUAZ+l8KarHIfsR+rBAnjY9VH71BXvPXBuObCkXsw==" }, "Microsoft.CSharp": { "type": "Transitive", @@ -189,19 +189,19 @@ }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "pCmzLLWTIrIv94o7JtQ1qcPD0oc1YNY9XvlO6/tOF9YCcUfDZ3Tx9Z//CM7hFnprduHFPekif7jteBc/sXQ31Q==", + "resolved": "7.0.9", + "contentHash": "ow2PPoeW0yFc7NhexacQUw/LVjkO1mLK3VZAxhVIVjmQWlgYl/4mo9/U7uz+z75I+ZN6LUvq9M0ftU3IE75Ilg==", "dependencies": { "SQLitePCLRaw.core": "2.1.4" } }, "Microsoft.EntityFrameworkCore": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "6XUI2YGoaLMoP9KGaqWmmd4B2n5bpQbXrVRpH20Et3YjQ0Rn3Ia6HM/ANcSq9rBfjfUySgo9SwUZgQ4m4PF3LQ==", + "resolved": "7.0.9", + "contentHash": "9YuCdQWuRAmYYHqwW1h5ukKMC1fmNvcVHdp3gb8zdHxwSQz7hkGpYOBEjm6dRXRmGRkpUyHL8rwUz4kd53Ev0A==", "dependencies": { - "Microsoft.EntityFrameworkCore.Abstractions": "7.0.3", - "Microsoft.EntityFrameworkCore.Analyzers": "7.0.3", + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.9", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.9", "Microsoft.Extensions.Caching.Memory": "7.0.0", "Microsoft.Extensions.DependencyInjection": "7.0.0", "Microsoft.Extensions.Logging": "7.0.0" @@ -209,39 +209,39 @@ }, "Microsoft.EntityFrameworkCore.Abstractions": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "0NaFBZykUlQHknddRuKY4v+MFZX/AW+v2V85dgj7abIlt+kL3GWa7QNH5S1084VLf1u+dq1SnhZsOvykc3Y0sA==" + "resolved": "7.0.9", + "contentHash": "cfY6Fn7cnP/5pXndL8QYaey/B2nGn1fwze5aSaMJymmbqwqYzFiszHuWbsdVBCDYJc8ok7eB1m/nCc3/rltulQ==" }, "Microsoft.EntityFrameworkCore.Analyzers": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "CLyRWFLwaOUZNPEia/aBMzFxZqm/ITKt3B+yUFtrg4Ys5VF3n2gvneuItC9IhpeOcjfdSgu/yUKf8y/IsNHs5A==" + "resolved": "7.0.9", + "contentHash": "VvqFD3DdML6LhPCAR/lG2xNX66juylC8v57yUAAYnUSdEUOMRi3lNoT4OrNdG0rere3UOQPhvVl5FH2QdyoF8Q==" }, "Microsoft.EntityFrameworkCore.Relational": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "RxNNjtTrxsMtdBtgoXGRSy8uCXaBHaVzIonTeo7+Ys+N0yEWwhf2E74cxneyunMi13Ezlld10ecCHlDubEU/Pw==", + "resolved": "7.0.9", + "contentHash": "u7iN6cNd6SJUlpdk24JVIbkji/UbkEEQ7pXncTyT4eXXj+Hz2y4NSZFOAywPGcioIgX1YzbKWDiJhk7hjSFxBQ==", "dependencies": { - "Microsoft.EntityFrameworkCore": "7.0.3", + "Microsoft.EntityFrameworkCore": "7.0.9", "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" } }, "Microsoft.EntityFrameworkCore.Sqlite": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "bNWgYJsT6+0I98RSIY0rZAYu6NkLFgPvWPO1LKTsBqG6iwhCW3M38JGDVOOSf69N9HUZz9ilKNLTyYKNRQkyGw==", + "resolved": "7.0.9", + "contentHash": "otP72XqfG9UdO0+3O2p1UEx4MLXSAulXc8tIvuq+v1KPtBj/GuMZeJIz+eCu09Xv6fJ6k7aUb8J/x+H0rqOjjA==", "dependencies": { - "Microsoft.EntityFrameworkCore.Sqlite.Core": "7.0.3", + "Microsoft.EntityFrameworkCore.Sqlite.Core": "7.0.9", "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" } }, "Microsoft.EntityFrameworkCore.Sqlite.Core": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "w0yzGr1IDY4sp+RkFnVlWVF1N2lmaJHCmzVldZ/e36bXdT95E8N7/+JYWwKm1nLWEpS6naaoNtqQO6buRHTfAg==", + "resolved": "7.0.9", + "contentHash": "uLy1swPL4AD6BQsu3SEIzSWKc6gIlmoSAYZX39VnbrqvzkGmMsgEgdCsJIZvdjAW/vzhPazACKMYna1iif04sg==", "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.3", - "Microsoft.EntityFrameworkCore.Relational": "7.0.3", + "Microsoft.Data.Sqlite.Core": "7.0.9", + "Microsoft.EntityFrameworkCore.Relational": "7.0.9", "Microsoft.Extensions.DependencyModel": "7.0.0" } }, @@ -302,8 +302,8 @@ }, "Microsoft.Extensions.Features": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "LnHGYYYi4dX5XcW1J4QPyMqfWw6cKF9Hp23f3BMTl3kytUGv19K6E9nWA83/SVahzVLwL+RrR02o14VUMBUlug==" + "resolved": "7.0.9", + "contentHash": "IJ2vdDt2OYCKyJ7ZJPIZKa4b0M0tsG36h0QUt1d/E8IMAnjIncI+1i9Am0nmheD/wpcVd9eDykiV4dklcwUd3Q==" }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", @@ -349,8 +349,8 @@ }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==" + "resolved": "7.0.1", + "contentHash": "pkeBFx0vqMW/A3aUVHh7MPu3WkBhaVlezhSZeb1c9XD0vUReYH1TLFSy5MxJgZfmz5LZzYoErMorlYZiwpOoNA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", @@ -368,8 +368,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -378,19 +378,19 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.5.0", - "contentHash": "QwiBJcC/oEA1kojOaB0uPWOIo4i6BYuTBBYJVhUvmXkyYqZ2Ut/VZfgi+enf8LF8J4sjO98oRRFt39MiRorcIw==", + "resolved": "17.6.3", + "contentHash": "gSqtX3RvcFisaLPs6sKXdZkSwUix83NQ9nOU/w6pYrHTl+d8GsVHSL9rvDNxMgoV5BNOdyU7zK7JOfbSaVMDWQ==", "dependencies": { - "NuGet.Frameworks": "5.11.0", + "NuGet.Frameworks": "6.5.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.5.0", - "contentHash": "X86aikwp9d4SDcBChwzQYZihTPGEtMdDk+9t64emAl7N0Tq+OmlLAoW+Rs+2FB2k6QdUicSlT4QLO2xABRokaw==", + "resolved": "17.6.3", + "contentHash": "lrgRXKFfIZSPlhuoQGLtciO/osL+4oADYEYb0d5or7n7YyJATIWespq3lRgz2IQpRh6N7cm0DnCOWeZiCRGzxA==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.5.0", + "Microsoft.TestPlatform.ObjectModel": "17.6.3", "Newtonsoft.Json": "13.0.1" } }, @@ -406,8 +406,8 @@ }, "Namotion.Reflection": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "9t63RauDp+CWzMCcCRAGXLRqEVIw0djYisGaDWhgHuXSaz/Djjpp9gpumCWVLpuDHLNf4HUmYWJeBt4AUyJSWA==", + "resolved": "2.1.2", + "contentHash": "7tSHAzX8GWKy0qrW6OgQWD7kAZiqzhq+m1503qczuwuK6ZYhOGCQUxw+F3F4KkRM70aB6RMslsRVSCFeouIehw==", "dependencies": { "Microsoft.CSharp": "4.3.0" } @@ -470,85 +470,85 @@ }, "NJsonSchema": { "type": "Transitive", - "resolved": "10.8.0", - "contentHash": "lChjsLWaxyvElh4WJjVhdIiCtx7rimYGFTxtSi2pAkZf0ZnKaXYIX484HCVyzbDDHejDZPgOrcfAJ3kqNSTONw==", + "resolved": "10.9.0", + "contentHash": "IBPo6Srxn2MEcIFM3HdM4QImrJbsIeujENQyzHL2Pv6wLsKSYAyAEilecRqaLOhoy3snEiPLx7hhv7opbhOxKQ==", "dependencies": { - "Namotion.Reflection": "2.1.0", + "Namotion.Reflection": "2.1.2", "Newtonsoft.Json": "9.0.1" } }, "NJsonSchema.Yaml": { "type": "Transitive", - "resolved": "10.8.0", - "contentHash": "sygi7CN1AQHFNfpk/RRgsAMl+5tTM65Rajau3QPKoflJoZbxPQLBgZZrH7SMINumkW61JqDy6EhKfHsxngTzqw==", + "resolved": "10.9.0", + "contentHash": "lGOtsydEnX1mVLT2Cyre7mST7K7crveYtai9FGC2i7COKEMEFjsfbnUtgXSHKxS/bzxVEIjLa49tR6xw34WkEw==", "dependencies": { "Microsoft.CSharp": "4.4.1", - "NJsonSchema": "10.8.0", + "NJsonSchema": "10.9.0", "YamlDotNet": "11.2.1" } }, "NSwag.Annotations": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "2zDLZXEU1PVuvdMc1k+SIkLonp8vPRHAkto6qQfCeCPqhDaF82+FOWe3TLJIYBS8IC7aV/mT+eoqJLeZvXiN4A==" + "resolved": "13.19.0", + "contentHash": "ukpuIdZTczGUwyIAz954xiefikAUShtEoColOODeKilKGcB5CXn1Q6j3D/Er75z2+qMA3qieXb386xAyW2/v+Q==" }, "NSwag.AspNetCore": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "ueewpltbJpZGWgR3BkLXQRX1g7ZtzNl7sT5DI90lNufJhLWnjC5nAfxRTP4J8nqO1vR79zLYzzA5ZwsusZaTpA==", + "resolved": "13.19.0", + "contentHash": "7ZPAHrJCMPuDN3kE5bZIckWIVtorMj3YCU0bYu83CqVBsOGlxUy6VS8CnmLHlmAJ5gxEA+RD+KGepJvk3u+ygQ==", "dependencies": { "Microsoft.Extensions.ApiDescription.Server": "6.0.3", "Microsoft.Extensions.FileProviders.Embedded": "[7.0.0, 8.0.0)", - "NSwag.Annotations": "13.18.2", - "NSwag.Core": "13.18.2", - "NSwag.Core.Yaml": "13.18.2", - "NSwag.Generation": "13.18.2", - "NSwag.Generation.AspNetCore": "13.18.2" + "NSwag.Annotations": "13.19.0", + "NSwag.Core": "13.19.0", + "NSwag.Core.Yaml": "13.19.0", + "NSwag.Generation": "13.19.0", + "NSwag.Generation.AspNetCore": "13.19.0" } }, "NSwag.Core": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "QM6OnVtUkD62fi0lgFF65KbZ0Y8ToGD+Rb4W3Nz6ymCWWfVbMwkn8xUxIjWSLsOEYJCbLvBBeGt+oBNrJwxb+A==", + "resolved": "13.19.0", + "contentHash": "UkPCsEJ5WaE6mcEjarZZfMPyyRPHOWK9YuFvxNjrSHclCxVUZ7jgFtNGMX0wy0WvXkmA5b6H9IoaAJECMxcu/g==", "dependencies": { - "NJsonSchema": "10.8.0", + "NJsonSchema": "10.9.0", "Newtonsoft.Json": "10.0.1" } }, "NSwag.Core.Yaml": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "y+h+4jrN3BC0B3v1Qg0Fr3jrGTB5nR5RAn5ZG5qBveiazeB9VDfR5cP9URN6wb3VypahHRzYryUB2KFZuiS22A==", + "resolved": "13.19.0", + "contentHash": "F97HsEclpnydInq1Wrd74WDQePHQ7S+e4yKi4BiYi/hLy6s88YlpRFB3R5Bx64iRkGKesU/uGiovKtFevpW2Bw==", "dependencies": { - "NJsonSchema.Yaml": "10.8.0", - "NSwag.Core": "13.18.2", + "NJsonSchema.Yaml": "10.9.0", + "NSwag.Core": "13.19.0", "YamlDotNet": "11.2.1" } }, "NSwag.Generation": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "hmdi+kXwKTgxu2aYgaILDw2nKvco1/wEd1RXaVNIz4ck6yHTJ58ANVcUjN3ytmL//f+hKEKWZznTi4YQW7jtpQ==", + "resolved": "13.19.0", + "contentHash": "TdBY+P6WGElaHIAzYaT9te141y46UCUTjlGgGKi5eR4ZXHE/JhmrXXU8kr3zFHWw7gk6TeOKy5LnPlJaxNXb5Q==", "dependencies": { - "NJsonSchema": "10.8.0", - "NSwag.Core": "13.18.2", + "NJsonSchema": "10.9.0", + "NSwag.Core": "13.19.0", "Newtonsoft.Json": "10.0.1" } }, "NSwag.Generation.AspNetCore": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "D+yfRbXtv/wDan1oEkskGWejlCiUTdLlV93qynay1Xp1HmnC0XYspjLkfMGr9kqYX4CY9SrMUnDUsRNeyOoR/g==", + "resolved": "13.19.0", + "contentHash": "1ne3rqJtWTUbZuN/kyCTk1cT36ZLXZs2/tE6Kvhb8MA6GySbwSwaLIJ1eHFn6dksp5+Ic5EhI1ZL6wrqapQgsg==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "[7.0.0, 8.0.0)", "Microsoft.Extensions.Options": "[7.0.0, 8.0.0)", - "NSwag.Generation": "13.18.2" + "NSwag.Generation": "13.19.0" } }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.11.0", - "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" + "resolved": "6.5.0", + "contentHash": "QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg==" }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { "type": "Transitive", @@ -659,12 +659,8 @@ }, "SixLabors.ImageSharp": { "type": "Transitive", - "resolved": "2.1.3", - "contentHash": "8yonNRWX3vUE9k29ta0Hbfa0AEc0hbDjSH/nZ3vOTJEXmY6hLnGsjDKoz96Z+AgOsrdkAu6PdL/Ebaf70aitzw==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "5.0.0", - "System.Text.Encoding.CodePages": "5.0.0" - } + "resolved": "3.0.1", + "contentHash": "o0v/J6SJwp3RFrzR29beGx0cK7xcMRgOyIuw8ZNLQyNnBhiyL/vIQKn7cfycthcWUPG3XezUjFwBWzkcUUDFbg==" }, "SQLitePCLRaw.bundle_e_sqlite3": { "type": "Transitive", @@ -1133,11 +1129,6 @@ "Microsoft.NETCore.Targets": "1.1.0" } }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" - }, "System.Runtime.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -1355,14 +1346,6 @@ "System.Runtime": "4.3.0" } }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "NyscU59xX6Uo91qvhOs2Ccho3AR2TnZPomo1Z0K6YpyztBPM/A5VbkzOO19sy3A3i1TtEnTxA7bCe3Us+r5MWg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "5.0.0" - } - }, "System.Text.Encoding.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -1487,30 +1470,30 @@ }, "xunit.analyzers": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" + "resolved": "1.2.0", + "contentHash": "d3dehV/DASLRlR8stWQmbPPjfYC2tct50Evav+OlsJMkfFqkhYvzO1k0s81lk0px8O0knZU/FqC8SqbXOtn+hw==" }, "xunit.assert": { "type": "Transitive", - "resolved": "2.4.2", - "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", + "resolved": "2.5.0", + "contentHash": "wN84pKX5jzfpgJ0bB6arrCA/oelBeYLCpnQ9Wj5xGEVPydKzVSDY5tEatFLHE/rO0+0RC+I4H5igGE118jRh1w==", "dependencies": { "NETStandard.Library": "1.6.1" } }, "xunit.core": { "type": "Transitive", - "resolved": "2.4.2", - "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", + "resolved": "2.5.0", + "contentHash": "dnV0Mn2s1C0y2m33AylQyMkEyhBQsL4R0302kwSGiEGuY3JwzEmhTa9pnghyMRPliYSs4fXfkEAP+5bKXryGFg==", "dependencies": { - "xunit.extensibility.core": "[2.4.2]", - "xunit.extensibility.execution": "[2.4.2]" + "xunit.extensibility.core": "[2.5.0]", + "xunit.extensibility.execution": "[2.5.0]" } }, "xunit.extensibility.core": { "type": "Transitive", - "resolved": "2.4.2", - "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", + "resolved": "2.5.0", + "contentHash": "xRm6NIV3i7I+LkjsAJ91Xz2fxJm/oMEi2CYq1G5HlGTgcK1Zo2wNbLO6nKX1VG5FZzXibSdoLwr/MofVvh3mFA==", "dependencies": { "NETStandard.Library": "1.6.1", "xunit.abstractions": "2.0.3" @@ -1518,11 +1501,11 @@ }, "xunit.extensibility.execution": { "type": "Transitive", - "resolved": "2.4.2", - "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", + "resolved": "2.5.0", + "contentHash": "7+v2Bvp+1ew1iMGQVb1glICi8jcNdHbRUX6Ru0dmJBViGdjiS7kyqcX2VxleQhFbKNi+WF0an7/TeTXD283RlQ==", "dependencies": { "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.2]" + "xunit.extensibility.core": "[2.5.0]" } }, "YamlDotNet": { @@ -1534,14 +1517,14 @@ "type": "Project", "dependencies": { "AutoMapper": "[12.0.1, )", - "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.0, )", - "Markdig": "[0.30.4, )", - "Microsoft.AspNetCore.SpaServices.Extensions": "[7.0.3, )", - "Microsoft.EntityFrameworkCore": "[7.0.3, )", - "Microsoft.EntityFrameworkCore.Analyzers": "[7.0.3, )", - "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.3, )", - "NSwag.AspNetCore": "[13.18.2, )", - "SixLabors.ImageSharp": "[2.1.3, )" + "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", + "Markdig": "[0.31.0, )", + "Microsoft.AspNetCore.SpaServices.Extensions": "[7.0.9, )", + "Microsoft.EntityFrameworkCore": "[7.0.9, )", + "Microsoft.EntityFrameworkCore.Analyzers": "[7.0.9, )", + "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.9, )", + "NSwag.AspNetCore": "[13.19.0, )", + "SixLabors.ImageSharp": "[3.0.1, )" } } } diff --git a/BackEnd/Timeline/Timeline.csproj b/BackEnd/Timeline/Timeline.csproj index 6000cdb5..92fc6dec 100644 --- a/BackEnd/Timeline/Timeline.csproj +++ b/BackEnd/Timeline/Timeline.csproj @@ -29,18 +29,18 @@ - - - - - - - + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + diff --git a/BackEnd/Timeline/packages.lock.json b/BackEnd/Timeline/packages.lock.json index 3dc3a828..e6716f52 100644 --- a/BackEnd/Timeline/packages.lock.json +++ b/BackEnd/Timeline/packages.lock.json @@ -13,37 +13,37 @@ }, "AutoMapper.Extensions.Microsoft.DependencyInjection": { "type": "Direct", - "requested": "[12.0.0, )", - "resolved": "12.0.0", - "contentHash": "XCJ4E3oKrbRl1qY9Mr+7uyC0xZj1+bqQjmQRWTiTKiVuuXTny+7YFWHi20tPjwkMukLbicN6yGlDy5PZ4wyi1w==", + "requested": "[12.0.1, )", + "resolved": "12.0.1", + "contentHash": "+g/K+Vpe3gGMKGzjslMOdqNlkikScDjWfVvmWTayrDHaG/n2pPmFBMa+jKX1r/h6BDGFdkyRjAuhFE3ykW+r1g==", "dependencies": { - "AutoMapper": "12.0.0", + "AutoMapper": "[12.0.1]", "Microsoft.Extensions.Options": "6.0.0" } }, "Markdig": { "type": "Direct", - "requested": "[0.30.4, )", - "resolved": "0.30.4", - "contentHash": "9LL7Mzubwf6QmOTZIqf+vERiinqPA1H+irBA38POhr93W/it00AvFWaCtF80+8VJTooFmcAJyZT2f60t1f88eQ==" + "requested": "[0.31.0, )", + "resolved": "0.31.0", + "contentHash": "CEdZ3KyFfz5IPMrofhCOSrc4O2KNvSXSMXt3fv0W5AFCsk6a/JhKZuTBxGSadNt8n4zyyd/xXfoUMvr4ZbZ4Fw==" }, "Microsoft.AspNetCore.SpaServices.Extensions": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "dh2ZmM+4Y3b3pCBndGuvpBIp1OOOK+CeZruphDKoFWgmxfN/RYmV0QvOS3u1McVb1yFmcVcXgVx0DEW5+WRkFg==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "qPuCTxQD832rs6vH5W8nVowU+BiWh45uH8+WnhEFiqgjGAGO8gw9Yf2aO4m0+VBi60kLwM8KYwYyLlpm0A8tbA==", "dependencies": { "Microsoft.Extensions.FileProviders.Physical": "7.0.0" } }, "Microsoft.EntityFrameworkCore": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "6XUI2YGoaLMoP9KGaqWmmd4B2n5bpQbXrVRpH20Et3YjQ0Rn3Ia6HM/ANcSq9rBfjfUySgo9SwUZgQ4m4PF3LQ==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "9YuCdQWuRAmYYHqwW1h5ukKMC1fmNvcVHdp3gb8zdHxwSQz7hkGpYOBEjm6dRXRmGRkpUyHL8rwUz4kd53Ev0A==", "dependencies": { - "Microsoft.EntityFrameworkCore.Abstractions": "7.0.3", - "Microsoft.EntityFrameworkCore.Analyzers": "7.0.3", + "Microsoft.EntityFrameworkCore.Abstractions": "7.0.9", + "Microsoft.EntityFrameworkCore.Analyzers": "7.0.9", "Microsoft.Extensions.Caching.Memory": "7.0.0", "Microsoft.Extensions.DependencyInjection": "7.0.0", "Microsoft.Extensions.Logging": "7.0.0" @@ -51,53 +51,49 @@ }, "Microsoft.EntityFrameworkCore.Analyzers": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "CLyRWFLwaOUZNPEia/aBMzFxZqm/ITKt3B+yUFtrg4Ys5VF3n2gvneuItC9IhpeOcjfdSgu/yUKf8y/IsNHs5A==" + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "VvqFD3DdML6LhPCAR/lG2xNX66juylC8v57yUAAYnUSdEUOMRi3lNoT4OrNdG0rere3UOQPhvVl5FH2QdyoF8Q==" }, "Microsoft.EntityFrameworkCore.Sqlite": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "bNWgYJsT6+0I98RSIY0rZAYu6NkLFgPvWPO1LKTsBqG6iwhCW3M38JGDVOOSf69N9HUZz9ilKNLTyYKNRQkyGw==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "otP72XqfG9UdO0+3O2p1UEx4MLXSAulXc8tIvuq+v1KPtBj/GuMZeJIz+eCu09Xv6fJ6k7aUb8J/x+H0rqOjjA==", "dependencies": { - "Microsoft.EntityFrameworkCore.Sqlite.Core": "7.0.3", + "Microsoft.EntityFrameworkCore.Sqlite.Core": "7.0.9", "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" } }, "Microsoft.EntityFrameworkCore.Tools": { "type": "Direct", - "requested": "[7.0.3, )", - "resolved": "7.0.3", - "contentHash": "yHFlYPZS3Jx7JMCQnGKfJzv95rJWVcmcUn/OW5cbCyWgQk81JJpTZ9Q6kkvwquYjFRfvYHBGuXNIYhAJokOBTQ==", + "requested": "[7.0.9, )", + "resolved": "7.0.9", + "contentHash": "GWOSIe8ltR/mqv2wpRvMhy6ULapdKhZXXpXSGWzG1fRxhYXjSGpe2Pqhxqo46o9RDGlk0WJUXrwyU+N4voPxMw==", "dependencies": { - "Microsoft.EntityFrameworkCore.Design": "7.0.3" + "Microsoft.EntityFrameworkCore.Design": "7.0.9" } }, "NSwag.AspNetCore": { "type": "Direct", - "requested": "[13.18.2, )", - "resolved": "13.18.2", - "contentHash": "ueewpltbJpZGWgR3BkLXQRX1g7ZtzNl7sT5DI90lNufJhLWnjC5nAfxRTP4J8nqO1vR79zLYzzA5ZwsusZaTpA==", + "requested": "[13.19.0, )", + "resolved": "13.19.0", + "contentHash": "7ZPAHrJCMPuDN3kE5bZIckWIVtorMj3YCU0bYu83CqVBsOGlxUy6VS8CnmLHlmAJ5gxEA+RD+KGepJvk3u+ygQ==", "dependencies": { "Microsoft.Extensions.ApiDescription.Server": "6.0.3", "Microsoft.Extensions.FileProviders.Embedded": "[7.0.0, 8.0.0)", - "NSwag.Annotations": "13.18.2", - "NSwag.Core": "13.18.2", - "NSwag.Core.Yaml": "13.18.2", - "NSwag.Generation": "13.18.2", - "NSwag.Generation.AspNetCore": "13.18.2" + "NSwag.Annotations": "13.19.0", + "NSwag.Core": "13.19.0", + "NSwag.Core.Yaml": "13.19.0", + "NSwag.Generation": "13.19.0", + "NSwag.Generation.AspNetCore": "13.19.0" } }, "SixLabors.ImageSharp": { "type": "Direct", - "requested": "[2.1.3, )", - "resolved": "2.1.3", - "contentHash": "8yonNRWX3vUE9k29ta0Hbfa0AEc0hbDjSH/nZ3vOTJEXmY6hLnGsjDKoz96Z+AgOsrdkAu6PdL/Ebaf70aitzw==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "5.0.0", - "System.Text.Encoding.CodePages": "5.0.0" - } + "requested": "[3.0.1, )", + "resolved": "3.0.1", + "contentHash": "o0v/J6SJwp3RFrzR29beGx0cK7xcMRgOyIuw8ZNLQyNnBhiyL/vIQKn7cfycthcWUPG3XezUjFwBWzkcUUDFbg==" }, "Humanizer.Core": { "type": "Transitive", @@ -111,44 +107,44 @@ }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "pCmzLLWTIrIv94o7JtQ1qcPD0oc1YNY9XvlO6/tOF9YCcUfDZ3Tx9Z//CM7hFnprduHFPekif7jteBc/sXQ31Q==", + "resolved": "7.0.9", + "contentHash": "ow2PPoeW0yFc7NhexacQUw/LVjkO1mLK3VZAxhVIVjmQWlgYl/4mo9/U7uz+z75I+ZN6LUvq9M0ftU3IE75Ilg==", "dependencies": { "SQLitePCLRaw.core": "2.1.4" } }, "Microsoft.EntityFrameworkCore.Abstractions": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "0NaFBZykUlQHknddRuKY4v+MFZX/AW+v2V85dgj7abIlt+kL3GWa7QNH5S1084VLf1u+dq1SnhZsOvykc3Y0sA==" + "resolved": "7.0.9", + "contentHash": "cfY6Fn7cnP/5pXndL8QYaey/B2nGn1fwze5aSaMJymmbqwqYzFiszHuWbsdVBCDYJc8ok7eB1m/nCc3/rltulQ==" }, "Microsoft.EntityFrameworkCore.Design": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "Nv0Y2Zh8d919qKq8Q1bvbWQbFeb4JQ7jCuakajSVtip5JIwt4hTIWetVIapJ2vOQDDZuAHCzkjimMOlHH5LVsQ==", + "resolved": "7.0.9", + "contentHash": "tWsa+spzKZAwHrUP6vYM1LLh0P89UMcldEjerFPPZb0LcI/ONQmh7ldK4Q8TeRuIiuXxYgRYPElSgxwLp14oug==", "dependencies": { "Humanizer.Core": "2.14.1", - "Microsoft.EntityFrameworkCore.Relational": "7.0.3", + "Microsoft.EntityFrameworkCore.Relational": "7.0.9", "Microsoft.Extensions.DependencyModel": "7.0.0", "Mono.TextTemplating": "2.2.1" } }, "Microsoft.EntityFrameworkCore.Relational": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "RxNNjtTrxsMtdBtgoXGRSy8uCXaBHaVzIonTeo7+Ys+N0yEWwhf2E74cxneyunMi13Ezlld10ecCHlDubEU/Pw==", + "resolved": "7.0.9", + "contentHash": "u7iN6cNd6SJUlpdk24JVIbkji/UbkEEQ7pXncTyT4eXXj+Hz2y4NSZFOAywPGcioIgX1YzbKWDiJhk7hjSFxBQ==", "dependencies": { - "Microsoft.EntityFrameworkCore": "7.0.3", + "Microsoft.EntityFrameworkCore": "7.0.9", "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" } }, "Microsoft.EntityFrameworkCore.Sqlite.Core": { "type": "Transitive", - "resolved": "7.0.3", - "contentHash": "w0yzGr1IDY4sp+RkFnVlWVF1N2lmaJHCmzVldZ/e36bXdT95E8N7/+JYWwKm1nLWEpS6naaoNtqQO6buRHTfAg==", + "resolved": "7.0.9", + "contentHash": "uLy1swPL4AD6BQsu3SEIzSWKc6gIlmoSAYZX39VnbrqvzkGmMsgEgdCsJIZvdjAW/vzhPazACKMYna1iif04sg==", "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.3", - "Microsoft.EntityFrameworkCore.Relational": "7.0.3", + "Microsoft.Data.Sqlite.Core": "7.0.9", + "Microsoft.EntityFrameworkCore.Relational": "7.0.9", "Microsoft.Extensions.DependencyModel": "7.0.0" } }, @@ -270,8 +266,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -288,8 +284,8 @@ }, "Namotion.Reflection": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "9t63RauDp+CWzMCcCRAGXLRqEVIw0djYisGaDWhgHuXSaz/Djjpp9gpumCWVLpuDHLNf4HUmYWJeBt4AUyJSWA==", + "resolved": "2.1.2", + "contentHash": "7tSHAzX8GWKy0qrW6OgQWD7kAZiqzhq+m1503qczuwuK6ZYhOGCQUxw+F3F4KkRM70aB6RMslsRVSCFeouIehw==", "dependencies": { "Microsoft.CSharp": "4.3.0" } @@ -329,65 +325,65 @@ }, "NJsonSchema": { "type": "Transitive", - "resolved": "10.8.0", - "contentHash": "lChjsLWaxyvElh4WJjVhdIiCtx7rimYGFTxtSi2pAkZf0ZnKaXYIX484HCVyzbDDHejDZPgOrcfAJ3kqNSTONw==", + "resolved": "10.9.0", + "contentHash": "IBPo6Srxn2MEcIFM3HdM4QImrJbsIeujENQyzHL2Pv6wLsKSYAyAEilecRqaLOhoy3snEiPLx7hhv7opbhOxKQ==", "dependencies": { - "Namotion.Reflection": "2.1.0", + "Namotion.Reflection": "2.1.2", "Newtonsoft.Json": "9.0.1" } }, "NJsonSchema.Yaml": { "type": "Transitive", - "resolved": "10.8.0", - "contentHash": "sygi7CN1AQHFNfpk/RRgsAMl+5tTM65Rajau3QPKoflJoZbxPQLBgZZrH7SMINumkW61JqDy6EhKfHsxngTzqw==", + "resolved": "10.9.0", + "contentHash": "lGOtsydEnX1mVLT2Cyre7mST7K7crveYtai9FGC2i7COKEMEFjsfbnUtgXSHKxS/bzxVEIjLa49tR6xw34WkEw==", "dependencies": { "Microsoft.CSharp": "4.4.1", - "NJsonSchema": "10.8.0", + "NJsonSchema": "10.9.0", "YamlDotNet": "11.2.1" } }, "NSwag.Annotations": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "2zDLZXEU1PVuvdMc1k+SIkLonp8vPRHAkto6qQfCeCPqhDaF82+FOWe3TLJIYBS8IC7aV/mT+eoqJLeZvXiN4A==" + "resolved": "13.19.0", + "contentHash": "ukpuIdZTczGUwyIAz954xiefikAUShtEoColOODeKilKGcB5CXn1Q6j3D/Er75z2+qMA3qieXb386xAyW2/v+Q==" }, "NSwag.Core": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "QM6OnVtUkD62fi0lgFF65KbZ0Y8ToGD+Rb4W3Nz6ymCWWfVbMwkn8xUxIjWSLsOEYJCbLvBBeGt+oBNrJwxb+A==", + "resolved": "13.19.0", + "contentHash": "UkPCsEJ5WaE6mcEjarZZfMPyyRPHOWK9YuFvxNjrSHclCxVUZ7jgFtNGMX0wy0WvXkmA5b6H9IoaAJECMxcu/g==", "dependencies": { - "NJsonSchema": "10.8.0", + "NJsonSchema": "10.9.0", "Newtonsoft.Json": "10.0.1" } }, "NSwag.Core.Yaml": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "y+h+4jrN3BC0B3v1Qg0Fr3jrGTB5nR5RAn5ZG5qBveiazeB9VDfR5cP9URN6wb3VypahHRzYryUB2KFZuiS22A==", + "resolved": "13.19.0", + "contentHash": "F97HsEclpnydInq1Wrd74WDQePHQ7S+e4yKi4BiYi/hLy6s88YlpRFB3R5Bx64iRkGKesU/uGiovKtFevpW2Bw==", "dependencies": { - "NJsonSchema.Yaml": "10.8.0", - "NSwag.Core": "13.18.2", + "NJsonSchema.Yaml": "10.9.0", + "NSwag.Core": "13.19.0", "YamlDotNet": "11.2.1" } }, "NSwag.Generation": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "hmdi+kXwKTgxu2aYgaILDw2nKvco1/wEd1RXaVNIz4ck6yHTJ58ANVcUjN3ytmL//f+hKEKWZznTi4YQW7jtpQ==", + "resolved": "13.19.0", + "contentHash": "TdBY+P6WGElaHIAzYaT9te141y46UCUTjlGgGKi5eR4ZXHE/JhmrXXU8kr3zFHWw7gk6TeOKy5LnPlJaxNXb5Q==", "dependencies": { - "NJsonSchema": "10.8.0", - "NSwag.Core": "13.18.2", + "NJsonSchema": "10.9.0", + "NSwag.Core": "13.19.0", "Newtonsoft.Json": "10.0.1" } }, "NSwag.Generation.AspNetCore": { "type": "Transitive", - "resolved": "13.18.2", - "contentHash": "D+yfRbXtv/wDan1oEkskGWejlCiUTdLlV93qynay1Xp1HmnC0XYspjLkfMGr9kqYX4CY9SrMUnDUsRNeyOoR/g==", + "resolved": "13.19.0", + "contentHash": "1ne3rqJtWTUbZuN/kyCTk1cT36ZLXZs2/tE6Kvhb8MA6GySbwSwaLIJ1eHFn6dksp5+Ic5EhI1ZL6wrqapQgsg==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "[7.0.0, 8.0.0)", "Microsoft.Extensions.Options": "[7.0.0, 8.0.0)", - "NSwag.Generation": "13.18.2" + "NSwag.Generation": "13.19.0" } }, "SQLitePCLRaw.bundle_e_sqlite3": { @@ -750,11 +746,6 @@ "Microsoft.NETCore.Targets": "1.1.0" } }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" - }, "System.Runtime.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -830,14 +821,6 @@ "System.Runtime": "4.3.0" } }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "NyscU59xX6Uo91qvhOs2Ccho3AR2TnZPomo1Z0K6YpyztBPM/A5VbkzOO19sy3A3i1TtEnTxA7bCe3Us+r5MWg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "5.0.0" - } - }, "System.Text.Encoding.Extensions": { "type": "Transitive", "resolved": "4.3.0", diff --git a/FrontEnd/.eslintignore b/FrontEnd/.eslintignore index 6fc7bee6..19d1b61c 100644 --- a/FrontEnd/.eslintignore +++ b/FrontEnd/.eslintignore @@ -1 +1,2 @@ dist +src/migrating diff --git a/FrontEnd/src/App.tsx b/FrontEnd/src/App.tsx index ca3e4d38..6029daac 100644 --- a/FrontEnd/src/App.tsx +++ b/FrontEnd/src/App.tsx @@ -10,8 +10,6 @@ import LoginPage from "./pages/login"; import RegisterPage from "./pages/register"; import TimelinePage from "./pages/timeline"; import LoadingPage from "./pages/loading"; -import Search from "./views/search"; -import Admin from "./views/admin"; import AlertHost from "./views/common/alert/AlertHost"; export default function App() { @@ -25,8 +23,6 @@ export default function App() { } /> } /> } /> - } /> - } /> } /> } /> } /> diff --git a/FrontEnd/src/migrating/admin/Admin.tsx b/FrontEnd/src/migrating/admin/Admin.tsx new file mode 100644 index 00000000..986c36b4 --- /dev/null +++ b/FrontEnd/src/migrating/admin/Admin.tsx @@ -0,0 +1,27 @@ +import { Route, Routes } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +import AdminNav from "./AdminNav"; +import UserAdmin from "./UserAdmin"; +import MoreAdmin from "./MoreAdmin"; + +import "./index.css"; + +const Admin: React.FC = () => { + useTranslation("admin"); + + return ( + <> +
+ + + } /> + } /> + } /> + +
+ + ); +}; + +export default Admin; diff --git a/FrontEnd/src/migrating/admin/AdminNav.tsx b/FrontEnd/src/migrating/admin/AdminNav.tsx new file mode 100644 index 00000000..b7385e5c --- /dev/null +++ b/FrontEnd/src/migrating/admin/AdminNav.tsx @@ -0,0 +1,29 @@ +import { useLocation } from "react-router-dom"; + +import Tabs from "../common/tab/Tabs"; + +export function AdminNav({ className }: { className?: string }) { + const location = useLocation(); + const name = location.pathname.split("/")[2] ?? "user"; + + return ( + + ); +} + +export default AdminNav; diff --git a/FrontEnd/src/migrating/admin/MoreAdmin.tsx b/FrontEnd/src/migrating/admin/MoreAdmin.tsx new file mode 100644 index 00000000..d49d211f --- /dev/null +++ b/FrontEnd/src/migrating/admin/MoreAdmin.tsx @@ -0,0 +1,7 @@ +import * as React from "react"; + +const MoreAdmin: React.FC = () => { + return <>More...; +}; + +export default MoreAdmin; diff --git a/FrontEnd/src/migrating/admin/UserAdmin.tsx b/FrontEnd/src/migrating/admin/UserAdmin.tsx new file mode 100644 index 00000000..08560c87 --- /dev/null +++ b/FrontEnd/src/migrating/admin/UserAdmin.tsx @@ -0,0 +1,301 @@ +// eslint-disable +// @ts-nocheck + +import { useState, useEffect } from "react"; +import * as React from "react"; +import { Trans, useTranslation } from "react-i18next"; +import classnames from "classnames"; + +import { getHttpUserClient, HttpUser, kUserPermissionList } from "@/http/user"; + +import OperationDialog from "../common/dialog/OperationDialog"; +import Button from "../common/button/Button"; +import Spinner from "../common/Spinner"; +import FlatButton from "../common/button/FlatButton"; +import IconButton from "../common/button/IconButton"; + +const CreateUserDialog: React.FC<{ + open: boolean; + close: () => void; + onSuccess: (user: HttpUser) => void; +}> = ({ open, close, onSuccess }) => { + return ( + + getHttpUserClient().post({ + username: username as string, + password: password as string, + }) + } + onClose={close} + open={open} + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UsernameLabel: React.FC<{ children: React.ReactNode }> = (props) => { + return {props.children}; +}; + +const UserDeleteDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + return ( + ( + + 0{user.username}2 + + )} + onProcess={() => getHttpUserClient().delete(user.username)} + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UserModifyDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + return ( + + 0{user.username}2 + + } + inputs={ + [ + { + type: "text", + label: "admin:user.username", + initValue: user.username, + }, + { type: "text", label: "admin:user.password" }, + { + type: "text", + label: "admin:user.nickname", + initValue: user.nickname, + }, + ] as const + } + onProcess={([username, password, nickname]) => + getHttpUserClient().patch(user.username, { + username: username !== user.username ? username : undefined, + password: password !== "" ? password : undefined, + nickname: nickname !== user.nickname ? nickname : undefined, + }) + } + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UserPermissionModifyDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + const oldPermissionBoolList: boolean[] = kUserPermissionList.map( + (permission) => user.permissions.includes(permission), + ); + + return ( + ( + + 0{user.username}2 + + )} + inputScheme={kUserPermissionList.map( + (permission, index) => ({ + type: "bool", + label: { type: "custom", value: permission }, + initValue: oldPermissionBoolList[index], + }), + )} + onProcess={async (newPermissionBoolList): Promise => { + for (let index = 0; index < kUserPermissionList.length; index++) { + const oldValue = oldPermissionBoolList[index]; + const newValue = newPermissionBoolList[index]; + const permission = kUserPermissionList[index]; + if (oldValue === newValue) continue; + if (newValue) { + await getHttpUserClient().putUserPermission( + user.username, + permission, + ); + } else { + await getHttpUserClient().deleteUserPermission( + user.username, + permission, + ); + } + } + return newPermissionBoolList; + }} + onSuccessAndClose={onSuccess} + /> + ); +}; + +interface UserItemProps { + user: HttpUser; + onChange: () => void; +} + +const UserItem: React.FC = ({ user, onChange }) => { + const { t } = useTranslation(); + + const [dialog, setDialog] = useState< + "delete" | "modify" | "permission" | null + >(null); + + const [editMaskVisible, setEditMaskVisible] = React.useState(false); + + return ( + <> +
+ setEditMaskVisible(true)} + /> +
{user.username}
+ + {t("admin:user.nickname")} + {user.nickname} + + + {t("admin:user.uniqueId")} + {user.uniqueId} + + + {t("admin:user.permissions")} + {user.permissions.map((permission) => { + return ( + + {permission} + + ); + })} + +
setEditMaskVisible(false)} + > + setDialog("modify")} + /> + setDialog("permission")} + /> + setDialog("delete")} + /> +
+
+ setDialog(null)} + user={user} + onSuccess={onChange} + /> + setDialog(null)} + user={user} + onSuccess={onChange} + /> + setDialog(null)} + user={user} + onSuccess={onChange} + /> + + ); +}; + +const UserAdmin: React.FC = () => { + const [users, setUsers] = useState(null); + const [dialog, setDialog] = useState<"create" | null>(null); + const [usersVersion, setUsersVersion] = useState(0); + const updateUsers = (): void => { + setUsersVersion(usersVersion + 1); + }; + + useEffect(() => { + let subscribe = true; + void getHttpUserClient() + .list() + .then((us) => { + if (subscribe) { + setUsers(us.items); + } + }); + return () => { + subscribe = false; + }; + }, [usersVersion]); + + if (users) { + const userComponents = users.map((user) => { + return ( + + ); + }); + + return ( + <> +
+
+
+
+ {userComponents} + setDialog(null)} + onSuccess={updateUsers} + /> + + ); + } else { + return ; + } +}; + +export default UserAdmin; diff --git a/FrontEnd/src/migrating/admin/index.css b/FrontEnd/src/migrating/admin/index.css new file mode 100644 index 00000000..17e24586 --- /dev/null +++ b/FrontEnd/src/migrating/admin/index.css @@ -0,0 +1,33 @@ +.admin-user-item { + position: relative; + border: var(--cru-primary-color) solid; + border-width: 1px 1px 0; + padding: 1em; +} + +.admin-user-item:last-of-type { + border-bottom-width: 1px; +} + +.admin-user-item .edit-mask { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(255, 255, 255, 0.9); + position: absolute; + display: flex; + justify-content: space-around; + align-items: center; +} + +@media (max-width: 576px) { + .admin-user-item .edit-mask { + flex-direction: column; + } +} + +.admin-user-item .edit-mask button { + margin: 0.5em 2em; +} diff --git a/FrontEnd/src/migrating/admin/index.tsx b/FrontEnd/src/migrating/admin/index.tsx new file mode 100644 index 00000000..0467711d --- /dev/null +++ b/FrontEnd/src/migrating/admin/index.tsx @@ -0,0 +1,7 @@ +import { lazy } from "react"; + +const Admin = lazy( + () => import(/* webpackChunkName: "admin" */ "./Admin") +); + +export default Admin; diff --git a/FrontEnd/src/migrating/center/CenterBoards.tsx b/FrontEnd/src/migrating/center/CenterBoards.tsx new file mode 100644 index 00000000..a8be2c29 --- /dev/null +++ b/FrontEnd/src/migrating/center/CenterBoards.tsx @@ -0,0 +1,131 @@ +import * as React from "react"; +import { useTranslation } from "react-i18next"; + +import { highlightTimelineUsername } from "@/common"; + +import { pushAlert } from "@/services/alert"; +import { useUserLoggedIn } from "@/services/user"; + +import { getHttpTimelineClient } from "@/http/timeline"; +import { getHttpBookmarkClient } from "@/http/bookmark"; + +import TimelineBoard from "./TimelineBoard"; + +const CenterBoards: React.FC = () => { + const { t } = useTranslation(); + + const user = useUserLoggedIn(); + + return ( + <> +
+
+
+
+ + getHttpBookmarkClient() + .list(user.username) + .then((p) => p.items) + } + editHandler={{ + onDelete: (owner, timeline) => { + return getHttpBookmarkClient() + .delete(user.username, owner, timeline) + .catch((e) => { + pushAlert({ + message: "home.message.deleteBookmarkFail", + type: "danger", + }); + throw e; + }); + }, + onMove: (owner, timeline, index, offset) => { + return getHttpBookmarkClient() + .move( + user.username, + owner, + timeline, + index + offset + 1 // +1 because backend contract: index starts at 1 + ) + .catch((e) => { + pushAlert({ + message: "home.message.moveBookmarkFail", + type: "danger", + }); + throw e; + }) + .then(); + }, + }} + /> +
+
+ + getHttpBookmarkClient() + .list(highlightTimelineUsername) + .then((p) => p.items) + } + editHandler={ + user.username === highlightTimelineUsername + ? { + onDelete: (owner, timeline) => { + return getHttpBookmarkClient() + .delete(highlightTimelineUsername, owner, timeline) + .catch((e) => { + pushAlert({ + message: "home.message.deleteHighlightFail", + type: "danger", + }); + throw e; + }); + }, + onMove: (owner, timeline, index, offset) => { + return getHttpBookmarkClient() + .move( + highlightTimelineUsername, + owner, + timeline, + index + offset + 1 // +1 because backend contract: index starts at 1 + ) + .catch((e) => { + pushAlert({ + message: "home.message.moveBookmarkFail", + type: "danger", + }); + throw e; + }) + .then(); + }, + } + : undefined + } + /> +
+
+
+
+ + getHttpTimelineClient() + .listTimeline({ relate: user.username }) + .then((l) => + l.map((t, index) => ({ + timelineOwner: t.owner.username, + timelineName: t.nameV2, + position: index + 1, + })) + ) + } + /> +
+
+ + ); +}; + +export default CenterBoards; diff --git a/FrontEnd/src/migrating/center/TimelineBoard.tsx b/FrontEnd/src/migrating/center/TimelineBoard.tsx new file mode 100644 index 00000000..b3ccdf8c --- /dev/null +++ b/FrontEnd/src/migrating/center/TimelineBoard.tsx @@ -0,0 +1,390 @@ +import * as React from "react"; +import classnames from "classnames"; +import { Link } from "react-router-dom"; + +import { TimelineBookmark } from "@/http/bookmark"; + +import TimelineLogo from "../common/TimelineLogo"; +import LoadFailReload from "../common/LoadFailReload"; +import FlatButton from "../common/button/FlatButton"; +import Card from "../common/Card"; +import Spinner from "../common/Spinner"; +import IconButton from "../common/button/IconButton"; + +interface TimelineBoardItemProps { + timeline: TimelineBookmark; + // In height. + offset?: number; + // In px. + arbitraryOffset?: number; + // If not null, will disable navigation on click. + actions?: { + onDelete: () => void; + onMove: { + start: (e: React.PointerEvent) => void; + moving: (e: React.PointerEvent) => void; + end: (e: React.PointerEvent) => void; + }; + }; +} + +const TimelineBoardItem: React.FC = ({ + timeline, + arbitraryOffset, + offset, + actions, +}) => { + const content = ( + <> + + + {timeline.timelineOwner}/{timeline.timelineName} + + + {actions != null ? ( +
+ + { + e.currentTarget.setPointerCapture(e.pointerId); + actions.onMove.start(e); + }} + onPointerUp={(e) => { + actions.onMove.end(e); + try { + e.currentTarget.releasePointerCapture(e.pointerId); + } catch (_) { + void null; + } + }} + onPointerMove={actions.onMove.moving} + /> +
+ ) : null} + + ); + + const offsetStyle: React.CSSProperties = { + transform: + arbitraryOffset != null + ? `translate(0,${arbitraryOffset}px)` + : offset != null + ? `translate(0,${offset * 100}%)` + : undefined, + transition: offset != null ? "transform 0.5s" : undefined, + zIndex: arbitraryOffset != null ? 1 : undefined, + }; + + return actions == null ? ( + + {content} + + ) : ( +
+ {content} +
+ ); +}; + +interface TimelineBoardItemContainerProps { + timelines: TimelineBookmark[]; + editHandler?: { + // offset may exceed index range plusing index. + onMove: ( + owner: string, + timeline: string, + index: number, + offset: number + ) => void; + onDelete: (owner: string, timeline: string) => void; + }; +} + +const TimelineBoardItemContainer: React.FC = ({ + timelines, + editHandler, +}) => { + const [moveState, setMoveState] = React.useState(null); + + return ( + <> + {timelines.map((timeline, index) => { + const height = 48; + + let offset: number | undefined = undefined; + let arbitraryOffset: number | undefined = undefined; + if (moveState != null) { + if (index === moveState.index) { + arbitraryOffset = moveState.offset; + } else { + if (moveState.offset >= 0) { + const offsetCount = Math.round(moveState.offset / height); + if ( + index > moveState.index && + index <= moveState.index + offsetCount + ) { + offset = -1; + } else { + offset = 0; + } + } else { + const offsetCount = Math.round(-moveState.offset / height); + if ( + index < moveState.index && + index >= moveState.index - offsetCount + ) { + offset = 1; + } else { + offset = 0; + } + } + } + } + + return ( + { + editHandler.onDelete( + timeline.timelineOwner, + timeline.timelineName + ); + }, + onMove: { + start: (e) => { + if (moveState != null) return; + setMoveState({ + index, + offset: 0, + startPointY: e.clientY, + }); + }, + moving: (e) => { + if (moveState == null) return; + setMoveState({ + index, + offset: e.clientY - moveState.startPointY, + startPointY: moveState.startPointY, + }); + }, + end: () => { + if (moveState != null) { + const offsetCount = Math.round( + moveState.offset / height + ); + editHandler.onMove( + timeline.timelineOwner, + timeline.timelineName, + moveState.index, + offsetCount + ); + } + setMoveState(null); + }, + }, + } + : undefined + } + /> + ); + })} + + ); +}; + +interface TimelineBoardUIProps { + title?: string | null; + state: "offline" | "loading" | "loaded"; + timelines: TimelineBookmark[]; + onReload: () => void; + className?: string; + editHandler?: { + onMove: ( + owner: string, + timeline: string, + index: number, + offset: number + ) => void; + onDelete: (owner: string, timeline: string) => void; + }; +} + +const TimelineBoardUI: React.FC = (props) => { + const { title, state, timelines, className, editHandler } = props; + + const editable = editHandler != null; + + const [editing, setEditing] = React.useState(false); + + return ( + +
+ {title != null &&

{title}

} + {editable && + (editing ? ( + { + setEditing(false); + }} + /> + ) : ( + { + setEditing(true); + }} + /> + ))} +
+ {(() => { + if (state === "loading") { + return ( +
+ +
+ ); + } else if (state === "offline") { + return ( +
+ +
+ ); + } else { + return ( + { + if (index + offset >= timelines.length) { + offset = timelines.length - index - 1; + } else if (index + offset < 0) { + offset = -index; + } + editHandler.onMove(owner, timeline, index, offset); + }, + } + : undefined + } + /> + ); + } + })()} +
+ ); +}; + +export interface TimelineBoardProps { + title?: string | null; + className?: string; + load: () => Promise; + editHandler?: { + onMove: ( + owner: string, + timeline: string, + index: number, + offset: number + ) => Promise; + onDelete: (owner: string, timeline: string) => Promise; + }; +} + +const TimelineBoard: React.FC = ({ + className, + title, + load, + editHandler, +}) => { + const [state, setState] = React.useState<"offline" | "loading" | "loaded">( + "loading" + ); + const [timelines, setTimelines] = React.useState([]); + + React.useEffect(() => { + let subscribe = true; + if (state === "loading") { + void load().then( + (timelines) => { + if (subscribe) { + setState("loaded"); + setTimelines(timelines); + } + }, + () => { + setState("offline"); + } + ); + } + return () => { + subscribe = false; + }; + }, [load, state]); + + return ( + { + setState("loaded"); + }} + editHandler={ + typeof timelines === "object" && editHandler != null + ? { + onMove: (owner, timeline, index, offset) => { + const newTimelines = timelines.slice(); + const [t] = newTimelines.splice(index, 1); + newTimelines.splice(index + offset, 0, t); + setTimelines(newTimelines); + editHandler + .onMove(owner, timeline, index, offset) + .then(null, () => { + setTimelines(timelines); + }); + }, + onDelete: (owner, timeline) => { + const newTimelines = timelines.slice(); + newTimelines.splice( + timelines.findIndex( + (t) => + t.timelineOwner === owner && t.timelineName === timeline + ), + 1 + ); + setTimelines(newTimelines); + editHandler.onDelete(owner, timeline).then(null, () => { + setTimelines(timelines); + }); + }, + } + : undefined + } + /> + ); +}; + +export default TimelineBoard; diff --git a/FrontEnd/src/migrating/center/TimelineCreateDialog.tsx b/FrontEnd/src/migrating/center/TimelineCreateDialog.tsx new file mode 100644 index 00000000..63742936 --- /dev/null +++ b/FrontEnd/src/migrating/center/TimelineCreateDialog.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { useNavigate } from "react-router-dom"; + +import { validateTimelineName } from "@/services/timeline"; +import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline"; + +import OperationDialog from "../common/dialog/OperationDialog"; +import { useUserLoggedIn } from "@/services/user"; + +interface TimelineCreateDialogProps { + open: boolean; + close: () => void; +} + +const TimelineCreateDialog: React.FC = (props) => { + const navigate = useNavigate(); + + const user = useUserLoggedIn(); + + return ( + { + if (name.length === 0) { + return { 0: "home.createDialog.noEmpty" }; + } else if (name.length > 26) { + return { 0: "home.createDialog.tooLong" }; + } else if (!validateTimelineName(name)) { + return { 0: "home.createDialog.badFormat" }; + } else { + return null; + } + }} + onProcess={([name]): Promise => + getHttpTimelineClient().postTimeline({ name }) + } + onSuccessAndClose={(timeline: HttpTimelineInfo) => { + navigate(`${user.username}/${timeline.nameV2}`); + }} + failurePrompt={(e) => `${e as string}`} + /> + ); +}; + +export default TimelineCreateDialog; diff --git a/FrontEnd/src/migrating/center/index.css b/FrontEnd/src/migrating/center/index.css new file mode 100644 index 00000000..a779ff90 --- /dev/null +++ b/FrontEnd/src/migrating/center/index.css @@ -0,0 +1,43 @@ +.timeline-board { + min-height: 200px; + height: 100%; + position: relative; + padding: 1em 0; + display: flex; + flex-direction: column; +} + +.timeline-board-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 1em; +} + +.timeline-board-item { + font-size: 1.1em; + height: 48px; + transition: background 0.3s; + display: flex; + align-items: center; + padding: 0 1em; +} + +.timeline-board-item .icon { + height: 1.3em; + color: black; +} + +.timeline-board-item:hover { + background: #dee2e6; +} +.timeline-board-item .right { + display: flex; + align-items: center; + flex-shrink: 0; +} +.timeline-board-item .title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/FrontEnd/src/migrating/center/index.tsx b/FrontEnd/src/migrating/center/index.tsx new file mode 100644 index 00000000..77af2c20 --- /dev/null +++ b/FrontEnd/src/migrating/center/index.tsx @@ -0,0 +1,60 @@ +import * as React from "react"; +import { useNavigate } from "react-router-dom"; + +import { useUserLoggedIn } from "@/services/user"; + +import SearchInput from "../common/SearchInput"; +import Button from "../common/button/Button"; +import CenterBoards from "./CenterBoards"; +import TimelineCreateDialog from "./TimelineCreateDialog"; + +import "./index.css"; + +const HomePage: React.FC = () => { + const navigate = useNavigate(); + + const user = useUserLoggedIn(); + + const [navText, setNavText] = React.useState(""); + + const [dialog, setDialog] = React.useState<"create" | null>(null); + + return ( + <> +
+
+
+ { + navigate(`search?q=${navText}`); + }} + additionalButton={ + user != null && ( +
+
+ +
+ { + setDialog(null); + }} + /> + + ); +}; + +export default HomePage; diff --git a/FrontEnd/src/services/alert.ts b/FrontEnd/src/services/alert.ts index 42b14451..2f66dccc 100644 --- a/FrontEnd/src/services/alert.ts +++ b/FrontEnd/src/services/alert.ts @@ -1,10 +1,10 @@ import pull from "lodash/pull"; import { I18nText } from "@/common"; -import { PaletteColorType } from "@/palette"; +import { ThemeColor } from "@/views/common/common"; export interface AlertInfo { - type?: PaletteColorType; + type?: ThemeColor; message?: I18nText; customMessage?: React.ReactElement; dismissTime?: number | "never"; diff --git a/FrontEnd/src/views/admin/Admin.tsx b/FrontEnd/src/views/admin/Admin.tsx deleted file mode 100644 index 986c36b4..00000000 --- a/FrontEnd/src/views/admin/Admin.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Route, Routes } from "react-router-dom"; -import { useTranslation } from "react-i18next"; - -import AdminNav from "./AdminNav"; -import UserAdmin from "./UserAdmin"; -import MoreAdmin from "./MoreAdmin"; - -import "./index.css"; - -const Admin: React.FC = () => { - useTranslation("admin"); - - return ( - <> -
- - - } /> - } /> - } /> - -
- - ); -}; - -export default Admin; diff --git a/FrontEnd/src/views/admin/AdminNav.tsx b/FrontEnd/src/views/admin/AdminNav.tsx deleted file mode 100644 index b7385e5c..00000000 --- a/FrontEnd/src/views/admin/AdminNav.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useLocation } from "react-router-dom"; - -import Tabs from "../common/tab/Tabs"; - -export function AdminNav({ className }: { className?: string }) { - const location = useLocation(); - const name = location.pathname.split("/")[2] ?? "user"; - - return ( - - ); -} - -export default AdminNav; diff --git a/FrontEnd/src/views/admin/MoreAdmin.tsx b/FrontEnd/src/views/admin/MoreAdmin.tsx deleted file mode 100644 index d49d211f..00000000 --- a/FrontEnd/src/views/admin/MoreAdmin.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import * as React from "react"; - -const MoreAdmin: React.FC = () => { - return <>More...; -}; - -export default MoreAdmin; diff --git a/FrontEnd/src/views/admin/UserAdmin.tsx b/FrontEnd/src/views/admin/UserAdmin.tsx deleted file mode 100644 index d5179bf5..00000000 --- a/FrontEnd/src/views/admin/UserAdmin.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import { useState, useEffect } from "react"; -import * as React from "react"; -import { Trans, useTranslation } from "react-i18next"; -import classnames from "classnames"; - -import { getHttpUserClient, HttpUser, kUserPermissionList } from "@/http/user"; - -import OperationDialog, { - OperationDialogBoolInput, -} from "../common/dialog/OperationDialog"; -import Button from "../common/button/Button"; -import Spinner from "../common/Spinner"; -import FlatButton from "../common/button/FlatButton"; -import IconButton from "../common/button/IconButton"; - -const CreateUserDialog: React.FC<{ - open: boolean; - close: () => void; - onSuccess: (user: HttpUser) => void; -}> = ({ open, close, onSuccess }) => { - return ( - - getHttpUserClient().post({ - username, - password, - }) - } - onClose={close} - open={open} - onSuccessAndClose={onSuccess} - /> - ); -}; - -const UsernameLabel: React.FC<{ children: React.ReactNode }> = (props) => { - return {props.children}; -}; - -const UserDeleteDialog: React.FC<{ - open: boolean; - close: () => void; - user: HttpUser; - onSuccess: () => void; -}> = ({ open, close, user, onSuccess }) => { - return ( - ( - - 0{user.username}2 - - )} - onProcess={() => getHttpUserClient().delete(user.username)} - onSuccessAndClose={onSuccess} - /> - ); -}; - -const UserModifyDialog: React.FC<{ - open: boolean; - close: () => void; - user: HttpUser; - onSuccess: () => void; -}> = ({ open, close, user, onSuccess }) => { - return ( - ( - - 0{user.username}2 - - )} - inputScheme={ - [ - { - type: "text", - label: "admin:user.username", - initValue: user.username, - }, - { type: "text", label: "admin:user.password" }, - { - type: "text", - label: "admin:user.nickname", - initValue: user.nickname, - }, - ] as const - } - onProcess={([username, password, nickname]) => - getHttpUserClient().patch(user.username, { - username: username !== user.username ? username : undefined, - password: password !== "" ? password : undefined, - nickname: nickname !== user.nickname ? nickname : undefined, - }) - } - onSuccessAndClose={onSuccess} - /> - ); -}; - -const UserPermissionModifyDialog: React.FC<{ - open: boolean; - close: () => void; - user: HttpUser; - onSuccess: () => void; -}> = ({ open, close, user, onSuccess }) => { - const oldPermissionBoolList: boolean[] = kUserPermissionList.map( - (permission) => user.permissions.includes(permission) - ); - - return ( - ( - - 0{user.username}2 - - )} - inputScheme={kUserPermissionList.map( - (permission, index) => ({ - type: "bool", - label: { type: "custom", value: permission }, - initValue: oldPermissionBoolList[index], - }) - )} - onProcess={async (newPermissionBoolList): Promise => { - for (let index = 0; index < kUserPermissionList.length; index++) { - const oldValue = oldPermissionBoolList[index]; - const newValue = newPermissionBoolList[index]; - const permission = kUserPermissionList[index]; - if (oldValue === newValue) continue; - if (newValue) { - await getHttpUserClient().putUserPermission( - user.username, - permission - ); - } else { - await getHttpUserClient().deleteUserPermission( - user.username, - permission - ); - } - } - return newPermissionBoolList; - }} - onSuccessAndClose={onSuccess} - /> - ); -}; - -interface UserItemProps { - user: HttpUser; - onChange: () => void; -} - -const UserItem: React.FC = ({ user, onChange }) => { - const { t } = useTranslation(); - - const [dialog, setDialog] = useState< - "delete" | "modify" | "permission" | null - >(null); - - const [editMaskVisible, setEditMaskVisible] = React.useState(false); - - return ( - <> -
- setEditMaskVisible(true)} - /> -
{user.username}
- - {t("admin:user.nickname")} - {user.nickname} - - - {t("admin:user.uniqueId")} - {user.uniqueId} - - - {t("admin:user.permissions")} - {user.permissions.map((permission) => { - return ( - - {permission} - - ); - })} - -
setEditMaskVisible(false)} - > - setDialog("modify")} - /> - setDialog("permission")} - /> - setDialog("delete")} - /> -
-
- setDialog(null)} - user={user} - onSuccess={onChange} - /> - setDialog(null)} - user={user} - onSuccess={onChange} - /> - setDialog(null)} - user={user} - onSuccess={onChange} - /> - - ); -}; - -const UserAdmin: React.FC = () => { - const [users, setUsers] = useState(null); - const [dialog, setDialog] = useState<"create" | null>(null); - const [usersVersion, setUsersVersion] = useState(0); - const updateUsers = (): void => { - setUsersVersion(usersVersion + 1); - }; - - useEffect(() => { - let subscribe = true; - void getHttpUserClient() - .list() - .then((us) => { - if (subscribe) { - setUsers(us.items); - } - }); - return () => { - subscribe = false; - }; - }, [usersVersion]); - - if (users) { - const userComponents = users.map((user) => { - return ( - - ); - }); - - return ( - <> -
-
-
-
- {userComponents} - setDialog(null)} - onSuccess={updateUsers} - /> - - ); - } else { - return ; - } -}; - -export default UserAdmin; diff --git a/FrontEnd/src/views/admin/index.css b/FrontEnd/src/views/admin/index.css deleted file mode 100644 index 17e24586..00000000 --- a/FrontEnd/src/views/admin/index.css +++ /dev/null @@ -1,33 +0,0 @@ -.admin-user-item { - position: relative; - border: var(--cru-primary-color) solid; - border-width: 1px 1px 0; - padding: 1em; -} - -.admin-user-item:last-of-type { - border-bottom-width: 1px; -} - -.admin-user-item .edit-mask { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - background: rgba(255, 255, 255, 0.9); - position: absolute; - display: flex; - justify-content: space-around; - align-items: center; -} - -@media (max-width: 576px) { - .admin-user-item .edit-mask { - flex-direction: column; - } -} - -.admin-user-item .edit-mask button { - margin: 0.5em 2em; -} diff --git a/FrontEnd/src/views/admin/index.tsx b/FrontEnd/src/views/admin/index.tsx deleted file mode 100644 index 0467711d..00000000 --- a/FrontEnd/src/views/admin/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { lazy } from "react"; - -const Admin = lazy( - () => import(/* webpackChunkName: "admin" */ "./Admin") -); - -export default Admin; diff --git a/FrontEnd/src/views/center/CenterBoards.tsx b/FrontEnd/src/views/center/CenterBoards.tsx deleted file mode 100644 index a8be2c29..00000000 --- a/FrontEnd/src/views/center/CenterBoards.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import * as React from "react"; -import { useTranslation } from "react-i18next"; - -import { highlightTimelineUsername } from "@/common"; - -import { pushAlert } from "@/services/alert"; -import { useUserLoggedIn } from "@/services/user"; - -import { getHttpTimelineClient } from "@/http/timeline"; -import { getHttpBookmarkClient } from "@/http/bookmark"; - -import TimelineBoard from "./TimelineBoard"; - -const CenterBoards: React.FC = () => { - const { t } = useTranslation(); - - const user = useUserLoggedIn(); - - return ( - <> -
-
-
-
- - getHttpBookmarkClient() - .list(user.username) - .then((p) => p.items) - } - editHandler={{ - onDelete: (owner, timeline) => { - return getHttpBookmarkClient() - .delete(user.username, owner, timeline) - .catch((e) => { - pushAlert({ - message: "home.message.deleteBookmarkFail", - type: "danger", - }); - throw e; - }); - }, - onMove: (owner, timeline, index, offset) => { - return getHttpBookmarkClient() - .move( - user.username, - owner, - timeline, - index + offset + 1 // +1 because backend contract: index starts at 1 - ) - .catch((e) => { - pushAlert({ - message: "home.message.moveBookmarkFail", - type: "danger", - }); - throw e; - }) - .then(); - }, - }} - /> -
-
- - getHttpBookmarkClient() - .list(highlightTimelineUsername) - .then((p) => p.items) - } - editHandler={ - user.username === highlightTimelineUsername - ? { - onDelete: (owner, timeline) => { - return getHttpBookmarkClient() - .delete(highlightTimelineUsername, owner, timeline) - .catch((e) => { - pushAlert({ - message: "home.message.deleteHighlightFail", - type: "danger", - }); - throw e; - }); - }, - onMove: (owner, timeline, index, offset) => { - return getHttpBookmarkClient() - .move( - highlightTimelineUsername, - owner, - timeline, - index + offset + 1 // +1 because backend contract: index starts at 1 - ) - .catch((e) => { - pushAlert({ - message: "home.message.moveBookmarkFail", - type: "danger", - }); - throw e; - }) - .then(); - }, - } - : undefined - } - /> -
-
-
-
- - getHttpTimelineClient() - .listTimeline({ relate: user.username }) - .then((l) => - l.map((t, index) => ({ - timelineOwner: t.owner.username, - timelineName: t.nameV2, - position: index + 1, - })) - ) - } - /> -
-
- - ); -}; - -export default CenterBoards; diff --git a/FrontEnd/src/views/center/TimelineBoard.tsx b/FrontEnd/src/views/center/TimelineBoard.tsx deleted file mode 100644 index b3ccdf8c..00000000 --- a/FrontEnd/src/views/center/TimelineBoard.tsx +++ /dev/null @@ -1,390 +0,0 @@ -import * as React from "react"; -import classnames from "classnames"; -import { Link } from "react-router-dom"; - -import { TimelineBookmark } from "@/http/bookmark"; - -import TimelineLogo from "../common/TimelineLogo"; -import LoadFailReload from "../common/LoadFailReload"; -import FlatButton from "../common/button/FlatButton"; -import Card from "../common/Card"; -import Spinner from "../common/Spinner"; -import IconButton from "../common/button/IconButton"; - -interface TimelineBoardItemProps { - timeline: TimelineBookmark; - // In height. - offset?: number; - // In px. - arbitraryOffset?: number; - // If not null, will disable navigation on click. - actions?: { - onDelete: () => void; - onMove: { - start: (e: React.PointerEvent) => void; - moving: (e: React.PointerEvent) => void; - end: (e: React.PointerEvent) => void; - }; - }; -} - -const TimelineBoardItem: React.FC = ({ - timeline, - arbitraryOffset, - offset, - actions, -}) => { - const content = ( - <> - - - {timeline.timelineOwner}/{timeline.timelineName} - - - {actions != null ? ( -
- - { - e.currentTarget.setPointerCapture(e.pointerId); - actions.onMove.start(e); - }} - onPointerUp={(e) => { - actions.onMove.end(e); - try { - e.currentTarget.releasePointerCapture(e.pointerId); - } catch (_) { - void null; - } - }} - onPointerMove={actions.onMove.moving} - /> -
- ) : null} - - ); - - const offsetStyle: React.CSSProperties = { - transform: - arbitraryOffset != null - ? `translate(0,${arbitraryOffset}px)` - : offset != null - ? `translate(0,${offset * 100}%)` - : undefined, - transition: offset != null ? "transform 0.5s" : undefined, - zIndex: arbitraryOffset != null ? 1 : undefined, - }; - - return actions == null ? ( - - {content} - - ) : ( -
- {content} -
- ); -}; - -interface TimelineBoardItemContainerProps { - timelines: TimelineBookmark[]; - editHandler?: { - // offset may exceed index range plusing index. - onMove: ( - owner: string, - timeline: string, - index: number, - offset: number - ) => void; - onDelete: (owner: string, timeline: string) => void; - }; -} - -const TimelineBoardItemContainer: React.FC = ({ - timelines, - editHandler, -}) => { - const [moveState, setMoveState] = React.useState(null); - - return ( - <> - {timelines.map((timeline, index) => { - const height = 48; - - let offset: number | undefined = undefined; - let arbitraryOffset: number | undefined = undefined; - if (moveState != null) { - if (index === moveState.index) { - arbitraryOffset = moveState.offset; - } else { - if (moveState.offset >= 0) { - const offsetCount = Math.round(moveState.offset / height); - if ( - index > moveState.index && - index <= moveState.index + offsetCount - ) { - offset = -1; - } else { - offset = 0; - } - } else { - const offsetCount = Math.round(-moveState.offset / height); - if ( - index < moveState.index && - index >= moveState.index - offsetCount - ) { - offset = 1; - } else { - offset = 0; - } - } - } - } - - return ( - { - editHandler.onDelete( - timeline.timelineOwner, - timeline.timelineName - ); - }, - onMove: { - start: (e) => { - if (moveState != null) return; - setMoveState({ - index, - offset: 0, - startPointY: e.clientY, - }); - }, - moving: (e) => { - if (moveState == null) return; - setMoveState({ - index, - offset: e.clientY - moveState.startPointY, - startPointY: moveState.startPointY, - }); - }, - end: () => { - if (moveState != null) { - const offsetCount = Math.round( - moveState.offset / height - ); - editHandler.onMove( - timeline.timelineOwner, - timeline.timelineName, - moveState.index, - offsetCount - ); - } - setMoveState(null); - }, - }, - } - : undefined - } - /> - ); - })} - - ); -}; - -interface TimelineBoardUIProps { - title?: string | null; - state: "offline" | "loading" | "loaded"; - timelines: TimelineBookmark[]; - onReload: () => void; - className?: string; - editHandler?: { - onMove: ( - owner: string, - timeline: string, - index: number, - offset: number - ) => void; - onDelete: (owner: string, timeline: string) => void; - }; -} - -const TimelineBoardUI: React.FC = (props) => { - const { title, state, timelines, className, editHandler } = props; - - const editable = editHandler != null; - - const [editing, setEditing] = React.useState(false); - - return ( - -
- {title != null &&

{title}

} - {editable && - (editing ? ( - { - setEditing(false); - }} - /> - ) : ( - { - setEditing(true); - }} - /> - ))} -
- {(() => { - if (state === "loading") { - return ( -
- -
- ); - } else if (state === "offline") { - return ( -
- -
- ); - } else { - return ( - { - if (index + offset >= timelines.length) { - offset = timelines.length - index - 1; - } else if (index + offset < 0) { - offset = -index; - } - editHandler.onMove(owner, timeline, index, offset); - }, - } - : undefined - } - /> - ); - } - })()} -
- ); -}; - -export interface TimelineBoardProps { - title?: string | null; - className?: string; - load: () => Promise; - editHandler?: { - onMove: ( - owner: string, - timeline: string, - index: number, - offset: number - ) => Promise; - onDelete: (owner: string, timeline: string) => Promise; - }; -} - -const TimelineBoard: React.FC = ({ - className, - title, - load, - editHandler, -}) => { - const [state, setState] = React.useState<"offline" | "loading" | "loaded">( - "loading" - ); - const [timelines, setTimelines] = React.useState([]); - - React.useEffect(() => { - let subscribe = true; - if (state === "loading") { - void load().then( - (timelines) => { - if (subscribe) { - setState("loaded"); - setTimelines(timelines); - } - }, - () => { - setState("offline"); - } - ); - } - return () => { - subscribe = false; - }; - }, [load, state]); - - return ( - { - setState("loaded"); - }} - editHandler={ - typeof timelines === "object" && editHandler != null - ? { - onMove: (owner, timeline, index, offset) => { - const newTimelines = timelines.slice(); - const [t] = newTimelines.splice(index, 1); - newTimelines.splice(index + offset, 0, t); - setTimelines(newTimelines); - editHandler - .onMove(owner, timeline, index, offset) - .then(null, () => { - setTimelines(timelines); - }); - }, - onDelete: (owner, timeline) => { - const newTimelines = timelines.slice(); - newTimelines.splice( - timelines.findIndex( - (t) => - t.timelineOwner === owner && t.timelineName === timeline - ), - 1 - ); - setTimelines(newTimelines); - editHandler.onDelete(owner, timeline).then(null, () => { - setTimelines(timelines); - }); - }, - } - : undefined - } - /> - ); -}; - -export default TimelineBoard; diff --git a/FrontEnd/src/views/center/TimelineCreateDialog.tsx b/FrontEnd/src/views/center/TimelineCreateDialog.tsx deleted file mode 100644 index 63742936..00000000 --- a/FrontEnd/src/views/center/TimelineCreateDialog.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react"; -import { useNavigate } from "react-router-dom"; - -import { validateTimelineName } from "@/services/timeline"; -import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline"; - -import OperationDialog from "../common/dialog/OperationDialog"; -import { useUserLoggedIn } from "@/services/user"; - -interface TimelineCreateDialogProps { - open: boolean; - close: () => void; -} - -const TimelineCreateDialog: React.FC = (props) => { - const navigate = useNavigate(); - - const user = useUserLoggedIn(); - - return ( - { - if (name.length === 0) { - return { 0: "home.createDialog.noEmpty" }; - } else if (name.length > 26) { - return { 0: "home.createDialog.tooLong" }; - } else if (!validateTimelineName(name)) { - return { 0: "home.createDialog.badFormat" }; - } else { - return null; - } - }} - onProcess={([name]): Promise => - getHttpTimelineClient().postTimeline({ name }) - } - onSuccessAndClose={(timeline: HttpTimelineInfo) => { - navigate(`${user.username}/${timeline.nameV2}`); - }} - failurePrompt={(e) => `${e as string}`} - /> - ); -}; - -export default TimelineCreateDialog; diff --git a/FrontEnd/src/views/center/index.css b/FrontEnd/src/views/center/index.css deleted file mode 100644 index a779ff90..00000000 --- a/FrontEnd/src/views/center/index.css +++ /dev/null @@ -1,43 +0,0 @@ -.timeline-board { - min-height: 200px; - height: 100%; - position: relative; - padding: 1em 0; - display: flex; - flex-direction: column; -} - -.timeline-board-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 1em; -} - -.timeline-board-item { - font-size: 1.1em; - height: 48px; - transition: background 0.3s; - display: flex; - align-items: center; - padding: 0 1em; -} - -.timeline-board-item .icon { - height: 1.3em; - color: black; -} - -.timeline-board-item:hover { - background: #dee2e6; -} -.timeline-board-item .right { - display: flex; - align-items: center; - flex-shrink: 0; -} -.timeline-board-item .title { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} diff --git a/FrontEnd/src/views/center/index.tsx b/FrontEnd/src/views/center/index.tsx deleted file mode 100644 index 77af2c20..00000000 --- a/FrontEnd/src/views/center/index.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import * as React from "react"; -import { useNavigate } from "react-router-dom"; - -import { useUserLoggedIn } from "@/services/user"; - -import SearchInput from "../common/SearchInput"; -import Button from "../common/button/Button"; -import CenterBoards from "./CenterBoards"; -import TimelineCreateDialog from "./TimelineCreateDialog"; - -import "./index.css"; - -const HomePage: React.FC = () => { - const navigate = useNavigate(); - - const user = useUserLoggedIn(); - - const [navText, setNavText] = React.useState(""); - - const [dialog, setDialog] = React.useState<"create" | null>(null); - - return ( - <> -
-
-
- { - navigate(`search?q=${navText}`); - }} - additionalButton={ - user != null && ( -
-
- -
- { - setDialog(null); - }} - /> - - ); -}; - -export default HomePage; diff --git a/FrontEnd/src/views/common/button/LoadingButton.css b/FrontEnd/src/views/common/button/LoadingButton.css index 2f73116a..0a7e4a3a 100644 --- a/FrontEnd/src/views/common/button/LoadingButton.css +++ b/FrontEnd/src/views/common/button/LoadingButton.css @@ -11,4 +11,4 @@ .cru-loading-button-spinner { margin-left: 0.5em; -} +} \ No newline at end of file diff --git a/FrontEnd/src/views/search/index.css b/FrontEnd/src/views/search/index.css deleted file mode 100644 index 6ff4d9fa..00000000 --- a/FrontEnd/src/views/search/index.css +++ /dev/null @@ -1,15 +0,0 @@ -.timeline-search-result-item { - border: 1px solid; - border-color: #e9ecef; - background: #f8f9fa; - transition: all 0.3s; -} -.timeline-search-result-item:hover { - border-color: #0d6efd; -} - -.timeline-search-result-item-avatar { - width: 2em; - height: 2em; - border-radius: 50%; -} diff --git a/FrontEnd/src/views/search/index.tsx b/FrontEnd/src/views/search/index.tsx deleted file mode 100644 index 58257465..00000000 --- a/FrontEnd/src/views/search/index.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import * as React from "react"; -import { useTranslation } from "react-i18next"; -import { useNavigate, useLocation } from "react-router-dom"; -import { Link } from "react-router-dom"; - -import { HttpNetworkError } from "@/http/common"; -import { getHttpSearchClient } from "@/http/search"; -import { HttpTimelineInfo } from "@/http/timeline"; - -import SearchInput from "../common/SearchInput"; -import UserAvatar from "../common/user/UserAvatar"; - -import "./index.css"; - -const TimelineSearchResultItemView: React.FC<{ - timeline: HttpTimelineInfo; -}> = ({ timeline }) => { - return ( -
-

- - {timeline.title} - {timeline.nameV2} - -

-
- - {timeline.owner.nickname} - - @{timeline.owner.username} - -
-
- ); -}; - -const SearchPage: React.FC = () => { - const { t } = useTranslation(); - - const navigate = useNavigate(); - const location = useLocation(); - const searchParams = new URLSearchParams(location.search); - const queryParam = searchParams.get("q"); - - const [searchText, setSearchText] = React.useState(""); - const [state, setState] = React.useState< - HttpTimelineInfo[] | "init" | "loading" | "network-error" | "error" - >("init"); - - const [forceResearchKey, setForceResearchKey] = React.useState(0); - - React.useEffect(() => { - setState("init"); - if (queryParam != null && queryParam.length > 0) { - setSearchText(queryParam); - setState("loading"); - void getHttpSearchClient() - .searchTimelines(queryParam) - .then( - (ts) => { - setState(ts); - }, - (e) => { - if (e instanceof HttpNetworkError) { - setState("network-error"); - } else { - setState("error"); - } - } - ); - } - }, [queryParam, forceResearchKey]); - - return ( -
-
- { - if (queryParam === searchText) { - setForceResearchKey((old) => old + 1); - } else { - navigate(`/search?q=${searchText}`); - } - }} - /> -
- {(() => { - switch (state) { - case "init": { - if (queryParam == null || queryParam.length === 0) { - return
{t("searchPage.input")}
; - } - break; - } - case "loading": { - return
{t("searchPage.loading")}
; - } - case "network-error": { - return
{t("error.network")}
; - } - case "error": { - return
{t("error.unknown")}
; - } - default: { - if (state.length === 0) { - return
{t("searchPage.noResult")}
; - } - return state.map((t) => ( - - )); - } - } - })()} -
- ); -}; - -export default SearchPage; diff --git a/FrontEnd/tsconfig.json b/FrontEnd/tsconfig.json index 97946126..cd6aa25d 100644 --- a/FrontEnd/tsconfig.json +++ b/FrontEnd/tsconfig.json @@ -29,5 +29,8 @@ }, "include": [ "src" + ], + "exclude": [ + "src/migrating" ] } \ No newline at end of file -- cgit v1.2.3