Phase 1T
This commit is contained in:
parent
480b557f81
commit
04a41e81b0
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HDTLGKjLXobcUaxEK20oKhNA2P/e0F5i8S99UYMOMOXz7wzr2yGI7GO3Z5OP51pziurWR73kBLKcmG5kM9Sd0Z22jVBt0p5+xer2fhI31jHnIlRxkBckyVuULS810PkiBSkkChUa0pN+Lyy7pXB2CCdx0jNsv5OaR2XmXXsj3HG5Wt5G8YmTsuGTVomepjXDHMsYn57uHvkv94enj8e3m6ttJbkZkTWMe+dbTFaboIibgwoDrEduJM6RDMIGkIRAWMzzpnSDFOz4pfv7+OSZ8qxU43SjeAqsEvNEDIUyT2s9PztVFTsiO5LvN7D+7F7ZWdKrFP1vzDfyt3EabxZt36iM00nSCulm7gcjzAjq9kpLSdKeaQdy5lSv6xjLkRjdOC9lOjBmdah163SDrUg9MK1GDCANXZQsW0H7H1wZjCopEFLxvSO1WwHN02Qx2WurtrvppHmzGr28ak6TJCHJR3foX96I/rwP4AW2axjWrTaOkdGaw3B9koQOhutVX0E4YZekYwk2mBckE5IHZQIurXOOwQRIqvZB4gv40zVwz3rmJCkUHvig5KWG4/AodWBW6vtQDIGpySr2d0y53Helm2tHuZMn9P+X9axn2Fa6e2ntym+jJli3lKB8Kctsg9pwS3m6rsBpGhEo4UoSVs+bbn6RDgmipkKjue0Xev9J0VZtSfdbSnRnKsD5JfqF1hfWMcC+CghQACwMQ7UChoECrDCIVm0hEahQxMMWhNEtAZ6aRBa2Q8lwmpGxW/VbnHprAERFMdge24iIPeD1Vy23htpBGjh33GsPk4lD6IXhlDzQANyEyTwYLTmqFtwyg7OqeEHJFezSFEAI53fhnVXYBE9oZVcGdlyE4LkPrSO9873obee2lg0P1KaafoB1IcxpmVdhlxdvVa9Q/dpm8vCqXbffR1n/vfeo/slfqFUlR7DOJf5urb1UrMjwbolOu77qntlhzJc1fO+tpRrrBehZk8ZUt5O17AOjQxBXy6Xyz8AAAD//wMA9VbUEPQEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxUzW7bOBB+FYFnUSElihIF7MFwWtRI0xiJu7vojSKHMRFZNCjKaRD43ReU5dopetibMCJnvr/hO+rlDlCDFvv9pwP0YUApCnYq5STnmHBM6IYWDaNNUWdFWRLCqx8oRfYO3lCDKqYUVQJwARww06TEbWEU1hoEJVSTvGSxp3weUPOOpM00HKyCzA1/gx+s61GD/rG9dq9xtrSZ6tyoM+86WPVDkL2KYL6tlnf462K9eVifTg0wxMuZ1ahBdV3xUiuOmcgBMyZzLFVpcEULoZghYEQEIW1m+wC+l1026JfLfO1CD0E1eZYXGcG5QMcUaRlkhNzKATZv+4hikug21tOpPH027+gAHjV5ehbz1O5GdfZmN7Sj7fRNkP4ZgvFyB6/Ov8BBdihFe+/24IOFSZuHp+QCiZKMZDnPCUEpupdqa3tIVrfJQxcJS1UTBrrAAozGTFCJBSsKrItSVjk3VZUblKI78D10V13vrfJucCYks+TJhzlL1wfbj24cklUf4NnLcLr3WXYDoBStx7azw/YRpH7buMcx/uvHLnJZjt5DH5K1DNvkixy2qEFC1opKIYWUXCkDJQFDNJGcVBq45qBZrivNBNOcCaI4ky1lWpa0NbGCUvQwhv0Yzvr/vAKx8Xa3A31BsJk0XncyGOd3Kw19sMZGa84npkB13cQqmXsuOwt9+CAyahChkOuiBmxyyjGrtcSyLATmvOAGqBJVTk+CGfs8/tKJGKNZYcq65q1oKYHcVDUjlWmJVqZQQpctVHlFqhpqoQhpS0brViiigZZMR3be6VGF36NQTAY9jn3czmQVab/aHv/k7KLI2rvglOuiYbaDp7chwO5Pri3dbu8GGyJ/M1v7fYB718e/8/7Pms2XFy5cahD3IJlWj1U0B8E5JlLVmGlJcVtrgxUtSpkXpKW6RCm6deoFfBIDJm0/eXLO1MNTsvBqawOoMPo4+d+J1MnOz+eVueiRffu0WToPi/0+nat/HaJIp2bnAHx4V74P8fjWDeGK8kztCTpzBnYVJw2H01NlY5FrXYPmFOeMlpgJQXEtygq3Vd2KltdQqktck0fQ1oMKU7+NH+O0Wdk/5XLhgzVShSEuz1enpjjN+ZyP/A7yyrZft0/Dr6ybozR3oiRG9un0cE4J+l/v5vF4PP4HAAD//wMABRuhhygGAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSTwY7cKBCGX8XibDyAARvfRj27SmuSnVYySlZ7w1Q5jeKBFsaTRKN+9xXujpLJLTf0Q1X99VXxQoJ9QjKQ29Ppr2cMeSE1yX6TBBOaMk0Zf+TtIPkgZSM4U8zw/0hN/D1+JwPppHPcGaQtaqQSmKJjOzkKgIYzDkwoWXLazwsZXoj1DeCzd9jE5SOmxcdABvLJB4hfS23rGzfHFZoUZ9yHJdvgipl/9rt7+vb28PhwuLxacCnBjQcykL7vtAKnqTQCqZRWUOvURDveGicnhpMpJqxvfMiYgp2bBb78rA8xB8xuEI1oG0aFIeeagM22WB7tgo/fT8XFhuiu6PUmb8fhhTxjIoOof8C8pLtxs79x8enJBriZfPDLkdTklOIJU/a44dg6nGebfQzVtchu9hgyqcnDh+ow2zzF9PSK0YdL6/s/6PyddUcfsNrfkYEwjgLaHukkuKayB0utag3VutUTcmc6wUlNdjFkH9a4LtU+ZPycNpdkIH/becGLv9vkjj6jy2sq1v/VpRh+83kXoQiM1OSQIqwuVz9xc9awpmXl8mHNpzVX7xF8Qpex9PSY1mv630KEFlvQbk0JQ64ONh+rN3Y5koEY2ztujTXWaucmVAwnBsxq1gFq0AhSQAfSSNDSMKelHbkEq/g4FaX4LtOttoVCkK1QI9IRlaKyd46OvFO04+U971Q7ja+wVg9zibOuZxKhpQYnoNJwS41sWwqtsp3QU9eJ6Rck14lzVngDPl++xuZAA/QImlMhuaLSGE57ozo6dv1oRt2jcsXzPaaA8y+g3nmX4hKnXF0XpnqF7v0ayveutuX56gP9to3sLrovmKoycutD2ebrlM/n8/l/AAAA//8DAO33rqElBAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUUW/cKBDHv4rFs3EAY2z8Fm1a3SrXy6pd9U73NoZxg+LACnDaKNrvfsK7pzZPp3tBaGBm/vObgTfi4RnJSG5Ppw8v6HMiNcluMwkmFGWKMn7k7Sj5KGUjWNdxrf8mNXH3+EpG0ktjuNFIW1RIpWUdndrZUGtRc8YtE50sMeFbIuMbAddYfHEGm5C+YkwueDKSP5234XvJDa4xS1htE8OCe58yeFPE/LHf3dPfbw/Hh8PlVsJUnBtnyUiGoVedNYpKLZBKCYKC6Wba81YbOTOcdREBrnE+Y/SwNMk+/cxvQ/aYzSga0TaMCk3ONbGQoUieIOHx9VRUbIjuir3ezNt2fCMvGMko6n9hXsLdmMXdPKdpdYu9uawZ0lPa1hlMDvGV1OQUwwljdrjxuU0Jn6fl9Qjp6ePlTtmmDz/QrBntLqw+k5HwVpGabICWBbILvrpq3C0Ofd4Oc3Q+OfNfsVpSk4cv1WGBPIf4/K4fXy6Y9/+D8icwj85jtb8jI2EchW0HpLPgisrBAoWu1VSpVs3Ije4FJzXZBZ+dX8Oaqr3P+C1uJZGRfIQl4UXfbTSPLqPJayx1/qVKskMMdjW5+tlLzhrWtIwVpzWf1lx9RusimoyliGNcr/G+vncRSmxOuzVG9Lk6QH6sfoP0SEaiYTAcNGgAZcyMHcOZWQaK9RaVVWilsL2VWlolNTNKwsSlhY5Pc7GQmmAZnWqbVrRopIGOzgonKqeuoxMOQGHgyGduWC/ec6weluIHZmASbUs1zpZKzYFq2bbUth30Qs19L+ZfkFzngbMC2OLL5d1tCpS1A1rFqZC8o1JrTgfd9XTqh0lPasDOFM33GD0uv4D65EwMKcy5uk5I9Q7d59WXv6PapuW78/TH1qO7YJ4wVqXH4Hx5Kte2ns/n8z8AAAD//wMAE1/rSoIEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPosyXKFE3Y52iCzfxIlmkRW8jchgTlqkFRTkJjP3vAbUbJO6tF4IY8Jv5HsNXEuEZyUBuT6d3LxjzQmqSw1YSTGjKNGX8yOWg+KBUI1jPW8X/JTUJ9/idDKRT1nJrkErUSJVjLR2lt9Q5NJxxx0SrSk/4spDhlUBoHL4Ei828fMa0hDmSgfwdopu/ltkQGjvNq2vSPOE+LhmiLWQ+7Hf39K/bw/HhcHm14FLATXBkIH3f6dZZTZURSJUCQcG2nnZcGqs8Q28KCQhNiBlThKlZ3NOv+W7OEbMdRCNkw6gw5FwTBxkK5REWPH4/FRabRXelXm/l7Tq8khdMZBD1TzMv7W7sFG6el3ENk7u5nBmWp6LylOYTphxw82STOU2Qwxyr66TdFDBmUpOHT9Vhguzn9PzGqE8X/fv/If9Ypr/7hnbN6HbzGjMZCJeG1OQ92McQsdrfkYEwjsLJHqkXXFPVO6DQSkO1ltojt6YTnNRkN8cc4jqvS7WPGb+kTQAZyB8wLXihfpvsY8ho85qKqn904XFIs1ttrn75z1nDGslYAa35tObqI7qQ0GYs+o5pvfb7D0RosYF2a0oYc3WA/Fj9CcsjGYiB3nIwYAC0tR5bhp45Bpp1DrXT6JRwnVNGOa0Ms1rByJWDlo++VEhNsMRdbRsmZQe9B0k77wRVnUDaOwTq1WgFiHZUKN/4WD1MBQe2ZwqdpAa9o8pwoEZJSZ1soRPad53wv1lyTZ+zYrDDl8tf2Rho53p0mlOheEuVMZz2pu3o2PWjGXWPrS2c7zFFnH4z6n2waV5mn6vr8lRvrPu4xvLfq22RvoZIv20Z3c32CVNVMoYQy3pfYz2fz+cfAAAA//8DANVoRU82BAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUXW/jKBSG/4rFtXEBY2x81013tFGn02ianV3tHYbjFNWBCHBnqyr/fYSTqumM9mLvrGPe8/GcF16RU3tAPbo+HH5/BpciKlGyS4gRJjARmNAtrXvO+rqpBCed5OIfVCJ7Cy+oRy3XmmoJuAYBmBvS4KEeNTYGJCXUENbwnFPtIupfkbKVgWerofLxG4RovUM9+ss647/n2spWevKzqYKfYO1iUk7nZr6sV7f48/Vme785nYoQs7iyBvVoGLnhghisBRsxJx3BHSiBFVDgpqMSWHOSWZcgODVV0Ty91zc+OUi6ZxWrK4KZRMcSGZVUbnlQEbYvh9zFgugmx8slvHz2r+gZAupZ+QbzlO5KT/ZqH4fZTuZq8ruddbuVd6PdzUGlXLhEh+APEJKFBc5v1qnw8tnvdjkf+qSmCKhEWwh769R0+nEDo5qn9ODnsJCJ5um/zqAeqTl5VKKF5DQtZYvzMKvJgku/aC8K3z8Um0ml0Yf9hyU9nNiv/wf6O6UfrYNifYN6RCgwU3eAR0YF5p1RWDW1xELUYgSqZcsoKtHKu2Td7OdYrF2C3Znah/6ug360CXSaQ57pb5HNtgnezDoV7wumpCJVTUgWzekwp+IrGBtAJ8hDbMN8zveThAm2iD7ZCX7Bs5pDAJeKjUqPxR8qPqIeSdVpqqSSSgmtR2gIjMQQJUhrQBgBhjPTGi65EVwSLbgaKDeqocOYI6hEkE1WLL4momasIxLX1HSY12ODpaoHzIWghOpRctZ+gFvcT1mndEc4mBpLGA3mkioseV1jUzeqZWJsWzZecDobgpJM/dKEf0YwZy99OVn7bXYDz6d7vPQpjOnACIoZpw3mUlLcyabFQ9sNchAdNDpPtvIu+jeQ3yAMPtqUH5E76+xeTT8fed/MLQQH08V27qwOPvoxFWdbFh/29XV2+RUrFot+tw7/uxjjxusnCEU2lrLuYpnH4/H4AwAA//8DACOBIt4MBQAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1Hm/aI3w27RhZt6ES/aoG8UZxQL0UoLito0MPa/F9RukbhveRMGOsPDb87wjUzhiKQl96fTL2ec8kJqkoetJJgwlBnK+IHLVolW6sYw77TWf5OaDE/4jbTEqhh59EglGqQKmKad7CMFQM8ZBya0Kj3D54W0byQMDeB5iNjMy5+YlmGeSEv+GiaYv5azw9DEcV6hSfOIu2nJYYrFzB+7hyf6+/3+8Ly//rXgUsTNAKQlXa9AGQY0GtFTxRyjDoOhATkqcNyj0FfZMGVMUxibBb58Px/mPGGOrWiEbBgVnlxqAiGHYrkLCx6+nYqLDdFjqddbefts38gZE2lF/R/Ma7u7OA53y9qNeMbxFNKC6S7Ox2OYgNTklOYTpjzghuWMqZuXIReiMdrgHOfgglXagpNaSAuSIThmNXjwwSjTi6h1D53zVvUKBFdgUKnOkpps4MYx5GGeqpv3h3HAKZOaPL9U+zHkfk7Hd+hfrkR3PwG02CYtkUxLYy0qKWXwphMMwZpojOhiYLbvBPKITHtlPbeMSy+Yl9pYZyEwH0lNPoT4OkxY7R5JSxhHAdIh7QU3VDkINGjpqTHS9Mijt4KTmjzMUx6mdV6Xajdl/Jy2+5KW/BrGBa83vU/xdcgY85oKhE+mhHGfZlhjrr4HgLOGNZKxIlrzac3VR4QhYcxYcBzSeuv3P4kwYhM9rCnhlKt9yK/Vb2F5JS3xwUUefPAhmBh71Ax7BiwYZgENGAQlwILyCozyLBoVOq4gaN71pUJqgiVv1RZxzXoudadpj6ipYr2gnjFHey6CdMZaUPIdx+p5LLoQHVMIknrsgSrPA/VKSgpSBytMb63of0ByCwtnBTDg+bqsmwMD4BAMp0JxTZX3nDqvLe2s63xnHOpYPD9hmnD8AdSHIaZ5mftc3bJWvUP3cZ3Kg1Ntufs6TPSfbUaPc/yCqSozDsNU9us21ktNjhiWNeFxe6/aN7Ivy1UdtmdL6IZ5J2rykkPK6+lW1rKxzrjL5XL5FwAA//8DAPYEweL0BAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HVTL+JFWvQ2Ike2EC21oKhNA2P/e0DtBol7600Y6J0ZPvPOvJEIByQduT0efzlhzAupSR63kGBCU6Yp43suOyU62Tat4cpq9w+pyfiIX0lHjPKee4dUokaqAmtpLwdPQ0DHGQ9MtKrkhJeFdG8ExibgafTYzMsnTMs4R9KRv8YY5i+lNoyNn+Y1NGme8CEuGaIvzfz5cPdI/7jd7Z92l78WXIq4GQPpSD+ooDQL1GsxUMUsoxZBU0COKljuULQX2RgzpghTs4TPP+qHOUfMvhONkA2jwpFzTQJkKC33sOD+67F0sSG6L/F6C2+f3Rs5YSKdqL/DvKS78dN4k+fjhCecjpAWTDd+PhwgBlKTY5qPmPKIG5btpdMEeZxjdS12N40YM6nJ03O1myAPczq8Y/V8QfDwPwicMPWkI5K1UhuDSkoJTveCYTDaay16D8wMvUDukbVOGccN49IJ5mSrjTUBmPOkJi/T3MP0+7Lxc4L1NjAjtECFTiitnWcoLQ6tQRZA615b74K0RigbrAQHwF2Pxjvti0E+gH8dI1YP96QjjKMI0iIdBNdU2QAUWumo1lIPyL0zgpOa3M0xj3Gd16V6iBlf0saPdORXmBa8kLtN/nXM6POaCtS/dSm2S3NYfa5+OICzhjWSsSJa83HN1UcMY0KfseDdp/Wa7z8SocUmultTwpirHeTX6jdYXgsVsJ6DK0/V3g/YMhxYYKCZCaiDxqBEMEE5FbRyzGsFPVcBWt4PJUJqgsVw1eZxqSQGNgBtfQtUoeYUmDXUh9aI4EQ/wHuO1dNUdOAtUxgkdTgEqhwH6pSUNMgWjNCDMWL4CcnVfJwVwAFPl23dOtAhWAyaU6F4S5VznFrXGtob27teW2x96fkRU8TpJ1AfRp/mZR5ydfVu9Q7dxzWWi1NtPv4yRvrvNqP72X/GVJUZwxjLgl3Heq7JAWFZEx62g9W9kV3Zrmq/3S3RNsxZUZPnDCmvx2u4lY2x2p7P5/M3AAAA//8DADaVhNr1BAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJSFCUK2IPhtFgjTWMk7u5ibxQ5jInIokFRToMi/31BWa6dooe9CaN5fY/hD9SrPaAGLQ+HT0fo44AWKLopxAgTmAhM6JYWDWdNIXJS0IrW7F+0QO4O3lCDKq411RJwAQIwN6TEbWE1NgYkJdQQVvLUUz0PqPmBlMsNHJ2G3A9/QRic71GD/na98a9ptnK57vxo8uA7WPdDVL1Oy3xdr+7wl+Vm+7A5ZQ0wpOLcGdSg1nLDBTFYC2YxJzXBNSiBFVDgpqYSWHkqc32E0KsuH8zLZb7xsYeoG5azIieYSfS+QEZFlVZu1QDbt0PaYqLoNsUXU3j6bH6gIwTUsMWZzFO7G925m/3Qjq4zN1GFZ4g2qD28+vACR9WhBToEf4AQHUzcPDxll5UoyUnOBCMELdC90jvXQ7a+zR66BFjpmnAwBZZgDeaSKix5UWBTlKpiwlYVs2iB7iD00F11vXc6+MHbmM2UZx/mrHwfXT/6ccjWfYTnoOKp7rPqBkALtBnbzg27R1Dmbesfx/SvH7uEZTWGAH3MNirusj/VsEMNkqrWVEkllRJaWygJWGKIEqQyIIwAw5mpDJfcCC6JFly1lBtV0tamCFqghzEexnjm//vVEtvg9nswlw22E8ebTkXrw35toI/OuiTNOWMyVNdNqLK556pz0McPJKMGEQrMFDVgy6jAvDYKq7KQWIhCWKBaVoyeCLPuefzJE7HW8MKWdS1a2VICzFY1J5VtidG20NKULVSsIlUNtdSEtCWndSs1MUBLbhK64M2o469WKCaBHsc+XWe2TrBfXY+/C35hZBN89Np3STDXwdPbEGH/O9VWfn/wg4sJv52l/TbAve/T3/n+Z87m4qWPlxikO8im0yuZopYwiRWnBea20LjmdYsVU9TQtpVGJxlvvX6BkCWDKddPmpw99fCULYPeuQg6jiFN/mcCdZLz8/lkLnzkXz9tVz7A8nBYzNE/jomkU7OzAT68K9+GlL7zQ7yCPEN7gs6eF7uyk4Hj6alyKSiMqcEIihmnJeZSUlzLssJtVbeyFTWUE86TXbNHMC6AjlO/bRjTtJnZ3/lyGaKzSschHc8Xryc7zf6cU35d8kq2n9Wn4VfSzVaaO1GSLPt0ejgnB/2vd/P9/f39PwAAAP//AwC2uuIgKAYAAA==
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxU227cNhD9FYGvFRXeRJF6c20HXaSOjeyiLfo2Ikc2a5laUJSTwPC/F9TauaJAXwRhSM45c+bMPJEID0h6cnY8Xj5izAupSQ5bSDChKdOU8QOXvRK94o0xgivd/U1qEt7hZ9KTTjnHnUUqUSNVnrV0kKOj3qPljHsmWlVywu1C+icCofH4GBw28/IHpiXMkfTkzxD9/LFgQ2jcNK++SfOEu7hkiK6Qeb87f0d/P7s5XN+cbi24lMdN8KQnw6i80sxTp8VIFTOMGgRNATkqb7hF0Z6ehZgxRZiaxd9/xfdzjphdLxohG0aFJc818ZChUB5gwcPnY2GxSXRR4vUW3n77J/KIifSifhXzlO6Nm8Kbh2VYw+TfbF9Sk2Oaj5hywE2N6331lQRnDWuEFoyRmlyBuwsRq91FdT2VEsEZptBLanH0VFkO1CopqZctdEKPXSdGUpN3mCJO32S9Ci7Nyzzm6kXk6juc/dn5ZYRhwoLxFqYFSU12yz5D9DDNES8/oVvzKdchreX4fI45xHVel2oXM94meDl/fX++poQxVzeQ76rfYLkjPbFgHAcLFkA7N2LLcGSegWadR+01eiV855VVXivLnFYwcOWh5cNYIqQmvxYN96tzuCxf2WwmmaaNQ/XSp/MpYMzfyUh6wjgKLw3SUXBNlfFAoZWWai31iNzZTvBXmAOkW8ykJ6MZhoE5NwhluQNhQfqRSa9HK0TXgRpl2ymhdcs6cL7rBFdeduhAjpIZQWpyk2a/uvxjq+XWgJs0/4MuF6lITzRrW+NgGIRW3IA1qLhWRlvsrBqBKekG4K2BYeAMWuasEQ64tqAG345fVLqMtyHiRViOE3z+Btc0upG/OADDR1A/XH+b4AE/zun+/cnGzfvLA6nJhzWWjVDtikU+hkg/6TLRV+uUw+EuIXj0V7PHn32EZVyqbUJH27pRGks96DKhbKAwGEalYcC1VErpov3F7O4xVcVhEGKZqi/JrvfVWXJ3IaPLayr8/tp4XO+rmwnyOKeH7zbJN4X9KEAjJGelMx4fT9to46i9N+g1p0LxliprOTW27ejQmcEO2mDrimLXaz6uufqAPiR0eav4xYsb5vkduvufxXh1wYtFOSv17k9bbJP2fy2x55o8ICxrwodtW/dPZBcjpg35Yj2N4i5ehWkKC7o5+oX0WijTdK1WLwz/855kvOmkUs/Pz8//AgAA//8DAEDMGTMbBgAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTTW/cNhD9K8KcRZmkKErUzVin6MJNvEgWadEbxRnFhGVqQVFOAmP/e0DtBk5664UgBnwz72P4CsE+E/Rwezq9e6GQFigh+a0kudSMa8bFUdS9kr0SVdd2XKruXyjB39N36KFVzglniNWkiSnkDRvq0TFEMoIL5LJRuaf9skD/CtZXSC/eUTUvnykufg7Qw98+4Pw1z7a+ctO8YhXnifZhSTa4TObDfnfP/ro9HB8Ol1cLLRlceYQehlGh0hyZ03JkinecdWQ1syRIYScMyeYC8yFRDHaqFnx6m49zCpRcLytZV5xJA+cS0CabKQ92oeP3U2axWXSX6+VW3q79K7xQhF6WP828tLtxk795XobVT3hzOZNdnrLKU5xPFJOnzZNN5jTZ5OdQXCftJk8hQQkPn4rDZNM4x+ffjPp00b//H/KPefq7b+TWRLib15CgB1EbKOG9dY8+ULG/gx64IIl1R2yUQjPVoWW2qQ3TutYjCWdaKaCE3RySD+u8LsU+JPoSNwHQwx92WuhC/Ta6R5/IpTVmVf/ovAuHOOPqUvHmv+AVr2rOM2hNpzUVHwl9JJco6zvG9drvPxCp5QbarTFSSMXBpsfiT7s8Qg/Gdk5YY4212rmRGk4jR241b5E0akIlsUVlFGpluNPKDkKhbcQw5gqUQDnuYtswIdRQu4GYbCRnCp1idqCWNdia0TnpBpspvvlYPEwZZ13HFWHNDI3IlBGWGVXXDOvGtlKPbSvHXyy5pi94Nhjp5fJXNgYasSPUgkklGqaMEawzTcuGthvMoDtqXOZ8TzHQ9ItR772L8zKPqbguT/GbdR/XkP97sS3SVx/Yty2ju9k9USxyxtaHvN7XWM/n8/kHAAAA//8DAOoNqD02BAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRUwW7cNhD9FWHOokxSFCXqZqwTdOGmXiSLtOiN4oxiwjK1ICknhrH/Xki7ReJT0QtBjPiGb9571BsE+0zQw+3p9OGFQk5QQvZbSXKpGdeMi6OoeyV7JaquVa1q6r+hBH9Pr9BDq5wTzhCrSRNTyBs21KNjiGQEF8hlo9ae9luC/g2sr5BevKNqTl8pJj8H6OFPH3D+vt5tfeWmecEqzhPtQ8o2uJXMH/vdPfv99nB8OFxOJUoruPIIPQyjQqU5MqflyBTvOOvIamZJkMJOGJLNBeZDphjsVCV8+nk/zjlQdr2sZF1xJg2cS0Cb7Up5sImOr6eVxSbR3Vovt/K27d/ghSL0svxXzEu7Gzf5m+c0LH7Cm8uabXpK2zpal+f4CiWc4nyimD1t+tymRM/D9Hq06enj5cy6TR9+kFsy4W5eQoYeRK2hhE2gabLZz6G4ctxNnkLePuboQ/Luv3rVUMLDl+Iw2TzO8fmdH18uMu//h8qfrHv0gYr9HfTABUmsO2KjFJqpDi2zTW2Y1rUeSTjTSgEl7OaQfVjmJRX7kOlb3EaCHj7aKdGF3210jz6Ty0tc5/xLr7k6xBkXl4ufXgpe8armfAUt+bTk4jOhj+QyrUMc43Lt9/U9RGq5gXZLjBRycbD5sfjNpkfowdjOCWussVY7N1LDaeTIreYtkkZNqCS2qIxCrQx3WtlBKLSNGMa1AiXQGp1iS6uVjZAtR9Y5NTJFamRdKw3ruNNScMnR4Dsdi4dpw7mOK8KaGRqRKSMsM6quGdaNbaUe21aOv0hyzYPgq8BIL5d3tzHQiB2hFkwq0TBljGCdaVo2tN1gBt1R41bO9xQDTb8I9cm7OKd5zMU1IcU76T4vYf13FFtavvvAfmwe3c3uiWKxemx9WJ/K1dbz+Xz+BwAA//8DAELILvyCBAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1Hm/aI3w27RhZt6ES/aoG8UZxQL0UoLito0MPa/F9RukLpveRMGOjOH3xzyjUzhiKQl96fTL2ec8kJqkoetJJgwlBnK+IHLVslW8EZK75R2f5OaDE/4jbTEqhh59EglGqQKmKad7CMFQM8ZBya0Kj3D54W0byQMDeB5iNjMy5+YlmGeSEv+GiaYv5bZYWjiOK/QpHnE3bTkMMVi5o/dwxP9/X5/eN5f/1pwKeJmANIS1wsTQtdR77tAFaCjgXtOueaopFYBFb/KhiljmsLYLPDlx3yY84Q5tqIRsmFUeHKpCYQciuUuLHj4diouNkSPpV5v5e2zfSNnTKQV9XeY13Z3cRzulrUb8YzjKaQF012cj8cwAanJKc0nTHnADcsZUzcvQy5EY7TBOc7BBau0BSe1kBYkQ3DMavDgg1GmF1HrHjrnreoVCK7AoFKdJTXZwI1jyMM8VTfvD+OAUyY1eX6p9mPI/ZyO79C/XInufgJosU1aIpmWxlpUUsrgTScYgjXRGNHFwGzfCeQRmfbKem4Zl14wL7WxzkJgPpKafAjxdZiw2j2SljCOAqRD2gtuqHIQaNDSU2Ok6ZFHb0WZ/jBPeZjWeV2q3ZTxc9rOS1ryaxgXvJ70PsXXIWPMayoQPpkSxn2aYY25+hEAzhrWSMaKaM2nNVcfEYaEMWPBcUjrrd//JMKITfSwpoRTrvYhv1a/heWVtMQHF3nwwYdgYuxRM+wZsGCYBTRgEJQAC8orMMqzaFTouIKgedeXCqkJlrxVW8SNFyxy1VOuvKLKR0+d95zqTisP6KXD/h3H6nksuhAdUwiSeuyBKs8D9UpKClIHK0xvrSi670huYeGsAAY8Xy/r1QGAQzCcCsU1VWW489rSzrrOd8ahjsXzE6YJx/+A+jDENC9zn6tb1qp36D6uU3lwqi13X4eJ/rPt6HGOXzBVZcdhmMr9uq31UpMjhmVNeNzeq/aN7Mvlqg7bsyV0Y73zNXnJIeX1dCtb2Xjv3OVyufwLAAD//wMAMacs9fQEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJKFCUK2IPhtFgjTWMk7u5ibxQ5jInIpEFRToMi/31BWa6dooe9CaN5fY/hD+TkHlCLlofDpyO4OKAFinYKFaTgmHBM6JaWLSvbguZNwTgvxL9ogewdvKEW1UwpqgTgEjhgpkmFu9IorDUISqgmRcVST/k8oPYHkjbXcLQKcj/8BWGw3qEW/W2d9q9ptrS56v2o8+B7WLshSqfSMl/Xqzv8ZbnZPmxOWQMMqTi3GrWoMQWXsuuwEJ3ETEODJRUU04oCKysmgdFTmXURgpN9PuiXy3zto4Oo2iIvypzgQqD3BdIyyrRyJwfYvh3SFhNFtym+mMLTZ/sDHSGgtlicyTy1u1G9vdkP3Wh7fRNleIZogtzDqw8vcJQ9WqBD8AcI0cLEzcNTdlmJkpzkBS8IQQt0L9XOOsjWt9lDnwBL1RAGusQCjMZMUIkFK0usy0rWBTd1XRi0QHcQHPRXXe+tCn7wJmYz5dmHOSvvonWjH4ds7SI8BxlPdZ9lPwBaoM3Y9XbYPYLUb1v/OKZ/buwTltUYAriYbWTcZX/KYYdaJGSjqBRSSMmVMlARMEQTyUmtgWsOmhW61kwwzZkgijPZUaZlRTuTImiBHsZ4GOOZ/+9XS2yD3e9BXzbYThxvehmND/u1BhetsUmac8ZkqL6fUGVzz1VvwcUPJKMWEQqFLhvApqAcs0ZLLKtSYM5LboAqURfJUSvvjH0ef/JEjNGsNFXT8E50lEBh6oaR2nREK1MqoasO6qImdQONUIR0FaNNJxTRQCumE7rg9ajir1YoJ4EeR5euM1sn2K/W4e+cXRjZBB+98n0SzPbw9DZE2P9OtZXfH/xgY8JvZmm/DXDvXfo73//M2Vy89PESg3QH2XR6siLSlCXHomQCM91JLIhssDGkNgZ0WUOJFujWqxcIWTKYtG7S5Oyph6dsGdTORlBxDGnyPxOok5yfzydz4SP/+mm78gGWh8Nijv5xTCSdmp0N8OFd+Tak9J0f4hXkGdoT9Oa82JWdNBxPT5VNQa51A5pTXDBaYSYExY2oatzVTSc63kClLnbNHkHbACpO/bZhTNNmZn/ny2WI1kgVh3Q8X7ya7DT7c075dckr2X5Wn4ZfSTdbae5ESbLs0+nhnBz0v97N9/f39/8AAAD//wMAM2qugCgGAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSU227cNhCGX0XgtSjzJB50Z9gt6rqpF/EiLXo3JEe2EK20oKhNA2PfPaB2g8S9650w0D+Hb/7hG5nggKQjt8fjLyec8kJqkoctJJjQlGnK+J7LTslO8EY4boXl/5CaDI/4lXTEqBB4cEglaqQqspZ62QcaIzrOeGSiVSUnvCykeyMwNBFPQ8BmXj5hWoZ5Ih35a5ji/KXUhqEJ47zGJs0jPkxLhimUZv58uHukf9zu9k+7y18LLkXcDJF0xPZCA3hPnfNAVURLgTtOectRyVYBKn6RDVPGNMHYLPHzj/pxzhPm0IlGyIZR4ci5JhEylJY9LLj/eixdbIjuS7zewttn90ZOmEgn6u8wL+luwjjc5Pk44gnHI6QF002YDweYIqnJMc1HTHnADcs26ThCHuapuha7GwecMqnJ03O1GyH3czq8Y/V8QfDwPwicMHnSEclaqY1BJaUEp71gGI0OWgsfgJneC+QBWeuUcdwwLp1gTrbaWBOBuUBq8jLOHsbfl42fE8zbyIzQAhU6obR2gaG02LcGWQStvbbBRWmNUDZaCQ6AO48mOB2KQT5AeB0mrB7uSUcYRxGlRdoLrqmyESi00lGtpe6RB2dEmeZunvIwrfO6VA9Txpe08SMd+RXGBS/kblN4HTKGvKYC9W9diu3SHNeQqx8O4KxhjWSsiNZ8XHP1EeOQMGQsePdpveb7j0RosYnu1pRwytUO8mv1GyyvhQrYwMGVUXUIPbYMexYZaGYi6qgxKhFNVE5FrRwLWoHnKkLLfV8ipCZYDFdtHjcsGghtT73RLVWtZ9RxISj4wGPfC2Xb9h3H6mksOgiWKYySOuwjVY4DdUpKGmULRujeGNH/hORqPs4K4Iiny7VuHegYLUbNqVC8pco5Tq1rDfXGeue1xTaUnh8xTTj+BOrDENK8zH2urt6t3qH7uE7lxak2H38ZJvrvtqP7OXzGVJUdwzCVA7uu9VyTA8KyJjxsD1b3Rnbluqr99m6JtjHOupo8Z0h5PV7DRjbOWXs+n8/fAAAA//8DALmMltD1BAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUTW/jNhCG/4rAs6mQFEWZuqVOFzWy2Rgbd1v0NiJHDhGZNCgq2yDwf19QdhBnFz30Joz4zsczL/lKPOyRtOT6cPj9GX0ayYIkN4cEE4oyRRnf8qqVVSt4WSnBlBD/kAVxt/hCWtJIY7jRSCtUSKVlNe2q3lBrUXPGLRO1zDlhN5L2lYArLT47g2UYv2EcXfCkJX85b8P3XBtcaYYw2TKGAdd+TOBNbubLenVLP19vtveb06kRxywunSUtWfZCAXQd1boDKi0uKXDNKa85yqqWgJKfZM4njB6GcrRP7/VtSB6TaUUpqpJRoclxQSwkyC13MOL25ZC7mBHd5PhiDs+f7St5xkhasXiDeUp3ZQZ3tR+7yQ32agi7nfO7VfC9200RUi68IIcYDhiTwxnOb85DfPkcdrucj3yCYUSyIFuMe+dhOP24wR6mIT2EKc5kRvv0X2dIS2BKgSzITHIY5rLFeZjV4NCnX7QXhe8fis0AqQ9x/2FJDyf26/+B/g7Mo/NYrG9ISxhHYasl0l5wReXSAoW60lSpSvXIjW5E1qyCT85PYRqLtU+4O1P70N91NI8uoUlTzDP9rbLZNjHYyaTifcGclaysGMuiKR2mVHxF6yKahHmIbZzO+X6SCCVm0Sc34C94VlOM6FOxgfRY/AHjI2mJhqXhoEEDKGN6rBn2zDJQrLGorEIrhW2s1NIqqZlREjouLdS863OELAhmkxWzr1HpjlVNTbUGQWUvO6pr2dAKGmGENpxVH+EW90PWgVkyibaiGntLpeZAtawqaqsaGqH6phH9BaezITjLyS5N+OeI9uylLydrv81u8fl0j+c+lbVLtIpTIXlNpdacLnXd0K5ZdrpTS6xNnmwV/BjeQH7D2IXRpfyI3Dnv9jD8fOR9M7cYPQ4X27lzJoYx9Kk427L4sK+vk8+vWDFb9Lvz9N/ZGDfBPGEssrHA+YtlHo/H4w8AAAD//wMA2IvlogwFAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTwW7UMBD9lcjndWo7jhPnVm1BrAp0RStA3CaeCWuROivHKaBq/x05uwjKjZv17Dfz5r3xMwvwSKxj18fjqycKaWYblvwKKaEMF4YL+SCrTledsmUjhGis+sI2zN/ST9axRjsnnSVekSGuUdS8rwbHEclKIVGoWuea8HVm3TMDXyI9eUflNH+kOPspsI598gGn77k3+NKN04JlnEbahTlBcFnM+932lr+93j/c7c+vZpozufTIOtYOygD0Pbe2B66RWg7SSi5rSbqqNZCWZ5oPiWKAsZzx25/+OKVAyXWqVFUpuLLstGEICbLkHmZ6+HnMKlaLbjK+WeH12D2zJ4qsU5vfZp7LXbnRX7np8RECXg0++PnANuwYpyPF5Gm1Y51wHCH5KRSXJtvRU0hsw+7ui/0IaZji4wuP7s+j7/5j8nfgDj5QsbthHROSFFYt8UFJw3WLwKGuLDemMgNJZxuVOdspJB+WaZmLXUj0Na4qWcdewzjTWd91dAefyKUlZumfTc6afvi0nTADgm3YPk64uFT8sVuKUpSVyJd3SzouqfhA6CO5RHmmh7hcyv9DUUatpO0SI4VU7CEdijcwH1jHLLROggULYJwbqBY0CBRgRINk0BBqhQ1qq9FoK5zR0EuNUMt+yEjWndMt1oXSUuKAdcO1A8216DXvexq4rYwZemtb0eMLW4u7MfPAtUITVtzSgFxbCdzqquJY1dAoMzSNGv6y5JK4FNlvpKfz11gVGMSW0EiutKy5tlby1tYN75u2t71pqXZZ8y3FQONfRr3zLk7zNKTisjDFC+s+LCF/72Jdnu8+8B9rZDeT+0axyJGDD3mbLymfTqfTLwAAAP//AwAqQNGLJQQAAA==
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRUTW/cNhT8KwLPS5lfokTdjHWCLtzUi2SRFr09kU8xYZlakJQTw9j/XlDaIPWp6IUgnjiP82aGeiMBnpH05PZ8/vCCISeyI9mvJcGEpkxTxk9c9kr2wtTaKK2N+JvsiL/HV9KTVlnLrUEqUSNVjjV0kKOlzqHhjDsmGlV6wrdE+jcCvnb44i3Wc/qKMfk5kJ786YObv5e7wdd2mhdXx3nCQ0gZgi1k/jjs7+nvt8fTw3E7lTAVcO0d6Uk3Cg0wDNSYAahy2FHghlPecFSyUYCKbzAfMsYAU53c06/73ZwDZtuLWsiaUWHIZUccZCiUB0h4ej0XFqtEd6W+W8vrtn8jLxhJL3Y/xdza3djJ3zynYfGTu9nWDOkpresINs/xlezIOc5njNnjqs9tSvg8TK8nSE8ftzNlmz78QLtkdPt5CZn0hEtNdmQVaJog+zlUV477yWPI68ccfUje/lcvSXbk4Ut1nCCPc3x+58eXTebD/1D5E9hHH7A63JGeMI7CyQ7pKLimqnNAoZGGai31iNyaVhTMfg7Zh2VeUnUIGb/FdSTSk48wJdz43Ub76DPavMQy51+65OoYZ7fYXP3ykrOa1ZKxAlryecnVZ3Q+os1YhjjF5drv63uI0GIF7ZcYMeTqCPmx+g3SI+mJgc5yMGAAtLUjNgxH5hho1jrUTqNTwrVOGeW0MsxqBQNXDho+jKVCdgRLdKotrUK2jbSKIraWKmY5NdIyqgE1ArDOmPGdjtXDVHBgO6bQSWpwdFQZDtQoKamTDbRCj20rCu6nJNc8cFYEdviyvbuVgXauQ6c5FYo3VBnDaWealg5tN5hBd9jYwvkeY8DpX0J98jbOaR5zdU1I9U66z0so/45qTct3H+iP1aO72T5hrIrH4EN5KldbL5fL5R8AAAD//wMAoRyWV4IEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPS5kvUaJuxjpFF27qRbJoi95GnFFMWKYWFOUkMPzfC2o3SN1bLwQx4DfzPYavLMIzsZ7dns8fXijmhe1YDltJCWW5sFzIk9S90b1ytXVtq1X3N9uxcE/fWc9a4730jrgmS9ygaPigR88RyUkhUajGlJ7wZWH9K4NQI70ET/W8/EFpCXNkPfszRJy/ltkQaj/NK9ZpnugQlwzRFzK/H/b3/Lfb4+nheHm10FLAdUDWs25UFmAYuHMDcIPUcZBOctlIMroxQEZeYCFmShGmesGnn/NxzpGy71WtdC24cuxtxxAyFMoDLHT6fi4sNovuSn23lbdr/8peKLFe7X6YeWl346dw87wMa5jw5nJmWJ6KynOaz5RyoM2TTeY0QQ5zrK6T9lOgmNmOPXyujhPkcU7P74z6fNF/+B/yT2X6h2/k10y4n9eYWc+kdmzHPoJ/DJGqwx3rmZCkUHfERyUtNx0Ch0Y7bq22I0nvWlXa7eeYQ1zndakOMdOXtAlgPfsFpoUu1G+TfwyZfF5TUfWXLbtwTDOuPlc//ZeiFrUWooDWfF5z9YkwJPKZir5TWq/9/gNRVm2g/ZoSxVwdIT9Wv8LyyHrmoPMSHDgA6/1IjaBRoAArWiSLltAobNE4g9Y44a2BQRqERg5jqbAdoxJ3tW0YaAckoOPK6ZabDog77DQfpDANYmPGcXznY/UwbTjfCUOouaMRuXESuDNac9QNtMqObasK7ocl1/SlKAYjvVz+ysbAInaEVnJlZMONc5J3rmn50HaDG2xHjS+c7ylFmv5l1Mfg07zMY66uy1O9s+7TGst/r7ZF+hoi/7ZldDf7J0pVyRhCLOt9jfXt7e3tHwAAAP//AwDn5IjHNgQAAA==
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxU227jNhD9FYGvFRXeRIl6S50saqRJjLXRFn0bkaOYjUwZFJXsIsi/F5KTzWVRoC+CMCTnnDlzZp5IgAOShpwfj5cPGNJIcpL8EhJMaMo0ZXzHZaNkI0xRMc60qP4mOfFX+J00pFLWcmuQStRIlWMlbWVnqXNoOOOOiVLNOeFuJM0TAV84fPAWi2H8A+Poh0Aa8qcPbnicscEXth8mV8Shx3UYEwQ7k7lZr67o7+eb3e3mdGvEcX5ceEcaUndCA7QtNaYFqhzWFLjhlJcclSwVoOKnZz4kjAH6YnT3b/huSAGTbUQhZMGoMOQ5Jw4SzJRbGHH3/TizWCS6mOP5El5+myfygJE0In8V85TuzPb+7DC2k+/d2fIlOTnG4YgxeVzUuN1mbyQ4K1ghtGCM5OQa7N4HzNYX2W0/lwi2ZgqdpAY7R5XhQI2SkjpZQiV0V1WiIzm5whiwf5f12ts4jEOXsheRsw842/PVZYC2xxnjC/Qjkpysx22C4KAfAl5+QzulU65dnObj1RCSD9Mwjdk6JLyL8HL++n41xYghZRtI++w3GPekIQZqy8GAAdDWdlgy7JhjoFnlUDuNTglXOWWU08owqxW0XDkoedvNEZKTX2cNt5O1OI5vbBaT9P3CIXvp06r3GNIHGUlDGEfhZI20E1xTVTugUEpDtZa6Q25NJfgrzA7iHSbSkK5u25ZZ2wpluAVhQLqOSac7I0RVgepkWSmhdckqsK6qBFdOVmhBdpLVguRkEwc32fS51XJpwCYO/6BNs1SkIZqVZW2hbYVWvAZTo+Ja1dpgZVQHTEnbAi9raFvOoGTW1MIC1wZU68ruh0qX4c4HvPDjsYfv73DrQhfyFwtQ8w7Up+tfIhzwcYj3NycbFzeXO5KTr1OYN0K2ni3y6AP9pueJvp765Hf7iODQXQ8Of/YRzuOSLRNaCle7sgTKVN1RBVpSkAopZ2WHyuqKYUVycjHYe4zZ7DDwYZ6qH8lut9l5tHuf0KYpzvz+WnjcbrNND6kb4uHDJnlX2GcBCiE5mzvj8OG0jRaO2rkaneZUKF5SZQyntSkr2lZ1a1pdY2lnxW6ndJxS9hWdj2jTUvGLFxfM1R7t/c9ivLrgxaKczV7bnrbYIu3/WmLPOTkgjFPEw7KtmyeyDgHjgnwxnUZxHa593/sR7RDcSJpaqrqodGVeGP7nPcVEURrGn5+fn/8FAAD//wMAys86yBsGAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1HmTbzozbBbdOGmXsSLNugbxRnGQrTSgqI2DYz97wW1G6TuW96Egc7w8JszfCOTPyLpyP3p9MsZp7yQmuRhKwkmNGWaMn7gslOqY65h1iij2d+kJsMTfiMdMSoEHhxSiRqpAtbSXsZAAdBxxoGJVpWe/vNCujfihwbwPARs5uVPTMswT6Qjfw0TzF/L2X5owjiv0KR5xN20ZD+FYuaP3cMT/f1+f3jeX/9acCniZgDSERukQotIdXSRKt621FkZKbjeCS1chBivsmHKmCY/Ngt8+XE+zHnCHDrRCNkwKhy51AR89sVy7xc8fDsVFxuix1Kvt/L22b2RMybSifo7zGu7uzAOd8vaj3jG8eTTgukuzMejn4DU5JTmE6Y84IbljKmflyEXoiEYby3nYL1RrQErWyENSIZgmWnBgfNa6ShC20borTMqKhBcgUalekNqsoEbR5+Heapu3h/GAadMavL8Uu1Hn+Ocju/Qv1yJ7n4CaLFNOiJZK7UxqKSU3uleMASjg9aiD56Z2AvkAVnrlHHcMC6dYE622lgDnrlAavLBh9dhwmr3SDrCOAqQFmkUXFNlwVPfSke1ljoiD84ITmryME95mNZ5XardlPFz2u5LOvKrHxe83vQ+hdchY8hrKhA+6RLGfZphDbn6EQDOGtZIxopozac1Vx8RhoQhY8FxSOut3/8kQotN9LCmhFOu9j6/Vr/55ZV0xHkbuHfeea9DiNgyjAyY18wAatAISoAB5RRo5VjQyvdcgW95H0uF1ARL3qot4kE538uoKVihqWLcUseNp4Frbr0B6eR7jtXzWHQ+WKYQJHUYgSrHPXVKSgqy9UboaIwok/yO5BYWzgpgwPN1WTcHGsAiaE6F4i1VznFqXWtob2zvem2xDcXzE6YJx/+A+jCENC9zzNUta9U7dB/XqTw41Za7r8NE/9lm9DiHL5iqMmM/TGW/bmO91OSIflkTHrf3qnsj+7Jc1WF7tiRrHBemJi/Zp7yebmXjGqWFuVwul38BAAD//wMACyupKPQEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUXW/jKBSG/4rFtXEBY2x81013tFGn02ianV3tHYZDiupAhHFnqyr/fYSTqumM9mLvrGPe8/GcF16RV3tAPbo+HH5/Bp8mVKLklhAjTGAiMKFbWvec90RWlJG2IfwfVCJ3Cy+oRy3XmmoJuAYBmBvS4KG2GhsDkhJqCGt4zql2E+pfkXKVgWenoQrTN4iTCx716C/nTfieaytX6THMpophhLWfkvI6N/NlvbrFn6832/vN6dQEUxZXzqAedbrm0AFgYaXFnDYNll1tsZGDZIJJa6w9yZxPEL0aq8k8vdc3IXlIumcVqyuCmUTHEhmVVG55UBNsXw65iwXRTY6XS3j57F/RM0TUs/IN5indlR7d1X4aZjeaqzHsds7vVsFbt5ujSrlwiQ4xHCAmBwuc35xX8eVz2O1yPvRJjROgEm0h7p1X4+nHDVg1j+khzHEhM5mn/zqDeqTmFFCJFpLjuJQtzsOsRgc+/aK9KHz/UGxGlWyI+w9LejixX/8P9HdKPzoPxfoG9YhQYKbuAFtGBeadUVg1tcRC1MIC1bJlFJVoFXxyfg7zVKx9gt2Z2of+rqN+dAl0mmOe6W+RzbaJwcw6Fe8LpqQiVU1IFs3pMKfiKxgXQSfIQ2zjfM73k4QJtog+uRF+wbOaYwSfio1Kj8UfanpEPZKq01RJJZUSWltoCFhiiBKkNSCMAMOZaQ2X3AguiRZcDZQb1dDB5ggqEWSTFYuv684CpR3BkrUK8xYkHngjMWmM0o1iurbtB7jF/Zh1SneEg6mxBGswl1Rhyesam7pRLRO2bZm94HQ2BCWZ+qUJ/5zAnL305WTtt9kNPJ/u8dKnMKYDIyhmnDaYS0lxJ5sWD203yEF00Og82Sr4KbyB/AZxCJNL+RG5c97t1fjzkffN3EL0MF5s587pGKZgU3G2ZfFhX19nn1+xYrHod+fxv4sxboJ+glhkYynnL5Z5PB6PPwAAAP//AwBHon9jDAUAAA==
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HVTL+JFWvRGcUa2EC21oKhNA2P/e0DtBol7600Y6J0ZPvPOvJHoD0g6cns8/nLCmBdSkzxuIcGEpkxTxvdcdkp1zDVMOWmF+YfUZHzEr6QjRoXAg0MqUSNVwFrayyFQAHSccWCiVSWnf1lI90b82ACexoDNvHzCtIxzJB35a4wwfym1/diEaV6hSfOED3HJPobSzJ8Pd4/0j9vd/ml3+WvBpYibEUhHbJAKLSLVgxuo4m1LnZUDBdc7oYUbYBgusjFmTNFPzQKff9SHOUfMoRONkA2jwpFzTcBnX1ru/YL7r8fSxYbovsTrLbx9dm/khIl0ov4O85LuJkzjTZ6PE55wOvq0YLoJ8+HgI5CaHNN8xJRH3LBsL50mn8c5Vtdid9OIMZOaPD1Xu8nnYU6Hd6yeLwge/geBE6aedESyVmpjUEkpvdO9YAhGB61FHzwzQy+QB2StU8Zxw7h0gjnZamMNeOYCqcnLNPd++n3Z+DnBegvMCC1QoRNKaxcYSotDa5CB17rXNjiQ1ghlwUrvvOeuRxOcDsUgH3x4HSNWD/ekI4yjAGmRDoJrqix46lvpqNZSD8iDM4KTmtzNMY9xndeleogZX9LGj3TkVz8teCF3m8LrmDHkNRWof+tSbJdmWEOufjiAs4Y1krEiWvNxzdVHhDFhyFjw7tN6zfcfidBiE92tKWHM1c7n1+o3v7wWKt4G7l15qg5hwJbhwIB5zQygBo2gBBhQToFWjgWtfM8V+Jb3Q4mQmmAxXLV5nPUoglWCGi0GqqyQ1AcItDUBNXBtPLB3HKunqeh8sEwhSOpwAKoc99QpKSnI1huhB2NEccZ3JFfzcVYAA54u27p1oAEsguZUKN5S5Ryn1rWG9sb2rtcW21B6fsQUcfoJ1IcxpHmZh1xdvVu9Q/dxjeXiVJuPv4yR/rvN6H4OnzFVZcZ+jGXBrmM91+SAflkTHraD1b2RXdmuar/dLckax4WpyXP2Ka/Ha9i4Rmlhzufz+RsAAAD//wMAolJWbPUEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJKFCUK2IPhtFgjTWMk7u5ibxQ5jInIpEFRToMi/31BWa6dooe9CaN5fY/hD+TkHlCLlofDpyO4OKAFinYKFaTgmHBM6JaWLWMtEXnVkJKX9F+0QPYO3lCLaqYUVQJwCRww06TCXWkU1hoEJVSTomKpp3weUPsDSZtrOFoFuR/+gjBY71CL/rZO+9c0W9pc9X7UefA9rN0QpVNpma/r1R3+stxsHzanrAGGVJxbjVrUqJJBA4C5EQYzWlVYNKXBWnSi4IUw2phTmXURgpN9PuiXy3zto4Oo2iIvypzgQqD3BdIyyrRyJwfYvh3SFhNFtym+mMLTZ/sDHSGgtlicyTy1u1G9vdkP3Wh7fRNleIZogtzDqw8vcJQ9WqBD8AcI0cLEzcNTdlmJkpzkBS8IQQt0L9XOOsjWt9lDnwBL1RAGusQCjMZMUIkFK0usy0rWBTd1XSTAdxAc9Fdd760KfvAmZjPl2Yc5K++idaMfh2ztIjwHGU91n2U/AFqgzdj1dtg9gtRvW/84pn9u7BOW1RgCuJhtZNxlf8phh1okZKOoFFJIyZUyUBEwRBPJSa2Baw6aFbrWTDDNmSCKM9lRpmVFO5MiaIEexngY45n/71dLbIPd70FfNthOHG96GY0P+7UGF62xSZpzxmSovp9QZXPPVW/BxQ8koxYRCoUuG8CmoByzRkssq1JgzktugCpRF/REmLHP40+eiDGalaZqGt6JjhIoTN0wUpuOaGVKJXTVQV3UpG6gEYqQrmK06YQiGmjFdEIXvB5V/NUK5STQ4+jSdWbrBPvVOvydswsjm+CjV75Pgtkent6GCPvfqbby+4MfbEz4zSzttwHuvUt/5/ufOZuLlz5eYpDuIJtOT3ZUdU1dYN5phZksBW50TXHZ1YqKQiqA1P3WqxcIWTKYtG7S5Oyph6dsGdTORlBxDGnyPxOok5yfzydz4SP/+mm78gGWh8Nijv5xTCSdmp0N8OFd+Tak9J0f4hXkGdoT9Oa82JWdNBxPT5VNQa51A5pTXDBaYSYExY2oatzVTSc63kClLnbNHkHbACpO/bZhTNNmZn/ny2WI1kgVh3Q8X7ya7DT7c075dckr2X5Wn4ZfSTdbae5ESbLs0+nhnBz0v97N9/f39/8AAAD//wMAkjOOpigGAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACoxUy27kNhD8FYHXiDLfEnVzbC8ycPzAziAJcmuRLZuxTA0oyt6F4X8PpLHXj0WAXAShSXZVV1f3E4lwj6Qlx/v92QPGPJGS5LCGBBOGMkMZ33HZKtVyXdVMas7s36Qk4Ry/k5bUyjnuLFKJBqnyTNNO9o56j5Yz7pnQaskJNxNpnwiEyuNDcFiN0x+YpjBG0pI/Q/Tj44INoXLDOPsqjQNu4pQhuoXM5ebknP5+fL27uj7cmnBaHlfBk5Y0TipsEKnpbU8V15raRvbU284KI2zv+/7wLMSMKcJQTf7uDd+POWJ2raiErBgVljyXxEOGhXIHE+6+7xcWq0SnS7xcw+tv+0QeMJFWlK9iHtIduSEc3U/dHAZ/tH5JSfZp3GPKAVc1rrbFGwnOKlYJIxgjJbkAdxsiFpvT4mpYSgTXMIVeUou9p8pyoFZJSb3UUAvT17VYSjzHFHF4l/UiuDROY5+LF5GLDzjb45OzCN2AC8YXGCYkJdlM2wzRwzBGPPuGbs6HXLs0L8cnY8whzuM8FZuY8SbBy/nr+5M5JYy5uIZ8W/wG0y1piYXGcbBgAYxzPWqGPfMMDKs9Gm/QK+Frr6zyRlnmjIKOKw+ad/0SISX5ddFwOzuH0/TGZjXJMKwcipc+nQwBY/4gI2kJ4yi8bJD2ghuqGg8UtLTUGGl65M7Wgr/C7CDdYCYt6Zuu65hznVCWOxAWpO+Z9Ka3QtQ1qF7qWgljNKvB+boWXHlZowPZS9YIUpLrNPrZ5c+tlmsDrtP4D7q8SEVaYpjWjYOuE0bxBmyDihvVGIu1VT0wJV0HXDfQdZyBZs42wgE3FlTndf9DpbN4EyKehmk/wPd3uE1lKvmLA2h4D+rT9S8J7vFxTHeXBxtXl2c7UpKvc1w2QrFZLPIYIv1mlom+mIccdrcJwaO/GD3+7CNcxqVYJ5R3EpxWkkqsHVXC1LRzhlENrPNSauSdJCU5Hd0dpmJxGIS4TNWPZFfb4ji525DR5Tkt/P5aeVxti+sBcj+m+w+b5F1hnwWohORs6YzHh8M2Wjka7xv0hlOhuKbKWk4bq2va1U1nO9OgdotiV3Pez7n4ij4kdHmt+MWLK+bJLbq7n8V4dcGLRTlbvLY9bLFV2v+1xJ5Lco8wzQnv123dPpFNjJhW5NP5MIqbeBGGIUzoxugn0hrd6IpJo18Y/uc9I+uKa2Gen5+f/wUAAP//AwBHzZ1MGwYAAA==
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpSUUW/cKBDHv4rFs3EAY2z8Fm1a3SrXy6pd9aq+YWZoUBy8Apw2ivLdT3i3yuXpdC8IjZnhP7/54xcSzCOSkVyfTh+eMOREapL9FhJMKMoUZfzI21HKkXeN0px1SnwnNfG3+ExG0ktrudVIW1RIJbCOTq2zFAA1ZxyY6GSpaX4kMr4Q4xvAJ2+xWdJXjMkvgYzkbx9g+VnuNr6x87JCE5cZ9yFlE2wR89d+d0v/vD4c7w7nUwlTSW48kJEMtpU4IFLltKOSdx3VQ+so6EkLJbQD585pPmSMwcxNgoe3+2HJAbMdRSPahlGhyWtNwGRTJE8m4fH5VFRsiG5KvN7C23Z8IU8YySjq3zDP5a7s7K8e07T6Ga7OazbpIW2rMzYv8ZnU5BSXE8bsceNznRI+TvPz0aSHj+czZZs+/EK7ZoTdsoZMRsJbRWqyAZpnk/0SqovG3ewx5O1jjj4kb/+rVktqcvelOswmuyU+vpvHlzPm/f+g/MnYex+w2t+QkTCOAtoBqRNcUTmAoaZrNVWqVQ651b3gpCa7JWQf1mVN1T5k/BG3lshIPpo54VnfdbT3PqPNayx9flPFV4e4wGpz9TZLzhrWtIyVpDWf1lx9RvARbcbSxDGul3pf36cIJbak3RojhlwdTL6v/jDpnoxEm8Fyo402RlnrsGPoGDCjWA+oQCFIAT1ILUFJzaySZuISTMcnVyKkJlisU53dKmFwTABFzg2Vreup6TpDlbAC5AB66AuTN47V3VzyjB2YRGipRgdUam6olm1Loe1ML5Tre1H4/0Zy8QNnpRjg0/ndbQoUwICgOBWSd1Rqzemgu55O/TDpSQ3Y2aL5FmPA+V+gPnkbl7S4XF0cUr1D93kN5d9RbW756QP9tc3oZrEPGKsyY+NDeSqXsb6+vr7+AwAA//8DAEkVCfaCBAAA
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTwY7cKBD9FYuz8QDG2Pg26tlVWpPstJJRstobpoo0igdaGE8SjfrfV7g7Sia33NCDV/XqveKFBPOEZCS3p9NfzxjyQmqS/QYJJhRlijL+yNtRypF3jdID01r9R2ri7/E7GUkvreVWI21RIZXAOjq1zlIA1JxxYKKTpab5vJDxhRjfAD57i01cPmJafAxkJJ98gPi19Da+sXNcoUlxxn1Ysgm2iPlnv7unb28Pjw+Hy6sFl0JuPJCRDLaVOCBS5bSjkncd1UPrKOhJCyW0A+cuNB8ypmDmZoEvP/tDzAGzHUUj2oZRocm5JmCyKZIns+Dj91NRsVl0V/B6g7fj+EKeMZFR1D/MvJS7sbO/sfHpyQS4cT745UhqckrxhCl73OzYJpxnk30M1bXJbvYYMqnJw4fqMJvsYnp65dGHy+j7P5j8nbFHH7Da35GRMI4C2gGpE1xROYChpms1VapVDrnVveCkJrsYsg9rXJdqHzJ+TptKMpK/zbzgRd9tskef0eY1Fen/qpI1fvN5F6EAjNTkkCKsNlc/7easYU3LyuXDmk9rrt4j+IQ2Y5npMa3X8r9RhBIbabemhCFXB5OP1RuzHMlItBksN9poY5S1DjuGjgEzivWAChSCFNCD1BKU1MwqaSYuwXR8cgUpuku61bZQ0LvJ9SCosb2iEruBGhgstZOVPWNge9e/srV6mAvP2IFJhJZqdECl5oZq2bYU2s70Qrm+FyWOH5ZcE+es+A34fPkamwIFMCAoToXkHZVaczrorqdTP0x6UgN2tmi+xxRw/sWod96muESXq+vCVK+se7+G8r2rbXm++kC/bZHdRfsFU1UiNz6Ubb6mfD6fz/8DAAD//wMAry4kfSUEAAA=
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
https://dc.services.visualstudio.com/v2/track
|
|
||||||
Content-Type:application/x-json-stream
|
|
||||||
Content-Encoding:gzip
|
|
||||||
|
|
||||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPosyXKFE3Y52iCzfxIlmkRW8UZxgTlqkFRTkJjP3vAbUbJO6tF4IY8Jv5HsNXEu0zkoHcnk7vXjDmhdQkh60kmNCUacr4kctBqYG3jTad1Fz8S2oS7vE7GUinnOPOIJWokSpgLR2ldxQADWccmGhV6Wm/LGR4JTY0gC/BYTMvnzEtYY5kIH+HCPPXMtuGxk3zCk2aJ9zHJdvoCpkP+909/ev2cHw4XF4tuBRwE4AMpHdSYY9ItTeeKt621PTSUzCjEVoYD95fYCFmTNFOzQJPv+bDnCNmN4hGyIZRYci5JmCzLZRHu+Dx+6mw2Cy6K/V6K2/X4ZW8YCKDqH+aeWl346Zw87yMa5jg5nJmuzwVlac0nzDlgJsnm8xpsjnMsbpO2k0BYyY1efhUHSab/Zye3xj16aJ//z/kH8v0d9/QrRlhN68xk4FwaUhN3lv3GCJW+zsyEMZRgOyResE1VT1YaltpqNZSe+TOdIKTmuzmmENc53Wp9jHjl7QJIAP5w04LXqjfJvcYMrq8pqLqH1124ZBmWF2ufvnPWcMayVgBrfm05uojQkjoMhZ9x7Re+/0HIrTYQLs1JYy5Otj8WP1pl0cyEGN7x62xxlrtnMeWoWfArGYdoAaNoAR0oIwCrQxzWtmRK7AtH32pkJpgibvaNsxbBcIqR1s7Mqp639PeW0cVWt9p7FCq/o2P1cNUcNb1TCFIatADVYZbapSUFGRrO6F914kSzU9LrulzVgwGfLn8lY2BBugRNKdC8ZYqYzjtTdvRsetHM+oeW1c432OKOP1m1Pvg0rzMPlfX5aneWPdxjeW/V9sifQ2RftsyupvdE6aqZGxDLOt9jfV8Pp9/AAAA//8DAOIvUl42BAAA
|
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpRU0W7cKBT9FYtn4wDGGPwWTVrtKNvNqB11V/t2DdcNioNHgNNG0fz7Cs9U3Tyt9gWha87l3HMOfiMBnpEM5PZ0+vCCISdSk+y3kmBCUaYo40cuh9YMUjRdK3Vv9N+kJv4eX8lAemkttwZpiwqpdKyjYztZ6hwazrhjopOlJ3xLZHgj4BuHL95is6SvGJNfAhnInz645Xu5G3xj52V1TVxm3IeUIdhC5o/97p7+fns4PhwupxKmAm68IwMZx77vrNFUG9FTaRzQUXOgHbTOggCQTlxgPmSMAeYmuadf97slB8x2EI1oG0aFIeeaOMhQKI+Q8Ph6Kiw2ie5Kvd7K23Z4Iy8YySDqn2Je2t3Y2d88p3H1s7u5rBnSU9rWCWxe4iupySkuJ4zZ46bPbUr4PM6vR0hPHy9nyjZ9+IF2zeh2yxoyGQhvNanJJtA8Q/ZLqK4cd7PHkLePOfqQvP2vXi2pycOX6jBDnpb4/M6PLxeZ9/9D5U9gH33Aan9HBsI4CtdqpJPgikrtgELXGqpUqybk1vSCk5rslpB9WJc1VfuQ8VvcRiID+Qhzwgu/22gffUab11jm/EuVXB3i4labq19ectawpmWsgNZ8WnP1GZ2PaDOWIY5xvfb7+h4ilNhAuzVGDLk6QH6sfoP0SAZiQFsOBgyAsnbCjuHEHAPFeofKKXRSuN5JI52ShlklYeTSQcfHqVRITbBEp9rSyiane8UllaM2VI6dpnrkgvLeohiZEqKb3ulYPcwFB1Yzia6lBidHpeFAjWxb6toOeqGmvhcF91OSax44KwI7fLm8u42Bck6jU5wKyTsqjeFUm66nY69HMyqNnS2c7zEGnP8l1Cdv45KWKVfXhFTvpPu8hvLvqLa0fPeB/tg8ulvsE8aqeAw+lKdytfV8Pp//AQAA//8DAMx7OgqCBAAA
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS6Som2G3qOumXsSLtOhtSI5sIVpqQVGbBsb+94DaDRL31psw0DszfOadeSMRDkh6cns8/nLCmBdSkzxuIcGEpkxTxvdc9Yr1TDfMdMoo9g+pyfiIX0lPjPKee4tUokaqAmupk4OnIaDljAcmWlVywstC+jcCYxPwNHps5uUTpmWcI+nJX2MM85dSG8bGT/MamjRP+BCXDNGXZv58uHukf9zu9k+7y18LLkXcjIH0ZECuUbGOatFZqjrrqXVSUCfC0Co+BG/lRTbGjCnC1Czh84/6Yc4Rs+9FI2TDqLDkXJMAGUrLDhbcfz2WLjZE9yVeb+Hts38jJ0ykF/V3mJd0N34ab/J8nPCE0xHSgunGz4cDxEBqckzzEVMeccOyvXSaII9zrK7F7qYRYyY1eXqudhPkYU6Hd6yeLwge/geBEyZHeiJZK7UxqKSUYLUTDIPRXmvhPDAzOIHcI2utMpYbxqUVzMpWm84EYNaTmrxMs4Pp92XjZwVzXWBGaIEKrVBaW89Qdji0BlkArZ3uvA2yM0J1oZNgAbh1aLzVvhjkA/jXMWL1cE96wjiKIDukg+Caqi4AhVZaqrXUA3JvjeCkJndzzGNc53WpHmLGl7TxIz35FaYFL+Ruk38dM/q8pgL1b12K7dIcVp+rHw7grGGNZKyI1nxcc/URw5jQZyx492m95vuPRGixie7WlDDmagf5tfoNltdCBTrPwZanau8HbBkOLDDQzATUQWNQIpigrApaWea1AsdVgJa7oURITbAYrto8Lj3XzCmgILynCnlLXZmwGpzQw6ADBPmOY/U0FR34jikMklocAlWWA7VKShpkC0bowRgx/ITkaj7OCuCAp8u2bh3oEDoMmlOheEuVtZx2tjXUmc5Zpztsfen5EVPE6SdQH0af5mUecnX1bvUO3cc1lotTbT7+Mkb67zaj+9l/xlSVGcMYy4Jdx3quyQFhWRMetoPVv5Fd2a5qv90tWZbYipo8Z0h5PV7DWjZMG3U+n8/fAAAA//8DAIDgDUv1BAAA
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJSFCUK2IPhtFgjTWMk7u5ibxQ5jInIokFRToMi/31BWa6dooe9CaN5fY/hD9SrPaAGLQ+HT0fo44AWKLopxAgTmAhM6JbyhpOGiLwUXFYF+RctkLuDN9SgimtNtQRcgADMDSlxW1iNjQFJCTWElTz1VM8Dan4g5XIDR6ch98NfEAbne9Sgv11v/GuarVyuOz+aPPgO1v0QVa/TMl/Xqzv8ZbnZPmxOWQMMqTh3BjXIAhXASY0FqyXmtdRYtgXDLTO25NQaLYtTmesjhF51+WBeLvONjz1E3bCcFTnBTKL3BTIqqrRyqwbYvh3SFhNFtym+mMLTZ/MDHSGghi3OZJ7a3ejO3eyHdnSduYkqPEO0Qe3h1YcXOKoOLdAh+AOE6GDi5uEpu6xESU5yJhghaIHuld65HrL1bfbQJcBK14SDKbAEazCXVGHJiwKbolQVE7aqmEULdAehh+6q673TwQ/exmymPPswZ+X76PrRj0O27iM8BxVPdZ9VNwBaoM3Ydm7YPYIyb1v/OKZ//dglLKsxBOhjtlFxl/2phh1qkFS1pkoqqZTQ2kJJwBJDlCCVAWEEGM5MZbjkRnBJtOCqpdyokrY2RdACPYzxMMYz/9+vltgGt9+DuWywnTjedCpaH/ZrA3101iVpzhmTobpuQpXNPVedgz5+IBk1iFBgpqgBW0YF5rVRWJWFxEIUwgLVsmL0RJh1z+NPnoi1hhe2rGvRypYSYLaqOalsS4y2hZambKFiFalqqKUmpC05rVupiQFacpPQBW9GHX+1QjEJ9Dj26TqzdYL96nr8XfALI5vgo9e+S4K5Dp7ehgj736m28vuDH1xM+O0s7bcB7n2f/s73P3M2Fy99vMQg3UE2nV5NDeOsUrjgLcNcaIpbVbS4ZIZLw42xJHW/9foFQpYMplw/aXL21MNTtgx65yLoOIY0+Z8J1EnOz+eTufCRf/20XfkAy8NhMUf/OCaSTs3OBvjwrnwbUvrOD/EK8gztCTp7XuzKTgaOp6fKpaAwpgYjKGaclphLSXEtywq3Vd3KVtRQ6otds0cwLoCOU79tGNO0mdnf+XIZorNKxyEdzxevJzvN/pxTfl3ySraf1afhV9LNVpo7UZIs+3R6OCcH/a938/39/f0/AAAA//8DANnE2XQoBgAA
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpSUT2/cNhDFv4rAsyjzn0hRN8Nu0YWbehEv2qA3ijOKiWipBUVtGhj73Qtqt0jcW27CQG/4+Js3fCPRHZH05P50+uWMMS+kJjlsJcGEpkxTxg9c9Yr1TDdc8NYa+zepSXjCb6QnRnnPvUUqUSNVwFo6yNFTALSccWCiVaWn+7yQ/o240ACeg8dmXv7EtIQ5kp78FSLMX8vZLjR+mldo0jzhLi7ZRV/M/LF7eKK/3+8Pz/vrXwsuRdwEID0ZkWtUrKNadJaqznpqBynoIGBsFR/BW3mVhZgxRTc1C3z5fj7MOWL2vWiEbBgVllxqAi67YnlwCx6+nYqLDdFjqddbefvs38gZE+lF/R/Ma7s7P4W7ZR0mPON0cmnBdOfn49FFIDU5pfmEKQfcsJwxDfMSciHqvXFdxzl0zqjWQCdbIQ1IhtAx04IF67TSo/BtO8LQWaNGBYIr0KjUYEhNNnDT5HKYY3Xz/jAFjJnU5Pml2k8uj3M6vkP/ciW6+wmgxTbpiWSt1MagklI6qwfBEIz2WovBO2bGQSD3yFqrjOWGcWkFs7LVpjPgmPWkJh+cfw0Rq90j6QnjKEB2SEfBNVUdOOpaaanWUo/IvTWCk5o8zDGHuM7rUu1ixs9puy/pya9uWvB60/vkX0NGn9dUIHzSJYz7NMPqc/U9AJw1rJGMFdGaT2uuPiKEhD5jwXFI663f/yRCi030sKaEMVd7l1+r39zySnpiXee5s846p70fsWU4MmBOMwOoQSMoAQaUVaCVZV4rN3AFruXDWCqkJljyVm0R93bkfkBBjfGGKguGDsYIKqUyetQOW/aeY/U8FZ3zHVMIklocgSrLHbVKSgqydUbo0Rgx/oDkFhbOCmDA83VZNwcaoEPQnArFW6qs5bSzbbHRDXbQHba+eH7CFHH6AdSH4NO8zGOublmr3qH7uMby4FRb7r6GSP/ZZvQ4+y+YqjJjF2LZr9tYLzU5olvWhMftverfyL4sV3XYni1ZdtiKmrxkl/J6upW1bJg26nK5XP4FAAD//wMA6XvJ6PQEAAA=
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpSUTW/jNhCG/4rAs6mQFEWJuqVOFzWy2RibdFv0NiJHDhGZNCgq2yDIf19QdhBnFz30Joz4zsczL/lCPOyRdOTycPj9CX2ayIokt4QEE4oyRRm/57KTrGOq5IoL3dT/kBVx1/hMOtJIY7jRSCtUSKVlNe2rwVBrUXPGLRO1zDlhN5HuhYArLT45g2WYvmGcXPCkI385b8P3XBtcacYw2zKGETd+SuBNbubLZn1NP19u72+3x1MTTllcOks6MiBXKFlLlWg1la02VPeVoL2wQy35YI2ujjLnE0YPYznZx/f6NiSPyXSiFFXJqNDkdUUsJMgt9zDh/fMhd7Egusrx1RJePrsX8oSRdGL1BvOY7sKM7mI/9bMb7cUYdjvnd+vgB7ebI6RceEUOMRwwJocLnN+ch/j8Oex2OR/5BOOEZEXuMe6dh/H44woHmMd0F+a4kJns43+dIR2BOQWyIgvJcVzKFqdh1qNDn37RnhW+vSu2I6QhxP2HJd0d2W/+B/obMA/OY7G5Ih1hHIWtWqSD4IrK1gKFutJUqUoNyI1uBCcrsg4+OT+HeSo2PuHuRO1Df5fRPLiEJs0xz/S3ymbbxmBnk4r3BXNWsrJiLIvmdJhT8RWti2gS5iHu43zK95NEKLGIPrkRf8GznmNEn4otpIfiD5geSEc0tIaDBg2gjBmwZjgwy0CxxqKyCq0UtrFSS6ukZkZJ6Lm0UPN+yBGyIphNViy+1kPLhDKcQqsZla0aKAAA7YWUEhWzrW4+wC1ux6wD0zKJtqIaB0ul5kC1rCpqqxoaoYamEcMZp5MhOMvUz03454T25KUvR2u/zW7x6XiPlz6VtS1axamQvKZSa05bXTe0b9pe96rF2uTJ1sFP4Q3kN4x9mFzKj8iN824P489H3jdzjdHjeLadG2dimMKQipMtiw/7+jr7/IoVi0W/O0//XYxxFcwjxiIbC5w/W+br6+vrDwAAAP//AwCy3wbSDAUAAA==
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpSTwW7cOAyGX8Xg2XIkWZYt34JJFzvIthm0g+5ib7JIN0IceSDLaYtg3r2QZ4q0e9uLIBAi+f8fqVcI9pmgh9vT6d0LhbRACclvIcmlZlwzLo5C9Yr3vK2kkcK06l8owd/Td+ihVc4JZ4jVpIkp5A0b6tExRDKCC+SyUbmm/bJA/wrWV0gv3lE1L58pLn4O0MPfPuD8Nfe2vnLTvGIV54n2YUk2uCzmw353z/66PRwfDpdXCy05ufIIPYwkNCneMS07w1RnHDNDLdkgcWyUGNGZ+pLmQ6IY7FQt+PTWH+cUKLleVrKuOJMGziWgTTZLHuxCx++nrGJDdJfj5Rberv0rvFCEXpY/YV7K3bjJ3zwvw+onvLmcyS5P2eUpzieKydPGZLM5TTb5ORTXTrvJU0hQwsOn4jDZNM7x+TdQny7+9//D/jF3f/eN3JoId/MaEvQgFIcS3lv36AMV+zvogQuSWHfERik0Ux1aZpvaMK1rPZJwppUCStjNIfmwzutS7EOiL3EzAD38YaeFLtJvo3v0iVxaY3b1j867cIgzri4Vb/wFr3hV86zkYU2nNRUfCX0klyj7O8b1Wu8/KVLLLWm3xkghFQebHos/7fIIPRjbOWGNNdZq50ZqOI0cudW8RdKoCZXEFpVRqJXhTis7CIW2EcOYI1AC5XEX24YNI0ntWs6c05KpztbMGNsy3QwNF5LrljLiN47Fw5TzrOu4IqyZoRGZMsIyo+qaYd3YVuqxbeX4C5Lr9AXPgJFeLn9lU6ARO0ItmFSiYcoYwTrTtGxou8EMuqPGZc33FANNv4B6712cl3lMxXV5it/QfVxD/u/FtkhffWDfthndze6JYpFnbH3I630d6/l8Pv8AAAD//wMAFaeXhjYEAAA=
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACoxUTW/jNhD9KwKvFRWSoihRt9TJokaaxFgbbdHbiBzFbGTKoKhkF0H+e0E52XwsCvQiCENy3ps3b+aJeDggacn58Xj5gD5OJCfRLSHBhKJMUcZ3XLaStawuhJZVzZu/SU7cFX4nLamlMdxopCUqpNKyinZlb6i1qDnjlolKppxwN5H2iYArLD44g8U4/YFhcqMnLfnTeTs+JmxwhRnG2RZhHHDtpwjeJDI369UV/f18s7vdnG5NOKXHhbOkJT1yhZI1VIlGU9loQ3VXCtoJ21eS99bo8vTM+YjBw1BM9v4N347RYzStKERZMCo0ec6JhQiJcgcT7r4fE4tFoosUz5fw8ts+kQcMpBX5q5indGdmcGeHqZvdYM+WL8nJMYxHDNHhosbtNnsjwVnBCqEEYyQn12D2zmO2vshuh1QimIZJtCXV2FsqNQeqZVlSW1ZQC9XXtehJTq4weBzeZb12JozT2MfsReTsA872fHXpoRswYXyBYUKSk/W0jeAtDKPHy29o5njKtQtzOl6NPjo/j/OUrX3EuwAv56/vV3MI6GO2gbjPfoNpT1qioTEcNGgAZUyPFcOeWQaK1RaVVWilsLWVWlolNTNKQselhYp3fYqQnPyaNNzOxuA0vbFZTDIMC4fspU+rwaGPH2QkLWEchS0bpL3gisrGAoWq1FSpUvXIja4Ff4XZQbjDmKzVdF3HjOmE1NyA0FDanpVW9VqIugbZl1UthVIVq8HYuhZc2rJGA2VfskaQnGzCaGcTP7e6XBqwCeM/aGKSirREsapqDHSdUJI3oBuUXMlGaay17IHJ0nTAqwa6jjOomNGNMMCVBtnZqv+h0qW/cx4v3HQc4Ps73KZQRfmLAWh4D/LT9S8BDvg4hvubk42Lm8sdycnX2aeNkK2TRR6dp99UmujreYhutw8IFu31aPFnH2Eal2yZUNmLynBlaSVsT2XVIQWjOOVGQtejlKVNSS9Gc48hSw4D59NU/Uh2u83Og9m7iCbOIfH7a+Fxu802A8R+DIcPm+RdYZ8FKETJWeqMxYfTNlo4KmsbtIpTIXlFpdacNrqqaVc3ne5Ug5VJit3O8TjH7CtaF9DEpeIXLy6Yqz2a+5/FeHXBi0U5S17bnrbYIu3/WmLPOTkgTHPAw7Kt2yey9h7Dgnwxn0Zx7a/dMLgJzejtRFrOpSoaLuQLw/+8J1hTCM2r5+fn538BAAD//wMAUvEfuhsGAAA=
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpRTwW7cIBD9FYuzcQBjbHyLNq26StusmqitesPMuIvqwArjNFG0/17h3ShNb72hB2/mzXvDM/HmHklPLg+Hdw/o00xKktwKCSYUZYoyfsdlL1nP2kpo2bVd84OUxF3jE+lJK63lViOtUSGVwBo61KOlAKg548BEI3NN83Mm/TMxrgJ8cBarMH/FOLvgSU++OQ/hd+5tXGWnsEAVw4RbPyfjbRbzebu5ph8vd3c3u9OrGedMrhyQnozIFUrWUSU6TWWnLdVDLeggYGwkH8Hq+kRzPmH0Zqpm+PXaH0LymGwvKlFXjApNjiUBk0yWPJgZ754OWcVq0VXGyxVej/0zecBIelG+mHkqd2End2HD/b3xcDE67+Y9KckhhgPG5HC1Y51wmkxywRfnJpvJoU+kJDe3xW4yaQzx/o1Ht6fRt/8x+Sdj985jsb0iPWEcBdQd0lFwRWUHhpqm1lSpWo3IrW4FJyXZBJ+cX8IyF1uf8GdcVZKevDfTjCd9l9HuXUKblpilf1c5a3x0aRMgA4yUZBcDLDYVr3ZzVrGqZvnyZkmHJRVfEFxEmzDPdBeXc/l/KEKJlbRZYkSfip1J++KDmfekJ9p0lhtttDHK2hEbhiMDZhRrARUoBCmgBaklKKmZVdIMXIJp+DBmJOvO6RbrQmmllZCtotygolINhnZ1N1A11MoOQ2e5Gt/YWtxMmWdsxyRCTTWOQKXmhmpZ1xTqxrRCjW0rMu/FknPinGW/AR9OX2NVoAA6BMWpkLyhUmtOO920dGi7QQ+qw8ZmzdcYPU5/GfXJ2RjmMKbivDDFG+u+LD5/72Jdnt/O08c1sqtgf2EscuTG+bzN55SPx+PxDwAAAP//AwCD0iScJQQAAA==
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
https://dc.services.visualstudio.com/v2/track
|
||||||
|
Content-Type:application/x-json-stream
|
||||||
|
Content-Encoding:gzip
|
||||||
|
|
||||||
|
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS5Som7FO0IWbepEs0qK3ETmKCcvUgqScGMb+94LaDVKfil4IYsR3+M4zQ72RAM9IBnJ7On14wZATqUn2W0gwoSnTlPEjV4NiA+saYZiUXP9NauLv8ZUMpFPWcmuQStRIlWMtHeVkqXNoOOOOiVaVnPAtkeGNgG8cvniLzZK+Ykx+CWQgf/rglu/lbvCNnZfVNXGZcR9ShmCLmT/2u3v6++3h+HC4nEqYirjxjgxkQq5RsZ5q0RuqemOpGaWgo3BTq/jkrJEXmQ8ZY4C5Se7p1/1uyQGzHUQjZMOoMORcEwcZiuUREh5fT8XFhuiuxOstvG2HN/KCkQyi/gnzku7Gzv7mOY2rn93NZc2QntK2TmDzEl9JTU5xOWHMHjc+tynh8zi/HiE9fbycKdv04QfaNaPbLWvIZCBcdqQmG6B5huyXUF097maPIW8fc/QheftfuQqahy/VYYY8LfH5XT++XDDv/wflT2AffcBqf0cGwjgKJ3ukk+Caqt4BhVYaqrXUE3JrOsFJTXZLyD6sy5qqfcj4LW4lkYF8hDnhxd9ttI8+o81rLHX+pctcHeLiVpurX73krGGNZKyI1nxac/UZnY9oM5YijnG95vv6XiK02ES7NUYMuTpAfqx+g/RIBmKgtxwMGABt7YQtw4k5Bpp1DrXT6JRwnVNGOa0Ms1rByJWDlo9TiZCaYBmdaptWJowcjRIUmHNUKckpADcUOguyR1DSTe84Vg9z0YHtmUInqcHJUWU4UKOkpE620Ak9dZ0oup9IrvPAWQHs8OXy7jYH2rkeneZUKN5SZQynvWk7Onb9aEbdY2uL53uMAed/gfrkbVzSMuXqOiHVO3Sf11D+HdU2Ld99oD+2Ht0t9gljVXoMPpSncm3r+Xw+/wMAAP//AwANlERfggQAAA==
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
39
PlotLine/Controllers/ArchivesController.cs
Normal file
39
PlotLine/Controllers/ArchivesController.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using PlotLine.Services;
|
||||||
|
|
||||||
|
namespace PlotLine.Controllers;
|
||||||
|
|
||||||
|
public sealed class ArchivesController(IArchiveService archives) : Controller
|
||||||
|
{
|
||||||
|
public async Task<IActionResult> Index(int? projectId, string? entityType)
|
||||||
|
{
|
||||||
|
return View(await archives.GetArchivedItemsAsync(projectId, entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Archive(string entityType, int entityId, int? projectId, string? archivedReason)
|
||||||
|
{
|
||||||
|
await archives.ArchiveAsync(entityType, entityId, archivedReason);
|
||||||
|
TempData["ArchiveMessage"] = $"{entityType} archived. You can restore it from Archived Items.";
|
||||||
|
return RedirectToAction(nameof(Index), new { projectId, entityType });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Restore(string entityType, int entityId, int? projectId)
|
||||||
|
{
|
||||||
|
await archives.RestoreAsync(entityType, entityId);
|
||||||
|
TempData["ArchiveMessage"] = $"{entityType} restored.";
|
||||||
|
return RedirectToAction(nameof(Index), new { projectId, entityType });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> DeleteForever(string entityType, int entityId, int? projectId, string? confirmationText)
|
||||||
|
{
|
||||||
|
var result = await archives.DeleteForeverAsync(entityType, entityId, confirmationText ?? string.Empty);
|
||||||
|
TempData[result.Succeeded ? "ArchiveMessage" : "ArchiveError"] = result.Message;
|
||||||
|
return RedirectToAction(nameof(Index), new { projectId, entityType });
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -42,6 +42,7 @@ public sealed class BooksController(IBookService books) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await books.ArchiveAsync(id);
|
await books.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Book archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction("Details", "Projects", new { id = projectId });
|
return RedirectToAction("Details", "Projects", new { id = projectId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public sealed class ChaptersController(IChapterService chapters) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int bookId)
|
public async Task<IActionResult> Archive(int id, int bookId)
|
||||||
{
|
{
|
||||||
await chapters.ArchiveAsync(id);
|
await chapters.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Chapter archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction("Details", "Books", new { id = bookId });
|
return RedirectToAction("Details", "Books", new { id = bookId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,16 @@ public sealed class CharactersController(ICharacterService characters) : Control
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await characters.ArchiveCharacterAsync(id);
|
await characters.ArchiveCharacterAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Character archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> ArchiveRelationship(int id, int characterId)
|
||||||
|
{
|
||||||
|
await characters.ArchiveRelationshipAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Relationship archived. You can restore it from Archived Items.";
|
||||||
|
return RedirectToAction(nameof(Details), new { id = characterId });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public sealed class LocationsController(ILocationService locations) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await locations.ArchiveAsync(id);
|
await locations.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Location archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +77,7 @@ public sealed class LocationsController(ILocationService locations) : Controller
|
|||||||
public async Task<IActionResult> ArchiveRelationship(int id, int returnLocationId)
|
public async Task<IActionResult> ArchiveRelationship(int id, int returnLocationId)
|
||||||
{
|
{
|
||||||
await locations.ArchiveRelationshipAsync(id);
|
await locations.ArchiveRelationshipAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Location relationship archived.";
|
||||||
return RedirectToAction(nameof(Details), new { id = returnLocationId });
|
return RedirectToAction(nameof(Details), new { id = returnLocationId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public sealed class PlotLinesController(IPlotService plots) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await plots.ArchivePlotLineAsync(id);
|
await plots.ArchivePlotLineAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Plot line archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public sealed class PlotThreadsController(IPlotService plots) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await plots.ArchivePlotThreadAsync(id);
|
await plots.ArchivePlotThreadAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Plot thread archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,7 @@ public sealed class ProjectsController(IProjectService projects) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id)
|
public async Task<IActionResult> Archive(int id)
|
||||||
{
|
{
|
||||||
await projects.ArchiveAsync(id);
|
await projects.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Project archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index));
|
return RedirectToAction(nameof(Index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,6 +83,7 @@ public sealed class ScenariosController(IScenarioService scenarios) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await scenarios.ArchiveAsync(id);
|
await scenarios.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Scenario archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,7 @@ public sealed class ScenesController(
|
|||||||
public async Task<IActionResult> Archive(int id, int chapterId)
|
public async Task<IActionResult> Archive(int id, int chapterId)
|
||||||
{
|
{
|
||||||
await scenes.ArchiveAsync(id);
|
await scenes.ArchiveAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Scene archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction("Details", "Chapters", new { id = chapterId });
|
return RedirectToAction("Details", "Chapters", new { id = chapterId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +274,14 @@ public sealed class ScenesController(
|
|||||||
return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID);
|
return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> DeleteCharacterKnowledge(int id, int sceneId, int? projectId, int? bookId)
|
||||||
|
{
|
||||||
|
await characters.DeleteKnowledgeAsync(id);
|
||||||
|
return RedirectForScene(sceneId, projectId, bookId);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> AddRelationshipEvent(RelationshipEventCreateViewModel model)
|
public async Task<IActionResult> AddRelationshipEvent(RelationshipEventCreateViewModel model)
|
||||||
@ -281,6 +290,14 @@ public sealed class ScenesController(
|
|||||||
return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID);
|
return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> DeleteRelationshipEvent(int id, int sceneId, int? projectId, int? bookId)
|
||||||
|
{
|
||||||
|
await characters.DeleteRelationshipEventAsync(id);
|
||||||
|
return RedirectForScene(sceneId, projectId, bookId);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> SaveWorkflow(SceneWorkflowEditViewModel model)
|
public async Task<IActionResult> SaveWorkflow(SceneWorkflowEditViewModel model)
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public sealed class StoryAssetsController(IAssetService assets) : Controller
|
|||||||
public async Task<IActionResult> Archive(int id, int projectId)
|
public async Task<IActionResult> Archive(int id, int projectId)
|
||||||
{
|
{
|
||||||
await assets.ArchiveAssetAsync(id);
|
await assets.ArchiveAssetAsync(id);
|
||||||
|
TempData["ArchiveMessage"] = "Asset archived. You can restore it from Archived Items.";
|
||||||
return RedirectToAction(nameof(Index), new { projectId });
|
return RedirectToAction(nameof(Index), new { projectId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -118,6 +118,7 @@ public interface ICharacterRepository
|
|||||||
Task<IReadOnlyList<CharacterKnowledgeItem>> ListKnowledgeBySceneAsync(int sceneId);
|
Task<IReadOnlyList<CharacterKnowledgeItem>> ListKnowledgeBySceneAsync(int sceneId);
|
||||||
Task<IReadOnlyList<CharacterKnowledgeItem>> ListKnowledgeByCharacterAsync(int characterId);
|
Task<IReadOnlyList<CharacterKnowledgeItem>> ListKnowledgeByCharacterAsync(int characterId);
|
||||||
Task<int> SaveKnowledgeAsync(CharacterKnowledgeItem knowledge);
|
Task<int> SaveKnowledgeAsync(CharacterKnowledgeItem knowledge);
|
||||||
|
Task DeleteKnowledgeAsync(int characterKnowledgeId);
|
||||||
Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByProjectAsync(int projectId);
|
Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByProjectAsync(int projectId);
|
||||||
Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByCharacterAsync(int characterId);
|
Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByCharacterAsync(int characterId);
|
||||||
Task<int> SaveRelationshipAsync(CharacterRelationship relationship);
|
Task<int> SaveRelationshipAsync(CharacterRelationship relationship);
|
||||||
@ -125,6 +126,7 @@ public interface ICharacterRepository
|
|||||||
Task<IReadOnlyList<RelationshipEvent>> ListRelationshipEventsBySceneAsync(int sceneId);
|
Task<IReadOnlyList<RelationshipEvent>> ListRelationshipEventsBySceneAsync(int sceneId);
|
||||||
Task<IReadOnlyList<RelationshipEvent>> ListRelationshipEventsByCharacterAsync(int characterId);
|
Task<IReadOnlyList<RelationshipEvent>> ListRelationshipEventsByCharacterAsync(int characterId);
|
||||||
Task<int> SaveRelationshipEventAsync(RelationshipEvent relationshipEvent);
|
Task<int> SaveRelationshipEventAsync(RelationshipEvent relationshipEvent);
|
||||||
|
Task DeleteRelationshipEventAsync(int relationshipEventId);
|
||||||
Task<(IReadOnlyList<Character> Characters, IReadOnlyList<SceneCharacter> Appearances)> GetTimelineAsync(int projectId, int? bookId);
|
Task<(IReadOnlyList<Character> Characters, IReadOnlyList<SceneCharacter> Appearances)> GetTimelineAsync(int projectId, int? bookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +248,15 @@ public interface IScenarioRepository
|
|||||||
Task ArchiveAsync(int scenarioId);
|
Task ArchiveAsync(int scenarioId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IArchiveRepository
|
||||||
|
{
|
||||||
|
Task<IReadOnlyList<ArchivedItem>> ListAsync(int? projectId, string? entityType);
|
||||||
|
Task<IReadOnlyList<Project>> ListProjectFiltersAsync();
|
||||||
|
Task ArchiveAsync(string entityType, int entityId, string? reason);
|
||||||
|
Task RestoreAsync(string entityType, int entityId);
|
||||||
|
Task<ArchiveDeleteResult> DeleteForeverAsync(string entityType, int entityId, string confirmationText);
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TimelineData
|
public sealed class TimelineData
|
||||||
{
|
{
|
||||||
public Project? Project { get; init; }
|
public Project? Project { get; init; }
|
||||||
@ -978,6 +989,55 @@ public sealed class ScenarioRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class ArchiveRepository(ISqlConnectionFactory connectionFactory) : IArchiveRepository
|
||||||
|
{
|
||||||
|
public async Task<IReadOnlyList<ArchivedItem>> ListAsync(int? projectId, string? entityType)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
var rows = await connection.QueryAsync<ArchivedItem>(
|
||||||
|
"dbo.Archive_List",
|
||||||
|
new { ProjectID = projectId, EntityType = entityType },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
return rows.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<Project>> ListProjectFiltersAsync()
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
var rows = await connection.QueryAsync<Project>(
|
||||||
|
"dbo.Archive_ProjectFilterList",
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
return rows.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ArchiveAsync(string entityType, int entityId, string? reason)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
await connection.ExecuteAsync(
|
||||||
|
"dbo.Archive_Entity",
|
||||||
|
new { EntityType = entityType, EntityID = entityId, ArchivedReason = reason },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RestoreAsync(string entityType, int entityId)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
await connection.ExecuteAsync(
|
||||||
|
"dbo.Archive_Restore",
|
||||||
|
new { EntityType = entityType, EntityID = entityId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ArchiveDeleteResult> DeleteForeverAsync(string entityType, int entityId, string confirmationText)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
return await connection.QuerySingleAsync<ArchiveDeleteResult>(
|
||||||
|
"dbo.Archive_DeleteForever",
|
||||||
|
new { EntityType = entityType, EntityID = entityId, ConfirmationText = confirmationText },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class SceneDependencyRepository(ISqlConnectionFactory connectionFactory) : ISceneDependencyRepository
|
public sealed class SceneDependencyRepository(ISqlConnectionFactory connectionFactory) : ISceneDependencyRepository
|
||||||
{
|
{
|
||||||
public async Task<SceneDependencyLookupData> GetLookupsAsync()
|
public async Task<SceneDependencyLookupData> GetLookupsAsync()
|
||||||
@ -1843,6 +1903,12 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
commandType: CommandType.StoredProcedure);
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteKnowledgeAsync(int characterKnowledgeId)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
await connection.ExecuteAsync("dbo.CharacterKnowledge_Delete", new { CharacterKnowledgeID = characterKnowledgeId }, commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByProjectAsync(int projectId)
|
public async Task<IReadOnlyList<CharacterRelationship>> ListRelationshipsByProjectAsync(int projectId)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
@ -1916,6 +1982,12 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
commandType: CommandType.StoredProcedure);
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteRelationshipEventAsync(int relationshipEventId)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
await connection.ExecuteAsync("dbo.RelationshipEvent_Delete", new { RelationshipEventID = relationshipEventId }, commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<(IReadOnlyList<Character> Characters, IReadOnlyList<SceneCharacter> Appearances)> GetTimelineAsync(int projectId, int? bookId)
|
public async Task<(IReadOnlyList<Character> Characters, IReadOnlyList<SceneCharacter> Appearances)> GetTimelineAsync(int projectId, int? bookId)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
|
|||||||
@ -1493,6 +1493,26 @@ public sealed class ScenarioComparisonRow
|
|||||||
public bool HasMoved { get; set; }
|
public bool HasMoved { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class ArchivedItem
|
||||||
|
{
|
||||||
|
public string EntityType { get; set; } = string.Empty;
|
||||||
|
public int EntityID { get; set; }
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
public int? ProjectID { get; set; }
|
||||||
|
public string? ProjectName { get; set; }
|
||||||
|
public int? BookID { get; set; }
|
||||||
|
public string? BookTitle { get; set; }
|
||||||
|
public DateTime? ArchivedDate { get; set; }
|
||||||
|
public string? ArchivedReason { get; set; }
|
||||||
|
public DateTime UpdatedDate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ArchiveDeleteResult
|
||||||
|
{
|
||||||
|
public bool Succeeded { get; set; }
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class AnalyticsBusyScene
|
public sealed class AnalyticsBusyScene
|
||||||
{
|
{
|
||||||
public int SceneID { get; set; }
|
public int SceneID { get; set; }
|
||||||
|
|||||||
@ -37,6 +37,7 @@ public class Program
|
|||||||
builder.Services.AddScoped<IExportRepository, ExportRepository>();
|
builder.Services.AddScoped<IExportRepository, ExportRepository>();
|
||||||
builder.Services.AddScoped<IDynamicsRepository, DynamicsRepository>();
|
builder.Services.AddScoped<IDynamicsRepository, DynamicsRepository>();
|
||||||
builder.Services.AddScoped<IScenarioRepository, ScenarioRepository>();
|
builder.Services.AddScoped<IScenarioRepository, ScenarioRepository>();
|
||||||
|
builder.Services.AddScoped<IArchiveRepository, ArchiveRepository>();
|
||||||
builder.Services.AddScoped<IProjectService, ProjectService>();
|
builder.Services.AddScoped<IProjectService, ProjectService>();
|
||||||
builder.Services.AddScoped<IBookService, BookService>();
|
builder.Services.AddScoped<IBookService, BookService>();
|
||||||
builder.Services.AddScoped<IChapterService, ChapterService>();
|
builder.Services.AddScoped<IChapterService, ChapterService>();
|
||||||
@ -53,6 +54,7 @@ public class Program
|
|||||||
builder.Services.AddScoped<IExportService, ExportService>();
|
builder.Services.AddScoped<IExportService, ExportService>();
|
||||||
builder.Services.AddScoped<IDynamicsService, DynamicsService>();
|
builder.Services.AddScoped<IDynamicsService, DynamicsService>();
|
||||||
builder.Services.AddScoped<IScenarioService, ScenarioService>();
|
builder.Services.AddScoped<IScenarioService, ScenarioService>();
|
||||||
|
builder.Services.AddScoped<IArchiveService, ArchiveService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@ -120,12 +120,15 @@ public interface ICharacterService
|
|||||||
Task<CharacterDetailViewModel?> GetCharacterDetailAsync(int characterId);
|
Task<CharacterDetailViewModel?> GetCharacterDetailAsync(int characterId);
|
||||||
Task<int> SaveCharacterAsync(CharacterEditViewModel model);
|
Task<int> SaveCharacterAsync(CharacterEditViewModel model);
|
||||||
Task ArchiveCharacterAsync(int characterId);
|
Task ArchiveCharacterAsync(int characterId);
|
||||||
|
Task ArchiveRelationshipAsync(int characterRelationshipId);
|
||||||
Task<int> AddSceneCharacterAsync(SceneCharacterCreateViewModel model);
|
Task<int> AddSceneCharacterAsync(SceneCharacterCreateViewModel model);
|
||||||
Task<int> UpdateSceneCharacterAsync(SceneCharacterEditViewModel model);
|
Task<int> UpdateSceneCharacterAsync(SceneCharacterEditViewModel model);
|
||||||
Task DeleteSceneCharacterAsync(int sceneCharacterId);
|
Task DeleteSceneCharacterAsync(int sceneCharacterId);
|
||||||
Task<int> AddAttributeEventAsync(CharacterAttributeEventCreateViewModel model);
|
Task<int> AddAttributeEventAsync(CharacterAttributeEventCreateViewModel model);
|
||||||
Task<int> AddKnowledgeAsync(CharacterKnowledgeCreateViewModel model);
|
Task<int> AddKnowledgeAsync(CharacterKnowledgeCreateViewModel model);
|
||||||
|
Task DeleteKnowledgeAsync(int characterKnowledgeId);
|
||||||
Task<int> AddRelationshipEventAsync(RelationshipEventCreateViewModel model);
|
Task<int> AddRelationshipEventAsync(RelationshipEventCreateViewModel model);
|
||||||
|
Task DeleteRelationshipEventAsync(int relationshipEventId);
|
||||||
string DisplayAge(Character character, DateTime? sceneStartDateTime = null);
|
string DisplayAge(Character character, DateTime? sceneStartDateTime = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +203,14 @@ public interface IScenarioService
|
|||||||
Task ArchiveAsync(int scenarioId);
|
Task ArchiveAsync(int scenarioId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IArchiveService
|
||||||
|
{
|
||||||
|
Task<ArchivedItemsViewModel> GetArchivedItemsAsync(int? projectId, string? entityType);
|
||||||
|
Task ArchiveAsync(string entityType, int entityId, string? reason);
|
||||||
|
Task RestoreAsync(string entityType, int entityId);
|
||||||
|
Task<ArchiveDeleteResult> DeleteForeverAsync(string entityType, int entityId, string confirmationText);
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class ProjectService(IProjectRepository projects, IBookRepository books) : IProjectService
|
public sealed class ProjectService(IProjectRepository projects, IBookRepository books) : IProjectService
|
||||||
{
|
{
|
||||||
public Task<IReadOnlyList<Project>> ListAsync() => projects.ListAsync();
|
public Task<IReadOnlyList<Project>> ListAsync() => projects.ListAsync();
|
||||||
@ -2402,6 +2413,50 @@ public sealed class ScenarioService(IProjectRepository projects, IBookRepository
|
|||||||
public Task ArchiveAsync(int scenarioId) => scenarios.ArchiveAsync(scenarioId);
|
public Task ArchiveAsync(int scenarioId) => scenarios.ArchiveAsync(scenarioId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class ArchiveService(IArchiveRepository archives) : IArchiveService
|
||||||
|
{
|
||||||
|
private static readonly (string Value, string Label)[] EntityTypes =
|
||||||
|
[
|
||||||
|
("Project", "Projects"),
|
||||||
|
("Book", "Books"),
|
||||||
|
("Chapter", "Chapters"),
|
||||||
|
("Scene", "Scenes"),
|
||||||
|
("PlotLine", "Plot Lines"),
|
||||||
|
("PlotThread", "Plot Threads"),
|
||||||
|
("StoryAsset", "Story Assets"),
|
||||||
|
("Character", "Characters"),
|
||||||
|
("Location", "Locations"),
|
||||||
|
("Scenario", "Scenarios"),
|
||||||
|
("Relationship", "Relationships")
|
||||||
|
];
|
||||||
|
|
||||||
|
public async Task<ArchivedItemsViewModel> GetArchivedItemsAsync(int? projectId, string? entityType)
|
||||||
|
{
|
||||||
|
var normalisedType = EntityTypes.Any(x => x.Value == entityType) ? entityType : null;
|
||||||
|
var projects = await archives.ListProjectFiltersAsync();
|
||||||
|
return new ArchivedItemsViewModel
|
||||||
|
{
|
||||||
|
ProjectID = projectId,
|
||||||
|
EntityType = normalisedType,
|
||||||
|
ProjectOptions = projects.Select(project => new SelectListItem(
|
||||||
|
project.IsArchived ? $"{project.ProjectName} (Archived)" : project.ProjectName,
|
||||||
|
project.ProjectID.ToString(),
|
||||||
|
project.ProjectID == projectId)).ToList(),
|
||||||
|
EntityTypeOptions = EntityTypes.Select(type => new SelectListItem(type.Label, type.Value, type.Value == normalisedType)).ToList(),
|
||||||
|
Items = await archives.ListAsync(projectId, normalisedType)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ArchiveAsync(string entityType, int entityId, string? reason) =>
|
||||||
|
archives.ArchiveAsync(entityType, entityId, reason);
|
||||||
|
|
||||||
|
public Task RestoreAsync(string entityType, int entityId) =>
|
||||||
|
archives.RestoreAsync(entityType, entityId);
|
||||||
|
|
||||||
|
public Task<ArchiveDeleteResult> DeleteForeverAsync(string entityType, int entityId, string confirmationText) =>
|
||||||
|
archives.DeleteForeverAsync(entityType, entityId, confirmationText);
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class AssetService(IProjectRepository projects, IAssetRepository assets, ILocationRepository locations) : IAssetService
|
public sealed class AssetService(IProjectRepository projects, IAssetRepository assets, ILocationRepository locations) : IAssetService
|
||||||
{
|
{
|
||||||
public async Task<StoryAssetListViewModel?> GetAssetsAsync(int projectId)
|
public async Task<StoryAssetListViewModel?> GetAssetsAsync(int projectId)
|
||||||
@ -2828,6 +2883,8 @@ public sealed class CharacterService(IProjectRepository projects, ICharacterRepo
|
|||||||
|
|
||||||
public Task ArchiveCharacterAsync(int characterId) => characters.ArchiveCharacterAsync(characterId);
|
public Task ArchiveCharacterAsync(int characterId) => characters.ArchiveCharacterAsync(characterId);
|
||||||
|
|
||||||
|
public Task ArchiveRelationshipAsync(int characterRelationshipId) => characters.ArchiveRelationshipAsync(characterRelationshipId);
|
||||||
|
|
||||||
public async Task<int> AddSceneCharacterAsync(SceneCharacterCreateViewModel model)
|
public async Task<int> AddSceneCharacterAsync(SceneCharacterCreateViewModel model)
|
||||||
{
|
{
|
||||||
var characterId = model.CharacterID.GetValueOrDefault();
|
var characterId = model.CharacterID.GetValueOrDefault();
|
||||||
@ -2900,6 +2957,8 @@ public sealed class CharacterService(IProjectRepository projects, ICharacterRepo
|
|||||||
Description = model.Description
|
Description = model.Description
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public Task DeleteKnowledgeAsync(int characterKnowledgeId) => characters.DeleteKnowledgeAsync(characterKnowledgeId);
|
||||||
|
|
||||||
public async Task<int> AddRelationshipEventAsync(RelationshipEventCreateViewModel model)
|
public async Task<int> AddRelationshipEventAsync(RelationshipEventCreateViewModel model)
|
||||||
{
|
{
|
||||||
var relationshipId = model.CharacterRelationshipID.GetValueOrDefault();
|
var relationshipId = model.CharacterRelationshipID.GetValueOrDefault();
|
||||||
@ -2931,6 +2990,8 @@ public sealed class CharacterService(IProjectRepository projects, ICharacterRepo
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task DeleteRelationshipEventAsync(int relationshipEventId) => characters.DeleteRelationshipEventAsync(relationshipEventId);
|
||||||
|
|
||||||
public string DisplayAge(Character character, DateTime? sceneStartDateTime = null)
|
public string DisplayAge(Character character, DateTime? sceneStartDateTime = null)
|
||||||
{
|
{
|
||||||
if (character.BirthDate.HasValue && sceneStartDateTime.HasValue)
|
if (character.BirthDate.HasValue && sceneStartDateTime.HasValue)
|
||||||
|
|||||||
444
PlotLine/Sql/020_Phase1T_ArchiveRestore.sql
Normal file
444
PlotLine/Sql/020_Phase1T_ArchiveRestore.sql
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
SET ANSI_NULLS ON;
|
||||||
|
GO
|
||||||
|
SET QUOTED_IDENTIFIER ON;
|
||||||
|
GO
|
||||||
|
|
||||||
|
DECLARE @ArchiveTables TABLE (TableName sysname);
|
||||||
|
INSERT @ArchiveTables (TableName)
|
||||||
|
VALUES
|
||||||
|
(N'Projects'), (N'Books'), (N'Chapters'), (N'Scenes'), (N'PlotLines'), (N'PlotThreads'),
|
||||||
|
(N'StoryAssets'), (N'Characters'), (N'Locations'), (N'Scenarios'), (N'CharacterRelationships');
|
||||||
|
|
||||||
|
DECLARE @TableName sysname;
|
||||||
|
DECLARE @Sql nvarchar(max);
|
||||||
|
DECLARE archive_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT TableName FROM @ArchiveTables;
|
||||||
|
OPEN archive_cursor;
|
||||||
|
FETCH NEXT FROM archive_cursor INTO @TableName;
|
||||||
|
WHILE @@FETCH_STATUS = 0
|
||||||
|
BEGIN
|
||||||
|
IF COL_LENGTH(N'dbo.' + @TableName, N'IsArchived') IS NULL
|
||||||
|
BEGIN
|
||||||
|
SET @Sql = N'ALTER TABLE dbo.' + QUOTENAME(@TableName) + N' ADD IsArchived bit NOT NULL CONSTRAINT ' + QUOTENAME(N'DF_' + @TableName + N'_IsArchived_Phase1T') + N' DEFAULT 0;';
|
||||||
|
EXEC sys.sp_executesql @Sql;
|
||||||
|
END
|
||||||
|
|
||||||
|
IF COL_LENGTH(N'dbo.' + @TableName, N'ArchivedDate') IS NULL
|
||||||
|
BEGIN
|
||||||
|
SET @Sql = N'ALTER TABLE dbo.' + QUOTENAME(@TableName) + N' ADD ArchivedDate datetime2 NULL;';
|
||||||
|
EXEC sys.sp_executesql @Sql;
|
||||||
|
END
|
||||||
|
|
||||||
|
IF COL_LENGTH(N'dbo.' + @TableName, N'ArchivedReason') IS NULL
|
||||||
|
BEGIN
|
||||||
|
SET @Sql = N'ALTER TABLE dbo.' + QUOTENAME(@TableName) + N' ADD ArchivedReason nvarchar(500) NULL;';
|
||||||
|
EXEC sys.sp_executesql @Sql;
|
||||||
|
END
|
||||||
|
|
||||||
|
FETCH NEXT FROM archive_cursor INTO @TableName;
|
||||||
|
END
|
||||||
|
CLOSE archive_cursor;
|
||||||
|
DEALLOCATE archive_cursor;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Archive_List
|
||||||
|
@ProjectID int = NULL,
|
||||||
|
@EntityType nvarchar(80) = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT EntityType, EntityID, DisplayName, ProjectID, ProjectName, BookID, BookTitle, ArchivedDate, ArchivedReason, UpdatedDate
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT N'Project' AS EntityType, p.ProjectID AS EntityID, p.ProjectName AS DisplayName, p.ProjectID, p.ProjectName,
|
||||||
|
CAST(NULL AS int) AS BookID, CAST(NULL AS nvarchar(200)) AS BookTitle, p.ArchivedDate, p.ArchivedReason, p.UpdatedDate
|
||||||
|
FROM dbo.Projects p
|
||||||
|
WHERE p.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Book', b.BookID, b.BookTitle, b.ProjectID, p.ProjectName, b.BookID, b.BookTitle, b.ArchivedDate, b.ArchivedReason, b.UpdatedDate
|
||||||
|
FROM dbo.Books b INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
|
||||||
|
WHERE b.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Chapter', c.ChapterID, CONCAT(N'Ch ', c.ChapterNumber, N': ', c.ChapterTitle), b.ProjectID, p.ProjectName, b.BookID, b.BookTitle, c.ArchivedDate, c.ArchivedReason, c.UpdatedDate
|
||||||
|
FROM dbo.Chapters c INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
|
||||||
|
WHERE c.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Scene', s.SceneID, CONCAT(N'Scene ', s.SceneNumber, N': ', s.SceneTitle), b.ProjectID, p.ProjectName, b.BookID, b.BookTitle, s.ArchivedDate, s.ArchivedReason, s.UpdatedDate
|
||||||
|
FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
|
||||||
|
WHERE s.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'PlotLine', pl.PlotLineID, pl.PlotLineName, pl.ProjectID, p.ProjectName, pl.BookID, b.BookTitle, pl.ArchivedDate, pl.ArchivedReason, pl.UpdatedDate
|
||||||
|
FROM dbo.PlotLines pl INNER JOIN dbo.Projects p ON p.ProjectID = pl.ProjectID LEFT JOIN dbo.Books b ON b.BookID = pl.BookID
|
||||||
|
WHERE pl.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'PlotThread', pt.PlotThreadID, pt.ThreadTitle, pl.ProjectID, p.ProjectName, pl.BookID, b.BookTitle, pt.ArchivedDate, pt.ArchivedReason, pt.UpdatedDate
|
||||||
|
FROM dbo.PlotThreads pt INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID INNER JOIN dbo.Projects p ON p.ProjectID = pl.ProjectID LEFT JOIN dbo.Books b ON b.BookID = pl.BookID
|
||||||
|
WHERE pt.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'StoryAsset', sa.StoryAssetID, sa.AssetName, sa.ProjectID, p.ProjectName, CAST(NULL AS int), CAST(NULL AS nvarchar(200)), sa.ArchivedDate, sa.ArchivedReason, sa.UpdatedDate
|
||||||
|
FROM dbo.StoryAssets sa INNER JOIN dbo.Projects p ON p.ProjectID = sa.ProjectID
|
||||||
|
WHERE sa.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Character', ch.CharacterID, ch.CharacterName, ch.ProjectID, p.ProjectName, CAST(NULL AS int), CAST(NULL AS nvarchar(200)), ch.ArchivedDate, ch.ArchivedReason, ch.UpdatedDate
|
||||||
|
FROM dbo.Characters ch INNER JOIN dbo.Projects p ON p.ProjectID = ch.ProjectID
|
||||||
|
WHERE ch.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Location', l.LocationID, l.LocationName, l.ProjectID, p.ProjectName, CAST(NULL AS int), CAST(NULL AS nvarchar(200)), l.ArchivedDate, l.ArchivedReason, l.UpdatedDate
|
||||||
|
FROM dbo.Locations l INNER JOIN dbo.Projects p ON p.ProjectID = l.ProjectID
|
||||||
|
WHERE l.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Scenario', sc.ScenarioID, sc.ScenarioName, sc.ProjectID, p.ProjectName, sc.BookID, b.BookTitle, sc.ArchivedDate, sc.ArchivedReason, sc.UpdatedDate
|
||||||
|
FROM dbo.Scenarios sc INNER JOIN dbo.Projects p ON p.ProjectID = sc.ProjectID LEFT JOIN dbo.Books b ON b.BookID = sc.BookID
|
||||||
|
WHERE sc.IsArchived = 1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT N'Relationship', cr.CharacterRelationshipID, CONCAT(ca.CharacterName, N' / ', cb.CharacterName), cr.ProjectID, p.ProjectName, CAST(NULL AS int), CAST(NULL AS nvarchar(200)), cr.ArchivedDate, cr.ArchivedReason, cr.UpdatedDate
|
||||||
|
FROM dbo.CharacterRelationships cr INNER JOIN dbo.Projects p ON p.ProjectID = cr.ProjectID INNER JOIN dbo.Characters ca ON ca.CharacterID = cr.CharacterAID INNER JOIN dbo.Characters cb ON cb.CharacterID = cr.CharacterBID
|
||||||
|
WHERE cr.IsArchived = 1
|
||||||
|
) archived
|
||||||
|
WHERE (@ProjectID IS NULL OR archived.ProjectID = @ProjectID)
|
||||||
|
AND (@EntityType IS NULL OR archived.EntityType = @EntityType)
|
||||||
|
ORDER BY ISNULL(ArchivedDate, UpdatedDate) DESC, EntityType, DisplayName;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Archive_Entity
|
||||||
|
@EntityType nvarchar(80),
|
||||||
|
@EntityID int,
|
||||||
|
@ArchivedReason nvarchar(500) = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
IF @EntityType = N'Project' UPDATE dbo.Projects SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ProjectID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Book' UPDATE dbo.Books SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE BookID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Chapter' UPDATE dbo.Chapters SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Scene' UPDATE dbo.Scenes SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'PlotLine' UPDATE dbo.PlotLines SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE PlotLineID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'PlotThread' UPDATE dbo.PlotThreads SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE PlotThreadID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'StoryAsset' UPDATE dbo.StoryAssets SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE StoryAssetID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Character' UPDATE dbo.Characters SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE CharacterID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Location' UPDATE dbo.Locations SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE LocationID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Scenario' UPDATE dbo.Scenarios SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Relationship' UPDATE dbo.CharacterRelationships SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE CharacterRelationshipID = @EntityID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Archive_Restore
|
||||||
|
@EntityType nvarchar(80),
|
||||||
|
@EntityID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
IF @EntityType = N'Project' UPDATE dbo.Projects SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE ProjectID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Book' UPDATE dbo.Books SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE BookID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Chapter' UPDATE dbo.Chapters SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Scene' UPDATE dbo.Scenes SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'PlotLine' UPDATE dbo.PlotLines SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE PlotLineID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'PlotThread' UPDATE dbo.PlotThreads SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE PlotThreadID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'StoryAsset' UPDATE dbo.StoryAssets SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE StoryAssetID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Character' UPDATE dbo.Characters SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE CharacterID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Location' UPDATE dbo.Locations SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE LocationID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Scenario' UPDATE dbo.Scenarios SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @EntityID;
|
||||||
|
ELSE IF @EntityType = N'Relationship' UPDATE dbo.CharacterRelationships SET IsArchived = 0, ArchivedDate = NULL, ArchivedReason = NULL, UpdatedDate = SYSUTCDATETIME() WHERE CharacterRelationshipID = @EntityID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Archive_ProjectFilterList
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT ProjectID, ProjectName, Description, CreatedDate, UpdatedDate, IsArchived
|
||||||
|
FROM dbo.Projects
|
||||||
|
ORDER BY IsArchived, ProjectName;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Archive_DeleteForever
|
||||||
|
@EntityType nvarchar(80),
|
||||||
|
@EntityID int,
|
||||||
|
@ConfirmationText nvarchar(20)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
IF UPPER(LTRIM(RTRIM(ISNULL(@ConfirmationText, N'')))) <> N'DELETE'
|
||||||
|
BEGIN
|
||||||
|
SELECT CAST(0 AS bit) AS Succeeded, N'Type DELETE to permanently delete an archived item.' AS Message;
|
||||||
|
RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
DECLARE @HasLinks bit = 0;
|
||||||
|
DECLARE @IsArchived bit = 0;
|
||||||
|
|
||||||
|
IF @EntityType = N'Project'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Projects WHERE ProjectID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.Books WHERE ProjectID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.PlotLines WHERE ProjectID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.StoryAssets WHERE ProjectID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.Characters WHERE ProjectID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.Locations WHERE ProjectID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.Scenarios WHERE ProjectID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Projects WHERE ProjectID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Book'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Books WHERE BookID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.Chapters WHERE BookID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.PlotLines WHERE BookID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.Scenarios WHERE BookID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Books WHERE BookID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Chapter'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Chapters WHERE ChapterID = @EntityID;
|
||||||
|
IF EXISTS (SELECT 1 FROM dbo.Scenes WHERE ChapterID = @EntityID) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Chapters WHERE ChapterID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Scene'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Scenes WHERE SceneID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.ScenePurposes WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneMetricValues WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.ThreadEvents WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.AssetEvents WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneCharacters WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterKnowledge WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.RelationshipEvents WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneNotes WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneChecklistItems WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneAttachments WHERE SceneID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.ScenarioSceneOrder WHERE SceneID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Scenes WHERE SceneID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'PlotLine'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.PlotLines WHERE PlotLineID = @EntityID;
|
||||||
|
IF EXISTS (SELECT 1 FROM dbo.PlotThreads WHERE PlotLineID = @EntityID) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.PlotLines WHERE PlotLineID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'PlotThread'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.PlotThreads WHERE PlotThreadID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.ThreadEvents WHERE PlotThreadID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterKnowledge WHERE PlotThreadID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.PlotThreads WHERE PlotThreadID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'StoryAsset'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.StoryAssets WHERE StoryAssetID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.AssetEvents WHERE StoryAssetID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.AssetDependencies WHERE SourceAssetID = @EntityID OR TargetAssetID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.AssetCustodyEvents WHERE StoryAssetID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterKnowledge WHERE StoryAssetID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneAssetLocations WHERE StoryAssetID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.StoryAssets WHERE StoryAssetID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Character'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Characters WHERE CharacterID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.SceneCharacters WHERE CharacterID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterAttributeEvents WHERE CharacterID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterKnowledge WHERE CharacterID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.CharacterRelationships WHERE CharacterAID = @EntityID OR CharacterBID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Characters WHERE CharacterID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Location'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Locations WHERE LocationID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.Locations WHERE ParentLocationID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.Scenes WHERE PrimaryLocationID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneCharacters WHERE LocationID = @EntityID OR EntryLocationID = @EntityID OR ExitLocationID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.StoryAssets WHERE CurrentLocationID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.SceneAssetLocations WHERE LocationID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.LocationRelationships WHERE FromLocationID = @EntityID OR ToLocationID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Locations WHERE LocationID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Scenario'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.Scenarios WHERE ScenarioID = @EntityID;
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM dbo.ScenarioSceneOrder WHERE ScenarioID = @EntityID
|
||||||
|
UNION ALL SELECT 1 FROM dbo.ScenarioWarnings WHERE ScenarioID = @EntityID
|
||||||
|
) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.Scenarios WHERE ScenarioID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE IF @EntityType = N'Relationship'
|
||||||
|
BEGIN
|
||||||
|
SELECT @IsArchived = IsArchived FROM dbo.CharacterRelationships WHERE CharacterRelationshipID = @EntityID;
|
||||||
|
IF EXISTS (SELECT 1 FROM dbo.RelationshipEvents WHERE CharacterRelationshipID = @EntityID) SET @HasLinks = 1;
|
||||||
|
IF @IsArchived = 1 AND @HasLinks = 0 DELETE FROM dbo.CharacterRelationships WHERE CharacterRelationshipID = @EntityID;
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
SELECT CAST(0 AS bit) AS Succeeded, N'This archived item type is not supported for permanent delete.' AS Message;
|
||||||
|
RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF ISNULL(@IsArchived, 0) = 0
|
||||||
|
BEGIN
|
||||||
|
SELECT CAST(0 AS bit) AS Succeeded, N'Only archived items can be permanently deleted.' AS Message;
|
||||||
|
RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF @HasLinks = 1
|
||||||
|
BEGIN
|
||||||
|
SELECT CAST(0 AS bit) AS Succeeded, N'This item has linked story data and cannot yet be permanently deleted safely. Leave it archived instead.' AS Message;
|
||||||
|
RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
SELECT CAST(1 AS bit) AS Succeeded, N'Archived item permanently deleted.' AS Message;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Project_Archive @ProjectID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Project', @ProjectID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Book_Archive @BookID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Book', @BookID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Chapter_Archive @ChapterID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Chapter', @ChapterID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Scene_Archive @SceneID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Scene', @SceneID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.PlotLine_Archive @PlotLineID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'PlotLine', @PlotLineID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.PlotThread_Archive @PlotThreadID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'PlotThread', @PlotThreadID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.StoryAsset_Archive @StoryAssetID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'StoryAsset', @StoryAssetID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Character_Archive @CharacterID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Character', @CharacterID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Location_Archive @LocationID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Location', @LocationID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Archive @ScenarioID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Scenario', @ScenarioID, NULL; END;
|
||||||
|
GO
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Relationship_Archive @CharacterRelationshipID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Relationship', @CharacterRelationshipID, NULL; END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.SceneCharacter_ListByScene
|
||||||
|
@SceneID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID,
|
||||||
|
CASE WHEN c.IsArchived = 1 THEN CONCAT(c.CharacterName, N' (archived)') ELSE c.CharacterName END AS CharacterName,
|
||||||
|
c.ShortName, c.BirthDate, c.AgeAtSeriesStart,
|
||||||
|
sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName,
|
||||||
|
sc.AppearanceNotes, sc.OutfitDescription, sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes,
|
||||||
|
sc.CreatedDate, sc.UpdatedDate
|
||||||
|
FROM dbo.SceneCharacters sc
|
||||||
|
INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
|
||||||
|
LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
|
||||||
|
LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
|
||||||
|
WHERE sc.SceneID = @SceneID
|
||||||
|
ORDER BY role.SortOrder, c.CharacterName;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ThreadEvent_ListByScene
|
||||||
|
@SceneID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
SELECT te.ThreadEventID, te.PlotThreadID,
|
||||||
|
CASE WHEN pt.IsArchived = 1 THEN CONCAT(pt.ThreadTitle, N' (archived)') ELSE pt.ThreadTitle END AS ThreadTitle,
|
||||||
|
pt.PlotLineID,
|
||||||
|
CASE WHEN pl.IsArchived = 1 THEN CONCAT(pl.PlotLineName, N' (archived)') ELSE pl.PlotLineName END AS PlotLineName,
|
||||||
|
pl.Colour, te.SceneID, te.EventTypeID, tet.TypeName AS EventTypeName, tet.MarkerText, te.EventTitle,
|
||||||
|
te.EventDescription, te.CreatedDate, te.UpdatedDate
|
||||||
|
FROM dbo.ThreadEvents te
|
||||||
|
INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
|
||||||
|
INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
|
||||||
|
INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
|
||||||
|
WHERE te.SceneID = @SceneID
|
||||||
|
ORDER BY pl.SortOrder, pt.Importance DESC, te.CreatedDate;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.AssetEvent_ListByScene
|
||||||
|
@SceneID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
SELECT ae.AssetEventID, ae.StoryAssetID, sa.ProjectID,
|
||||||
|
CASE WHEN sa.IsArchived = 1 THEN CONCAT(sa.AssetName, N' (archived)') ELSE sa.AssetName END AS AssetName,
|
||||||
|
sa.AssetKindID, ak.KindName,
|
||||||
|
ae.SceneID, ae.AssetEventTypeID, aet.TypeName AS AssetEventTypeName, aet.MarkerText,
|
||||||
|
ae.FromStateID, fs.StateName AS FromStateName, ae.ToStateID, ts.StateName AS ToStateName,
|
||||||
|
ae.EventTitle, ae.EventDescription, ae.CreatedDate, ae.UpdatedDate
|
||||||
|
FROM dbo.AssetEvents ae
|
||||||
|
INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID
|
||||||
|
INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
|
||||||
|
INNER JOIN dbo.AssetEventTypes aet ON aet.AssetEventTypeID = ae.AssetEventTypeID
|
||||||
|
LEFT JOIN dbo.AssetStates fs ON fs.AssetStateID = ae.FromStateID
|
||||||
|
LEFT JOIN dbo.AssetStates ts ON ts.AssetStateID = ae.ToStateID
|
||||||
|
WHERE ae.SceneID = @SceneID
|
||||||
|
ORDER BY sa.AssetName, ae.AssetEventID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.RelationshipEvent_ListByScene
|
||||||
|
@SceneID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
SELECT re.RelationshipEventID, re.CharacterRelationshipID, cr.ProjectID, cr.CharacterAID,
|
||||||
|
CASE WHEN ca.IsArchived = 1 THEN CONCAT(ca.CharacterName, N' (archived)') ELSE ca.CharacterName END AS CharacterAName,
|
||||||
|
cr.CharacterBID,
|
||||||
|
CASE WHEN cb.IsArchived = 1 THEN CONCAT(cb.CharacterName, N' (archived)') ELSE cb.CharacterName END AS CharacterBName,
|
||||||
|
CASE WHEN cr.IsArchived = 1 THEN CONCAT(rt.TypeName, N' (archived)') ELSE rt.TypeName END AS RelationshipTypeName,
|
||||||
|
re.SceneID, re.RelationshipStateID, rs.StateName AS RelationshipStateName, re.Intensity, re.IsKnownToOtherCharacter,
|
||||||
|
re.Description, re.CreatedDate, re.UpdatedDate
|
||||||
|
FROM dbo.RelationshipEvents re
|
||||||
|
INNER JOIN dbo.CharacterRelationships cr ON cr.CharacterRelationshipID = re.CharacterRelationshipID
|
||||||
|
INNER JOIN dbo.Characters ca ON ca.CharacterID = cr.CharacterAID
|
||||||
|
INNER JOIN dbo.Characters cb ON cb.CharacterID = cr.CharacterBID
|
||||||
|
INNER JOIN dbo.RelationshipTypes rt ON rt.RelationshipTypeID = cr.RelationshipTypeID
|
||||||
|
INNER JOIN dbo.RelationshipStates rs ON rs.RelationshipStateID = re.RelationshipStateID
|
||||||
|
WHERE re.SceneID = @SceneID
|
||||||
|
ORDER BY ca.CharacterName, cb.CharacterName;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterKnowledge_Delete
|
||||||
|
@CharacterKnowledgeID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
DELETE FROM dbo.CharacterKnowledge WHERE CharacterKnowledgeID = @CharacterKnowledgeID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.RelationshipEvent_Delete
|
||||||
|
@RelationshipEventID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
DELETE FROM dbo.RelationshipEvents WHERE RelationshipEventID = @RelationshipEventID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
@ -351,6 +351,15 @@ public sealed class ScenarioCompareViewModel
|
|||||||
public IReadOnlyList<ScenarioWarning> ScenarioWarnings { get; set; } = [];
|
public IReadOnlyList<ScenarioWarning> ScenarioWarnings { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class ArchivedItemsViewModel
|
||||||
|
{
|
||||||
|
public int? ProjectID { get; set; }
|
||||||
|
public string? EntityType { get; set; }
|
||||||
|
public IReadOnlyList<SelectListItem> ProjectOptions { get; set; } = [];
|
||||||
|
public IReadOnlyList<SelectListItem> EntityTypeOptions { get; set; } = [];
|
||||||
|
public IReadOnlyList<ArchivedItem> Items { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TimelineViewModel
|
public sealed class TimelineViewModel
|
||||||
{
|
{
|
||||||
public Project Project { get; set; } = new();
|
public Project Project { get; set; } = new();
|
||||||
|
|||||||
91
PlotLine/Views/Archives/Index.cshtml
Normal file
91
PlotLine/Views/Archives/Index.cshtml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
@model ArchivedItemsViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Archived Items";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="page-heading">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Archive</p>
|
||||||
|
<h1>Archived Items</h1>
|
||||||
|
<p class="lead-text">Restore projects, scenes, characters, assets, locations, threads, scenarios, and other archived planning items.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="story-bible-section">
|
||||||
|
<form method="get" class="timeline-filter-grid archive-filter-form">
|
||||||
|
<div>
|
||||||
|
<label class="form-label">Project</label>
|
||||||
|
<select class="form-select form-select-sm" name="projectId" asp-items="Model.ProjectOptions">
|
||||||
|
<option value="">All Projects</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="form-label">Entity type</label>
|
||||||
|
<select class="form-select form-select-sm" name="entityType" asp-items="Model.EntityTypeOptions">
|
||||||
|
<option value="">All archived items</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-filter-actions">
|
||||||
|
<button class="btn btn-outline-primary btn-sm" type="submit">Filter</button>
|
||||||
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Index">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="story-bible-section">
|
||||||
|
<div class="story-bible-section-heading">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Restore</p>
|
||||||
|
<h2>Archived Records</h2>
|
||||||
|
</div>
|
||||||
|
<span class="soft-count">@Model.Items.Count item@(Model.Items.Count == 1 ? "" : "s")</span>
|
||||||
|
</div>
|
||||||
|
@if (!Model.Items.Any())
|
||||||
|
{
|
||||||
|
<p class="muted">No archived items found for this filter.</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="archive-item-list">
|
||||||
|
@foreach (var item in Model.Items)
|
||||||
|
{
|
||||||
|
<article class="archive-item-card">
|
||||||
|
<div>
|
||||||
|
<span class="archived-badge">@item.EntityType</span>
|
||||||
|
<h3>@item.DisplayName</h3>
|
||||||
|
<p class="muted">
|
||||||
|
@if (!string.IsNullOrWhiteSpace(item.ProjectName))
|
||||||
|
{
|
||||||
|
<span>@item.ProjectName</span>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrWhiteSpace(item.BookTitle))
|
||||||
|
{
|
||||||
|
<span> / @item.BookTitle</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<p class="muted">Archived: @(item.ArchivedDate?.ToString("dd MMM yyyy HH:mm") ?? item.UpdatedDate.ToString("dd MMM yyyy HH:mm"))</p>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(item.ArchivedReason))
|
||||||
|
{
|
||||||
|
<p>@item.ArchivedReason</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="archive-actions">
|
||||||
|
<form asp-action="Restore" method="post" data-confirm-message="Restore this @item.EntityType.ToLowerInvariant()? This will return it to active lists and timelines where applicable.">
|
||||||
|
<input type="hidden" name="entityType" value="@item.EntityType" />
|
||||||
|
<input type="hidden" name="entityId" value="@item.EntityID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ProjectID" />
|
||||||
|
<button class="btn btn-outline-primary btn-sm restore-button" type="submit">Restore</button>
|
||||||
|
</form>
|
||||||
|
<form asp-action="DeleteForever" method="post" class="delete-forever-form" data-confirm-message="Permanently delete this @item.EntityType.ToLowerInvariant()? This cannot be undone. Any linked planning data may also be removed or become unavailable. Only continue if you are certain." data-require-delete-text="true">
|
||||||
|
<input type="hidden" name="entityType" value="@item.EntityType" />
|
||||||
|
<input type="hidden" name="entityId" value="@item.EntityID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ProjectID" />
|
||||||
|
<input type="hidden" name="confirmationText" value="" data-delete-confirm-target />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Delete Forever</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</section>
|
||||||
@ -39,6 +39,11 @@
|
|||||||
<a class="btn btn-outline-primary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID">Timeline</a>
|
<a class="btn btn-outline-primary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID">Timeline</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID">Story health</a>
|
<a class="btn btn-outline-primary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID">Story health</a>
|
||||||
<a class="btn btn-primary" asp-controller="Chapters" asp-action="Create" asp-route-bookId="@Model.Book.BookID">Add chapter</a>
|
<a class="btn btn-primary" asp-controller="Chapters" asp-action="Create" asp-route-bookId="@Model.Book.BookID">Add chapter</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this book? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Book.BookID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Book</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -71,6 +76,11 @@
|
|||||||
<td>@chapter.Summary</td>
|
<td>@chapter.Summary</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Chapters" asp-action="Edit" asp-route-id="@chapter.ChapterID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Chapters" asp-action="Edit" asp-route-id="@chapter.ChapterID">Edit</a>
|
||||||
|
<form asp-controller="Chapters" asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this chapter? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@chapter.ChapterID" />
|
||||||
|
<input type="hidden" name="bookId" value="@Model.Book.BookID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,11 @@
|
|||||||
<a class="btn btn-outline-primary" asp-controller="Writer" asp-action="Chapter" asp-route-id="@Model.Chapter.ChapterID">Chapter workflow</a>
|
<a class="btn btn-outline-primary" asp-controller="Writer" asp-action="Chapter" asp-route-id="@Model.Chapter.ChapterID">Chapter workflow</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="ChapterBrief" asp-route-id="@Model.Chapter.ChapterID">Chapter brief</a>
|
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="ChapterBrief" asp-route-id="@Model.Chapter.ChapterID">Chapter brief</a>
|
||||||
<a class="btn btn-primary" asp-controller="Scenes" asp-action="Create" asp-route-chapterId="@Model.Chapter.ChapterID">Add scene</a>
|
<a class="btn btn-primary" asp-controller="Scenes" asp-action="Create" asp-route-chapterId="@Model.Chapter.ChapterID">Add scene</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this chapter? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Chapter.ChapterID" />
|
||||||
|
<input type="hidden" name="bookId" value="@Model.Book.BookID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Chapter</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -94,6 +99,11 @@
|
|||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID" asp-route-selectedSceneId="@scene.SceneID">Open in timeline</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Book.BookID" asp-route-selectedSceneId="@scene.SceneID">Open in timeline</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Scenes" asp-action="Edit" asp-route-id="@scene.SceneID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Scenes" asp-action="Edit" asp-route-id="@scene.SceneID">Edit</a>
|
||||||
|
<form asp-controller="Scenes" asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this scene? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@scene.SceneID" />
|
||||||
|
<input type="hidden" name="chapterId" value="@Model.Chapter.ChapterID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,11 @@
|
|||||||
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="Character" asp-route-id="@Model.Character.CharacterID">Export character</a>
|
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="Character" asp-route-id="@Model.Character.CharacterID">Export character</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Exports" asp-action="Character" asp-route-id="@Model.Character.CharacterID" asp-route-format="markdown">Markdown</a>
|
<a class="btn btn-outline-secondary" asp-controller="Exports" asp-action="Character" asp-route-id="@Model.Character.CharacterID" asp-route-format="markdown">Markdown</a>
|
||||||
<a class="btn btn-outline-primary" asp-action="Edit" asp-route-id="@Model.Character.CharacterID">Edit character</a>
|
<a class="btn btn-outline-primary" asp-action="Edit" asp-route-id="@Model.Character.CharacterID">Edit character</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this character? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Character.CharacterID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Character</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -65,6 +70,11 @@
|
|||||||
<strong>@relationship.CharacterAName -> @relationship.CharacterBName</strong>
|
<strong>@relationship.CharacterAName -> @relationship.CharacterBName</strong>
|
||||||
<span>@relationship.RelationshipTypeName</span>
|
<span>@relationship.RelationshipTypeName</span>
|
||||||
<a asp-controller="Dynamics" asp-action="Relationship" asp-route-id="@relationship.CharacterRelationshipID">Evolution</a>
|
<a asp-controller="Dynamics" asp-action="Relationship" asp-route-id="@relationship.CharacterRelationshipID">Evolution</a>
|
||||||
|
<form asp-action="ArchiveRelationship" method="post" class="archive-button-form" data-confirm-message="Archive this relationship? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@relationship.CharacterRelationshipID" />
|
||||||
|
<input type="hidden" name="characterId" value="@Model.Character.CharacterID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -53,6 +53,11 @@
|
|||||||
<span class="status-pill">Age @character.AgeAtSeriesStart</span>
|
<span class="status-pill">Age @character.AgeAtSeriesStart</span>
|
||||||
}
|
}
|
||||||
<a class="btn btn-outline-secondary btn-sm ms-auto" asp-action="Edit" asp-route-id="@character.CharacterID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm ms-auto" asp-action="Edit" asp-route-id="@character.CharacterID">Edit</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this character? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@character.CharacterID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,11 @@
|
|||||||
<a class="btn btn-outline-secondary" asp-action="Edit" asp-route-id="@Model.Location.LocationID">Edit</a>
|
<a class="btn btn-outline-secondary" asp-action="Edit" asp-route-id="@Model.Location.LocationID">Edit</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-SelectedSceneID="@firstScene?.SceneID" asp-route-FocusType="location" asp-route-FocusID="@Model.Location.LocationID">Back to timeline</a>
|
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-SelectedSceneID="@firstScene?.SceneID" asp-route-FocusType="location" asp-route-FocusID="@Model.Location.LocationID">Back to timeline</a>
|
||||||
<a class="btn btn-outline-primary" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">All locations</a>
|
<a class="btn btn-outline-primary" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">All locations</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this location? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Location.LocationID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Location</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -93,7 +98,7 @@
|
|||||||
}
|
}
|
||||||
<p class="muted">@relationship.Notes</p>
|
<p class="muted">@relationship.Notes</p>
|
||||||
</div>
|
</div>
|
||||||
<form asp-action="ArchiveRelationship" method="post">
|
<form asp-action="ArchiveRelationship" method="post" data-confirm-message="Archive this location relationship? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
<input type="hidden" name="id" value="@relationship.LocationRelationshipID" />
|
<input type="hidden" name="id" value="@relationship.LocationRelationshipID" />
|
||||||
<input type="hidden" name="returnLocationId" value="@Model.Location.LocationID" />
|
<input type="hidden" name="returnLocationId" value="@Model.Location.LocationID" />
|
||||||
<button class="btn btn-outline-secondary btn-sm" type="submit">Archive</button>
|
<button class="btn btn-outline-secondary btn-sm" type="submit">Archive</button>
|
||||||
|
|||||||
@ -79,7 +79,7 @@ else
|
|||||||
</div>
|
</div>
|
||||||
<div class="button-row compact-buttons">
|
<div class="button-row compact-buttons">
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@location.LocationID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@location.LocationID">Edit</a>
|
||||||
<form asp-action="Archive" method="post">
|
<form asp-action="Archive" method="post" data-confirm-message="Archive this location? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
<input type="hidden" name="id" value="@location.LocationID" />
|
<input type="hidden" name="id" value="@location.LocationID" />
|
||||||
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
|||||||
@ -8,7 +8,17 @@
|
|||||||
<p class="eyebrow">@Model.Project?.ProjectName</p>
|
<p class="eyebrow">@Model.Project?.ProjectName</p>
|
||||||
<h1>@ViewData["Title"]</h1>
|
<h1>@ViewData["Title"]</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="button-row">
|
||||||
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Back to plot lines</a>
|
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Back to plot lines</a>
|
||||||
|
@if (Model.PlotLineID > 0)
|
||||||
|
{
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this plot line? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.PlotLineID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Plot Line</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form asp-action="Save" method="post" class="edit-panel">
|
<form asp-action="Save" method="post" class="edit-panel">
|
||||||
|
|||||||
@ -57,6 +57,11 @@
|
|||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-FocusType="plotline" asp-route-FocusID="@plotLine.PlotLineID">Focus</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-FocusType="plotline" asp-route-FocusID="@plotLine.PlotLineID">Focus</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="PlotThreads" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID" asp-route-plotLineId="@plotLine.PlotLineID">Add thread</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="PlotThreads" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID" asp-route-plotLineId="@plotLine.PlotLineID">Add thread</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@plotLine.PlotLineID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@plotLine.PlotLineID">Edit</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this plot line? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@plotLine.PlotLineID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,17 @@
|
|||||||
<p class="eyebrow">@Model.Project?.ProjectName</p>
|
<p class="eyebrow">@Model.Project?.ProjectName</p>
|
||||||
<h1>@ViewData["Title"]</h1>
|
<h1>@ViewData["Title"]</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="button-row">
|
||||||
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Back to plot threads</a>
|
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Back to plot threads</a>
|
||||||
|
@if (Model.PlotThreadID > 0)
|
||||||
|
{
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this plot thread? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.PlotThreadID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Plot Thread</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form asp-action="Save" method="post" class="edit-panel">
|
<form asp-action="Save" method="post" class="edit-panel">
|
||||||
|
|||||||
@ -59,6 +59,11 @@
|
|||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-FocusType="plotthread" asp-route-FocusID="@thread.PlotThreadID">Focus</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-FocusType="plotthread" asp-route-FocusID="@thread.PlotThreadID">Focus</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@thread.PlotThreadID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@thread.PlotThreadID">Edit</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this plot thread? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@thread.PlotThreadID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
<a asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
<a asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
||||||
<a asp-controller="Dynamics" asp-action="Story" asp-route-projectId="@Model.Project.ProjectID">Story dynamics</a>
|
<a asp-controller="Dynamics" asp-action="Story" asp-route-projectId="@Model.Project.ProjectID">Story dynamics</a>
|
||||||
<a asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Warnings</a>
|
<a asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Warnings</a>
|
||||||
|
<a asp-controller="Archives" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Archived Items</a>
|
||||||
<a asp-controller="Characters" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Characters</a>
|
<a asp-controller="Characters" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Characters</a>
|
||||||
<a asp-controller="StoryAssets" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Assets</a>
|
<a asp-controller="StoryAssets" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Assets</a>
|
||||||
<a asp-controller="Locations" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Locations</a>
|
<a asp-controller="Locations" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Locations</a>
|
||||||
@ -51,7 +52,12 @@
|
|||||||
<a class="btn btn-outline-primary" asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Warnings</a>
|
<a class="btn btn-outline-primary" asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Warnings</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
<a class="btn btn-outline-primary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Dynamics" asp-action="Story" asp-route-projectId="@Model.Project.ProjectID">Story dynamics</a>
|
<a class="btn btn-outline-primary" asp-controller="Dynamics" asp-action="Story" asp-route-projectId="@Model.Project.ProjectID">Story dynamics</a>
|
||||||
|
<a class="btn btn-outline-secondary" asp-controller="Archives" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Archived Items</a>
|
||||||
<a class="btn btn-primary" asp-controller="Books" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID">Add book</a>
|
<a class="btn btn-primary" asp-controller="Books" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID">Add book</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this project? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Project</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -82,6 +88,11 @@
|
|||||||
<td>@book.Description</td>
|
<td>@book.Description</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-controller="Books" asp-action="Edit" asp-route-id="@book.BookID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-controller="Books" asp-action="Edit" asp-route-id="@book.BookID">Edit</a>
|
||||||
|
<form asp-controller="Books" asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this book? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@book.BookID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,10 @@ else
|
|||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
<a class="btn btn-outline-primary btn-sm" asp-action="Details" asp-route-id="@project.ProjectID">Open</a>
|
<a class="btn btn-outline-primary btn-sm" asp-action="Details" asp-route-id="@project.ProjectID">Open</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@project.ProjectID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Edit" asp-route-id="@project.ProjectID">Edit</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this project? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
<div class="button-row mt-2">
|
<div class="button-row mt-2">
|
||||||
<a class="btn btn-outline-primary btn-sm" asp-action="Timeline" asp-route-id="@scenario.ScenarioID">Open timeline</a>
|
<a class="btn btn-outline-primary btn-sm" asp-action="Timeline" asp-route-id="@scenario.ScenarioID">Open timeline</a>
|
||||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Compare" asp-route-id="@scenario.ScenarioID">Compare</a>
|
<a class="btn btn-outline-secondary btn-sm" asp-action="Compare" asp-route-id="@scenario.ScenarioID">Compare</a>
|
||||||
<form asp-action="Archive" method="post">
|
<form asp-action="Archive" method="post" data-confirm-message="Archive this scenario? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
<input type="hidden" name="id" value="@scenario.ScenarioID" />
|
<input type="hidden" name="id" value="@scenario.ScenarioID" />
|
||||||
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<button class="btn btn-outline-primary" type="submit">Validate Scenario</button>
|
<button class="btn btn-outline-primary" type="submit">Validate Scenario</button>
|
||||||
</form>
|
</form>
|
||||||
<a class="btn btn-outline-primary" asp-action="Compare" asp-route-id="@Model.Scenario.ScenarioID">Compare</a>
|
<a class="btn btn-outline-primary" asp-action="Compare" asp-route-id="@Model.Scenario.ScenarioID">Compare</a>
|
||||||
<form asp-action="Archive" method="post">
|
<form asp-action="Archive" method="post" data-confirm-message="Archive this scenario? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
<input type="hidden" name="id" value="@Model.Scenario.ScenarioID" />
|
<input type="hidden" name="id" value="@Model.Scenario.ScenarioID" />
|
||||||
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
<button class="btn btn-outline-danger" type="submit">Archive Scenario</button>
|
<button class="btn btn-outline-danger" type="submit">Archive Scenario</button>
|
||||||
|
|||||||
@ -47,6 +47,11 @@
|
|||||||
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="SceneBrief" asp-route-id="@Model.SceneID">Scene brief</a>
|
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="SceneBrief" asp-route-id="@Model.SceneID">Scene brief</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Exports" asp-action="SceneBrief" asp-route-id="@Model.SceneID" asp-route-format="markdown">Markdown</a>
|
<a class="btn btn-outline-secondary" asp-controller="Exports" asp-action="SceneBrief" asp-route-id="@Model.SceneID" asp-route-format="markdown">Markdown</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="WritingSession" asp-route-sceneId="@Model.SceneID">Prepare Writing Session</a>
|
<a class="btn btn-outline-primary" asp-controller="Exports" asp-action="WritingSession" asp-route-sceneId="@Model.SceneID">Prepare Writing Session</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this scene? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.SceneID" />
|
||||||
|
<input type="hidden" name="chapterId" value="@Model.ChapterID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Scene</button>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Chapters" asp-action="Details" asp-route-id="@Model.ChapterID">Back to chapter</a>
|
<a class="btn btn-outline-secondary" asp-controller="Chapters" asp-action="Details" asp-route-id="@Model.ChapterID">Back to chapter</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -224,6 +224,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@if (Model.SceneID > 0)
|
||||||
|
{
|
||||||
|
<form asp-controller="Scenes" asp-action="Archive" method="post" class="inspector-archive-form archive-button-form mt-2" data-confirm-message="Archive this scene? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.SceneID" />
|
||||||
|
<input type="hidden" name="chapterId" value="@Model.ChapterID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive Scene</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
|
||||||
@if (TempData["WriterWorkspaceError"] is string writerWorkspaceError)
|
@if (TempData["WriterWorkspaceError"] is string writerWorkspaceError)
|
||||||
{
|
{
|
||||||
<div class="alert alert-warning">@writerWorkspaceError</div>
|
<div class="alert alert-warning">@writerWorkspaceError</div>
|
||||||
@ -1170,6 +1179,13 @@
|
|||||||
<span class="muted">@(item.AssetName ?? item.ThreadTitle)</span>
|
<span class="muted">@(item.AssetName ?? item.ThreadTitle)</span>
|
||||||
<span class="muted">@item.Description</span>
|
<span class="muted">@item.Description</span>
|
||||||
</div>
|
</div>
|
||||||
|
<form asp-controller="Scenes" asp-action="DeleteCharacterKnowledge" method="post">
|
||||||
|
<input type="hidden" name="id" value="@item.CharacterKnowledgeID" />
|
||||||
|
<input type="hidden" name="sceneId" value="@Model.SceneID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ReturnProjectID" />
|
||||||
|
<input type="hidden" name="bookId" value="@Model.ReturnBookID" />
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" type="submit">Remove</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -1210,6 +1226,13 @@
|
|||||||
<span class="muted">@item.RelationshipStateName / intensity @item.Intensity</span>
|
<span class="muted">@item.RelationshipStateName / intensity @item.Intensity</span>
|
||||||
<span class="muted">@item.Description</span>
|
<span class="muted">@item.Description</span>
|
||||||
</div>
|
</div>
|
||||||
|
<form asp-controller="Scenes" asp-action="DeleteRelationshipEvent" method="post">
|
||||||
|
<input type="hidden" name="id" value="@item.RelationshipEventID" />
|
||||||
|
<input type="hidden" name="sceneId" value="@Model.SceneID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.ReturnProjectID" />
|
||||||
|
<input type="hidden" name="bookId" value="@Model.ReturnBookID" />
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" type="submit">Remove</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -36,10 +36,40 @@
|
|||||||
</header>
|
</header>
|
||||||
<div class="container-fluid plotline-shell @ViewData["ShellClass"]">
|
<div class="container-fluid plotline-shell @ViewData["ShellClass"]">
|
||||||
<main role="main" class="pb-3">
|
<main role="main" class="pb-3">
|
||||||
|
@if (TempData["ArchiveMessage"] is string archiveMessage)
|
||||||
|
{
|
||||||
|
<div class="alert alert-info">@archiveMessage</div>
|
||||||
|
}
|
||||||
|
@if (TempData["ArchiveError"] is string archiveError)
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning">@archiveError</div>
|
||||||
|
}
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="plotlineConfirmModal" tabindex="-1" aria-labelledby="plotlineConfirmModalTitle" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content plotline-confirm-modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="modal-title fs-5" id="plotlineConfirmModalTitle">Confirm action</h2>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cancel"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p id="plotlineConfirmModalMessage" class="mb-0"></p>
|
||||||
|
<div class="delete-confirm-field d-none mt-3" data-delete-confirm-field>
|
||||||
|
<label class="form-label" for="plotlineDeleteConfirmInput">Type DELETE to continue</label>
|
||||||
|
<input class="form-control" id="plotlineDeleteConfirmInput" autocomplete="off" data-delete-confirm-input />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-danger" data-confirm-submit>Confirm</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.9/dist/chart.umd.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.9/dist/chart.umd.min.js"></script>
|
||||||
|
|||||||
@ -36,6 +36,11 @@
|
|||||||
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story assets</a>
|
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story assets</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-SelectedSceneID="@firstSceneId" asp-route-FocusType="asset" asp-route-FocusID="@Model.Asset.StoryAssetID">Back to timeline</a>
|
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-ProjectID="@Model.Project.ProjectID" asp-route-SelectedSceneID="@firstSceneId" asp-route-FocusType="asset" asp-route-FocusID="@Model.Asset.StoryAssetID">Back to timeline</a>
|
||||||
<a class="btn btn-outline-primary" asp-action="Edit" asp-route-id="@Model.Asset.StoryAssetID">Edit asset</a>
|
<a class="btn btn-outline-primary" asp-action="Edit" asp-route-id="@Model.Asset.StoryAssetID">Edit asset</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this asset? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@Model.Asset.StoryAssetID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger" type="submit">Archive Asset</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -78,6 +78,11 @@
|
|||||||
<span class="purpose-chip">Resolved</span>
|
<span class="purpose-chip">Resolved</span>
|
||||||
}
|
}
|
||||||
<a class="btn btn-outline-secondary btn-sm ms-auto" asp-action="Edit" asp-route-id="@asset.StoryAssetID">Edit</a>
|
<a class="btn btn-outline-secondary btn-sm ms-auto" asp-action="Edit" asp-route-id="@asset.StoryAssetID">Edit</a>
|
||||||
|
<form asp-action="Archive" method="post" class="archive-button-form" data-confirm-message="Archive this asset? This will hide it from active lists and timelines, but the data will be kept and can be restored later.">
|
||||||
|
<input type="hidden" name="id" value="@asset.StoryAssetID" />
|
||||||
|
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||||
|
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@
|
|||||||
<a asp-controller="StoryAssets" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Assets</a>
|
<a asp-controller="StoryAssets" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Assets</a>
|
||||||
<a asp-controller="Locations" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Locations</a>
|
<a asp-controller="Locations" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Locations</a>
|
||||||
<a asp-controller="PlotThreads" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Threads</a>
|
<a asp-controller="PlotThreads" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Threads</a>
|
||||||
|
<a asp-controller="Archives" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Archived Items</a>
|
||||||
</nav>
|
</nav>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -75,6 +76,7 @@
|
|||||||
<a class="btn btn-outline-secondary" asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Warnings</a>
|
<a class="btn btn-outline-secondary" asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Warnings</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Story health</a>
|
<a class="btn btn-outline-secondary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Story health</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Scenarios" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Create Scenario</a>
|
<a class="btn btn-outline-primary" asp-controller="Scenarios" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Create Scenario</a>
|
||||||
|
<a class="btn btn-outline-secondary" asp-controller="Archives" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Archived Items</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -121,6 +121,20 @@ a {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-row form,
|
||||||
|
.compact-buttons form,
|
||||||
|
.asset-card-footer form,
|
||||||
|
td.text-end form,
|
||||||
|
form[data-confirm-message] {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.text-end {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.content-grid {
|
.content-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
@ -2936,6 +2950,80 @@ body.dragging-location [data-drag-type="location"] {
|
|||||||
border-color: rgba(163, 61, 61, 0.24);
|
border-color: rgba(163, 61, 61, 0.24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.archive-filter-form {
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-item-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-item-card {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid var(--plotline-line);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-forever-form {
|
||||||
|
display: inline-flex;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-item-card h3 {
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archived-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
border: 1px solid rgba(82, 75, 65, 0.16);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
color: var(--plotline-muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: rgba(247, 245, 240, 0.86);
|
||||||
|
}
|
||||||
|
|
||||||
|
.restore-button {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-button-form {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plotline-confirm-modal .modal-title {
|
||||||
|
color: var(--plotline-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plotline-confirm-modal .modal-body p {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-confirm-field {
|
||||||
|
border: 1px solid rgba(163, 61, 61, 0.22);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(255, 247, 244, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
header,
|
header,
|
||||||
.breadcrumb-trail,
|
.breadcrumb-trail,
|
||||||
|
|||||||
@ -1,3 +1,117 @@
|
|||||||
|
(() => {
|
||||||
|
const modalElement = document.getElementById("plotlineConfirmModal");
|
||||||
|
const modal = modalElement && window.bootstrap ? new bootstrap.Modal(modalElement) : null;
|
||||||
|
const modalTitle = modalElement?.querySelector("#plotlineConfirmModalTitle");
|
||||||
|
const modalMessage = modalElement?.querySelector("#plotlineConfirmModalMessage");
|
||||||
|
const modalSubmit = modalElement?.querySelector("[data-confirm-submit]");
|
||||||
|
const deleteField = modalElement?.querySelector("[data-delete-confirm-field]");
|
||||||
|
const deleteInput = modalElement?.querySelector("[data-delete-confirm-input]");
|
||||||
|
let pendingForm = null;
|
||||||
|
let pendingSubmitter = null;
|
||||||
|
|
||||||
|
const splitMessage = (message) => {
|
||||||
|
const parts = message.split(/\n\s*\n/);
|
||||||
|
return {
|
||||||
|
title: parts.shift()?.trim() || "Confirm action",
|
||||||
|
body: parts.join("\n\n").trim()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetModal = () => {
|
||||||
|
pendingForm = null;
|
||||||
|
pendingSubmitter = null;
|
||||||
|
if (deleteInput) {
|
||||||
|
deleteInput.value = "";
|
||||||
|
}
|
||||||
|
deleteField?.classList.add("d-none");
|
||||||
|
modalSubmit?.removeAttribute("disabled");
|
||||||
|
};
|
||||||
|
|
||||||
|
modalElement?.addEventListener("hidden.bs.modal", resetModal);
|
||||||
|
|
||||||
|
deleteInput?.addEventListener("input", () => {
|
||||||
|
if (pendingForm?.dataset.requireDeleteText === "true" && modalSubmit) {
|
||||||
|
modalSubmit.disabled = deleteInput.value.trim() !== "DELETE";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
modalSubmit?.addEventListener("click", () => {
|
||||||
|
if (!pendingForm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingForm.dataset.requireDeleteText === "true") {
|
||||||
|
const target = pendingForm.querySelector("[data-delete-confirm-target], [name='confirmationText']");
|
||||||
|
if (target) {
|
||||||
|
target.value = deleteInput?.value.trim() || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingForm.dataset.confirmed = "true";
|
||||||
|
modal?.hide();
|
||||||
|
if (pendingForm.requestSubmit && pendingSubmitter) {
|
||||||
|
pendingForm.requestSubmit(pendingSubmitter);
|
||||||
|
} else if (pendingForm.requestSubmit) {
|
||||||
|
pendingForm.requestSubmit();
|
||||||
|
} else {
|
||||||
|
pendingForm.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("submit", (event) => {
|
||||||
|
const form = event.target;
|
||||||
|
if (!(form instanceof HTMLFormElement) || form.dataset.confirmed === "true") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const explicitMessage = form.dataset.confirmMessage;
|
||||||
|
const submitter = event.submitter instanceof HTMLElement ? event.submitter : form.querySelector("button[type='submit']");
|
||||||
|
const buttonText = submitter?.textContent || "";
|
||||||
|
const actionPath = form.getAttribute("action") || "";
|
||||||
|
const restoreAction = /restore/i.test(buttonText) || /\/restore\b/i.test(actionPath);
|
||||||
|
const deleteForeverAction = /delete forever/i.test(buttonText) || /\/deleteforever\b/i.test(actionPath);
|
||||||
|
const archiveAction = !restoreAction && !deleteForeverAction && (/archive/i.test(buttonText) || /\/archive\b/i.test(actionPath));
|
||||||
|
const removeAction = !deleteForeverAction && /(delete|remove)/i.test(buttonText);
|
||||||
|
if (!explicitMessage && !archiveAction && !restoreAction && !removeAction && !deleteForeverAction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = explicitMessage
|
||||||
|
|| (archiveAction
|
||||||
|
? "Archive this item?\n\nThis will hide it from active lists and timelines, but the data will be kept and can be restored later."
|
||||||
|
: restoreAction
|
||||||
|
? "Restore this item?\n\nThis will return it to active lists and timelines where applicable."
|
||||||
|
: deleteForeverAction
|
||||||
|
? "Permanently delete this item?\n\nThis cannot be undone. Any linked planning data may also be removed or become unavailable. Only continue if you are certain."
|
||||||
|
: "Remove this item?\n\nThis removes the link or supporting record. Major story items are archived instead of permanently deleted.");
|
||||||
|
|
||||||
|
if (!modal || !modalElement || !modalTitle || !modalMessage || !modalSubmit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
const content = splitMessage(message);
|
||||||
|
pendingForm = form;
|
||||||
|
pendingSubmitter = submitter;
|
||||||
|
modalTitle.textContent = form.dataset.confirmTitle || content.title;
|
||||||
|
modalMessage.textContent = form.dataset.confirmBody || content.body;
|
||||||
|
modalSubmit.textContent = form.dataset.confirmButtonText || buttonText.trim() || "Confirm";
|
||||||
|
modalSubmit.className = `btn ${form.dataset.confirmButtonClass || (restoreAction ? "btn-primary" : "btn-danger")}`;
|
||||||
|
|
||||||
|
const needsDeleteText = form.dataset.requireDeleteText === "true" || deleteForeverAction;
|
||||||
|
deleteField?.classList.toggle("d-none", !needsDeleteText);
|
||||||
|
if (needsDeleteText && modalSubmit) {
|
||||||
|
modalSubmit.disabled = true;
|
||||||
|
deleteInput?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.show();
|
||||||
|
if (needsDeleteText) {
|
||||||
|
window.setTimeout(() => deleteInput?.focus(), 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
const roots = document.querySelectorAll(".scene-inspector-root");
|
const roots = document.querySelectorAll(".scene-inspector-root");
|
||||||
if (!roots.length) {
|
if (!roots.length) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user