Compare commits

...

638 commits

Author SHA1 Message Date
0802dc5777 use v1 urls (#15)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: AkkomaGang/admin-fe#15
2022-12-14 12:05:59 +00:00
e018d26a5b normalise timeout 2022-11-13 23:15:37 +00:00
6b131e0779 Add options for translation services (#10)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: AkkomaGang/admin-fe#10
2022-08-29 19:36:36 +00:00
6880744463 display proxy correctly (#9)
Reviewed-on: AkkomaGang/admin-fe#9
2022-08-14 23:16:07 +00:00
2e86ce673b bump version 2022-08-12 16:01:58 +01:00
acf4065a75 Merge branch 'user-status-loading' into develop 2022-08-09 02:45:37 +01:00
0bdd146319 fix test 2022-08-09 02:45:10 +01:00
a13ec695f7 Merge pull request 'fix loading of user statuses' (#7) from user-status-loading into develop
Reviewed-on: AkkomaGang/admin-fe#7
2022-08-09 01:34:43 +00:00
2c868a42c6 fix loading of user statuses 2022-08-09 02:32:58 +01:00
fc98eea515 Purge defunct settings (#6)
Reviewed-on: AkkomaGang/admin-fe#6
2022-08-09 01:18:54 +00:00
713a833b00 Merge pull request 'Fix asset settings not loading in Frontend, bump node-sass' (#5) from eris/admin-fe:fix-avatar into develop
Reviewed-on: AkkomaGang/admin-fe#5
2022-08-02 09:22:56 +00:00
4c6d67dde7 Fix asset settings not loading in Frontend 2022-08-01 05:19:10 +00:00
c727ba8b18 Merge pull request 'make branch names consistent' (#3) from build-on-stable into develop
Reviewed-on: AkkomaGang/admin-fe#3
2022-07-15 10:51:00 +00:00
8a555bce21 make branch names consistent 2022-07-15 11:49:58 +01:00
e037713fa3 Merge pull request 'include branch in deploy' (#2) from stable into main
Reviewed-on: AkkomaGang/admin-fe#2
2022-07-15 10:46:48 +00:00
b3ee5a18d1 include branch in deploy 2022-07-15 11:46:02 +01:00
e84e6ce40d Merge pull request 'Purge SSH settings' (#1) from purge-ssh into main
Reviewed-on: AkkomaGang/admin-fe#1
2022-06-27 11:32:56 +00:00
7a815f233d Purge SSH settings 2022-06-27 12:27:46 +01:00
c4e16b1e15 add explanations to rate limit input 2022-06-21 17:09:58 +01:00
eed89a24ad use 16 for release 2022-06-17 14:24:42 +01:00
adf60bdeb1 use node14 2022-06-17 14:12:16 +01:00
f8ce0dee55 ensure always github config 2022-06-17 14:02:15 +01:00
c8b39ed1ef correct github connection 2022-06-17 13:58:47 +01:00
9a8b3b0c13 add woodpecker config 2022-06-17 13:54:54 +01:00
9baa356f56 apply fixes 2022-06-14 19:05:19 +01:00
Haelwenn (lanodan) Monnier
4406dce589
CHANGELOG.md: Release 2.4.0 2021-08-01 08:36:29 +02:00
Haelwenn
a57925fce9 Merge branch 'simplePolicy_reasons_for_instance_specific_policies' into 'develop'
Make MRF and Quarantine work with tuples

See merge request pleroma/admin-fe!187
2021-07-23 03:41:04 +00:00
Ilja
3b7bcea826 Make MRF and Quarantine work with tuples
* I added the keys to normaliser.js
2021-07-23 03:41:03 +00:00
Angelina Filippova
bc5dcfbafb Merge branch 'fix/revert-mod-log' into 'develop'
Revert including links in moderation log messages

Closes #187

See merge request pleroma/admin-fe!204
2021-04-12 22:26:59 +00:00
Angelina Filippova
8b2acaceb5 Revert including links in moderation log messages 2021-04-13 01:18:17 +03:00
Angelina Filippova
b1ce85fd33 Merge branch 'feature/reduce-nav-sidebars' into develop 2021-03-19 20:50:14 +03:00
Angelina Filippova
4d7a07815a Support new menu if BE does not return tabs 2021-03-19 19:48:24 +03:00
Angelina Filippova
1e5f128a56 Merge branch 'feature/install-switch-frontends' into 'develop'
Ability to install frontends

Closes #164

See merge request pleroma/admin-fe!197
2021-03-14 11:58:27 +00:00
Angelina Filippova
a50dc39354 Merge branch 'develop' into 'feature/install-switch-frontends'
# Conflicts:
#   CHANGELOG.md
2021-03-14 11:52:49 +00:00
Angelina Filippova
dfc00d9aa4 Update changelog 2021-03-14 14:49:44 +03:00
Angelina Filippova
ab73b3facb Update styles for mobile 2021-03-14 14:48:04 +03:00
Angelina Filippova
e9bd9444b3 Create component for frontends table, add button loading while frontend is installing 2021-03-14 14:08:59 +03:00
Angelina Filippova
d3929fc008 Merge branch 'develop' into 'feature/reduce-nav-sidebars'
# Conflicts:
#   CHANGELOG.md
2021-03-11 20:25:20 +00:00
Angelina Filippova
87e1ee4e21 Merge branch 'feature/hide-proxy-remote' into 'develop'
Ability to set rules and conditions for rendering settings

See merge request pleroma/admin-fe!190
2021-03-11 20:06:27 +00:00
Angelina Filippova
411606dc69 Merge branch 'develop' into 'feature/hide-proxy-remote'
# Conflicts:
#   CHANGELOG.md
2021-03-11 19:57:05 +00:00
Angelina Filippova
841340caa9 Merge branch 'fix/moderation-log-render' into 'develop'
Fix rendering moderation log messages

See merge request pleroma/admin-fe!199
2021-03-11 19:40:40 +00:00
Angelina Filippova
24af70ff6b Merge branch 'feature/update-invite-token-dialog' into 'develop'
Ability to copy invite link from dialog window

See merge request pleroma/admin-fe!200
2021-03-11 19:40:18 +00:00
Angelina Filippova
b068b74a10 Merge branch 'feature/update-error-pages' into 'develop'
Update 401 and 404 error pages

See merge request pleroma/admin-fe!201
2021-03-11 19:39:17 +00:00
Angelina Filippova
3cdb2d012c Update changelog 2021-03-11 22:32:43 +03:00
Angelina Filippova
9fd486dee2 Update icons on login page 2021-03-11 16:40:08 +03:00
Angelina Filippova
78571918fd Rename Moderation log component 2021-03-11 15:21:47 +03:00
Angelina Filippova
e4a82cee72 Add ability to copy invite link from dialog window 2021-03-11 15:02:01 +03:00
Angelina Filippova
0f295495ed Remove setting font-size for h1 and h2 2021-03-09 01:55:53 +08:00
Angelina Filippova
3377ec883f Remove unused view files 2021-03-09 01:54:36 +08:00
Angelina Filippova
1a268b5912 Remove unused guide view 2021-03-09 01:53:54 +08:00
Angelina Filippova
c8688007a6 Remove unused Dashboard and Documentation views 2021-03-09 01:52:46 +08:00
Angelina Filippova
686bc1d162 Remove unused components 2021-03-09 01:43:00 +08:00
Angelina Filippova
a3f952b346 Redo 404 Error page 2021-03-09 01:38:01 +08:00
Angelina Filippova
14cf2a460c Update 401 Error Page 2021-03-09 01:31:18 +08:00
Angelina Filippova
0087e95141 Remove unused Error log view files 2021-03-09 01:27:58 +08:00
Angelina Filippova
837474f179 Update webpack config to generate render function 2021-03-08 23:57:11 +08:00
Angelina Filippova
259acedd80 Update Relay index page 2021-03-08 20:43:16 +08:00
Angelina Filippova
6fb956adae Remove Relays from the Settings 2021-03-08 19:42:55 +08:00
Angelina Filippova
e3d891612f Add Route for Relays, update icons 2021-03-08 19:35:02 +08:00
Angelina Filippova
73d40d48fb Move styles mixins to views 2021-03-06 00:27:16 +08:00
Angelina Filippova
b3cd4a3d1d Use new endpoint to get list of tabs 2021-03-05 11:22:28 +08:00
Angelina Filippova
6abb32e3e6 Merge branch 'fix/error-on-account-creation' into 'develop'
Fix displaying multiple errors

Closes #159

See merge request pleroma/admin-fe!198
2021-03-01 22:38:25 +00:00
Angelina Filippova
c6169f36f7 Update changelog 2021-03-02 00:30:35 +03:00
Angelina Filippova
6722a9e34a Replace router push with the one that catches errors 2021-03-02 00:23:16 +03:00
Angelina Filippova
5ca76701c2 Fix displaying messages for multiple errors 2021-03-02 00:22:26 +03:00
Angelina Filippova
170079e06e Replace router push with the one that catches errors 2021-02-27 14:24:25 +03:00
Angelina Filippova
56c20277a4 Add validation and installation of an unknown frontend 2021-02-26 19:28:39 +03:00
Angelina Filippova
d7ef98e68b Add form for installing new frontend 2021-02-24 00:35:31 +03:00
Angelina Filippova
4880e55552 Add i18n translations o settings tabs 2021-02-23 23:42:47 +03:00
Angelina Filippova
8d52a897bb Add ability to install one of the available frontends 2021-02-23 23:04:31 +03:00
Angelina Filippova
21976f3828 Add table with available frontends on Frontend settings tab 2021-02-23 22:23:19 +03:00
Angelina Filippova
04d2f4bcca Fetch the list of frontends and save them in state 2021-02-21 18:04:41 +03:00
Angelina Filippova
05555ae6a3 Fix test 2021-02-12 01:15:17 +03:00
Angelina Filippova
db268467a9 Update Changelog 2021-02-11 20:22:08 +03:00
Angelina Filippova
07bc03f2ef Implement scroll to settings submenu when it is opened 2021-02-11 02:02:44 +03:00
Angelina Filippova
51de129b54 Update styles 2021-02-10 23:43:36 +03:00
Angelina Filippova
0e5d35fe6c Fix sidebar menu when it is collapsed 2021-02-10 21:19:27 +03:00
Angelina Filippova
de51323561 Fix search for elements on current route path 2021-02-09 02:26:39 +03:00
Angelina Filippova
5f9789bd24 Fix styles for settings header and add search in mobile version 2021-02-09 01:27:14 +03:00
Angelina Filippova
02f2f0e1f3 Replace router push with the one that catches errors 2021-02-08 01:42:31 +03:00
Angelina Filippova
8c9b5d5972 Replace depricated addRoutes with addRoute 2021-02-08 00:13:41 +03:00
Angelina Filippova
2d27962e16 Fix tests for forming search object 2021-02-07 02:45:55 +03:00
Angelina Filippova
1189095675 Fix tests for settings search 2021-02-07 02:39:36 +03:00
Angelina Filippova
f02ff602b5 Implement search for Relays 2021-02-07 01:15:31 +03:00
Angelina Filippova
6921d905dc Update search on all settings routes 2021-02-07 01:15:09 +03:00
Angelina Filippova
f96b5e0a0b Update settings search process after changing navigation 2021-02-05 18:14:25 +03:00
Angelina Filippova
8b1a60dce2 Move Emoji pack page to Emoji tab inside Settings page 2021-02-04 02:22:44 +03:00
Angelina Filippova
2bd4b90b22 Move Emoji settings to separate Emoji tab 2021-02-04 01:24:07 +03:00
Angelina Filippova
0dbd32ab42 Remove tabs and select navigation from settings index page 2021-01-30 02:38:39 +03:00
Angelina Filippova
e6d1489a9a Rename paths to settings tabs 2021-01-30 02:36:59 +03:00
Angelina Filippova
584c456b43 Refactoring, move merging routes with settings menu items to view file 2021-01-29 00:21:19 +03:00
Angelina Filippova
17f4ac6291 Pass nested settings routes to GenerateRoutes and save them in state 2021-01-28 21:53:35 +03:00
Angelina Filippova
ccaeaf9ee1 Generate routes from tabs that are kept in localStorage 2021-01-27 20:52:10 +03:00
8a39058467 Merge branch 'api/deactivated' into 'develop'
AdminAPI: change from deactivated to is_active

See merge request pleroma/admin-fe!193
2021-01-25 15:36:18 +00:00
Angelina Filippova
18d20efc5f Fetch settings tabs and keep them in local storage 2021-01-25 17:16:14 +03:00
Angelina Filippova
66791289d1 Mock tabs and save them in state 2021-01-25 13:54:46 +03:00
Angelina Filippova
3bb56cea6f Add tests for users filters 2021-01-23 00:21:12 +03:00
Angelina Filippova
3af1869053 Update tests for UsersFilter component, check if module actions are called 2021-01-22 22:22:35 +03:00
Angelina Filippova
3ff2c3ae38 Remove functions that mock filtering users 2021-01-22 22:13:22 +03:00
df0abd99c7 Change user.deactivated field to user.is_active 2021-01-18 15:16:54 -06:00
27db721e39 Merge branch 'api/approval_pending' into 'develop'
AdminAPI: change from approval_pending to is_approved

See merge request pleroma/admin-fe!192
2021-01-18 19:43:18 +00:00
891ec85764 Document breakage 2021-01-18 12:51:27 -06:00
d46869a1c9 Use logical AND not bitwise AND 2021-01-18 12:34:17 -06:00
3df5aebadf AdminAPI: change from approval_pending to is_approved 2021-01-18 12:24:35 -06:00
30b14142c7 Consistent style with pleroma/pleroma changelog for breaking changes 2021-01-18 12:24:01 -06:00
d4c7989f05 Merge branch 'api/confirmation_pending' into 'develop'
AdminAPI: change from confirmation_pending to is_confirmed

See merge request pleroma/admin-fe!191
2021-01-18 17:22:50 +00:00
Angelina Filippova
a8cf3a75ba Add is_confirmed flag to mocked users in tests 2021-01-17 00:58:03 +03:00
a549e5291d Document breakage 2021-01-16 10:48:56 -06:00
61d173549e Fix mocks 2021-01-16 10:36:30 -06:00
4c72ff4625 AdminAPI: change from confirmation_pending to is_confirmed 2021-01-16 10:25:25 -06:00
Angelina Filippova
cc6c8b2b38 Add tests for function that checks if setting follows rules 2020-12-29 00:54:15 +03:00
Angelina Filippova
2aede0f179 Update Changelog 2020-12-28 02:45:48 +03:00
Angelina Filippova
31863b7c49 Add rules for rendering settings. Do not render :proxy_remote setting if :uploader is set to Local 2020-12-28 02:41:37 +03:00
Angelina Filippova
0e36395a3e Merge branch 'fix/get-remote-packs' into 'develop'
Fix for closing emoji packs panels when switching between panels

Closes #152

See merge request pleroma/admin-fe!189
2020-12-23 19:25:40 +00:00
Angelina Filippova
1729460a75 Update Changelog 2020-12-23 22:12:37 +03:00
Angelina Filippova
bb1658c1aa Close collapse items with emoji pack metadata when another collapse item was opened 2020-12-23 22:01:04 +03:00
Angelina Filippova
bcf48997fe Merge branch 'feature/add-prometheus-settings' into 'develop'
Add Pleroma.Web.Endpoint.MetricsExporter settings

Closes #173

See merge request pleroma/admin-fe!186
2020-12-09 21:48:22 +00:00
Angelina Filippova
c506fa5ee5 Add placeholder for ip_whitelist input 2020-12-10 00:41:25 +03:00
Angelina Filippova
05cd0cc712 Remove :fed_sockets settings 2020-12-09 00:50:04 +03:00
Angelina Filippova
aa2b9102c3 Fix parsing value for ip_whitelist setting 2020-12-09 00:35:59 +03:00
Angelina Filippova
f50e787fa9 Add input for settings with type tuple and boolean, wrapping and parsing these settings 2020-12-08 22:22:27 +03:00
Angelina Filippova
add720534d Rename Link Formatter Input 2020-12-06 20:21:01 +03:00
Angelina Filippova
738e51152e Update Changelog 2020-12-05 01:13:24 +03:00
Angelina Filippova
c4c544aed4 Add Pleroma.Web.Endpoint.MetricsExporter settings 2020-12-05 01:11:24 +03:00
Angelina Filippova
f04ded8fa4 Merge branch 'feature/include-usernames-in-reports-modlogs' into 'develop'
Include usernames in all relevant reports actions in Moderation Log

Closes #145

See merge request pleroma/admin-fe!185
2020-12-04 19:06:33 +00:00
Angelina Filippova
ffe03e0d38 Update Changelog 2020-12-04 02:02:52 +03:00
Angelina Filippova
b82ee6ff0b Tablet UI for report show page 2020-12-04 01:54:21 +03:00
Angelina Filippova
c1dfdd3bbe Add mobile UI for single report show page 2020-12-04 01:37:56 +03:00
Angelina Filippova
9913909cfa Fix loading single report page 2020-12-03 23:23:20 +03:00
Angelina Filippova
27a4620dba Remove LogEntryMessage component, move it to Mod Log index page 2020-12-03 02:24:56 +03:00
Angelina Filippova
c9e9775eb1 Render links for reports on mod log page 2020-12-03 01:49:39 +03:00
Angelina Filippova
7cac1c7159 Pass nicknames instead of ids to user links from mod log 2020-12-02 23:42:44 +03:00
Angelina Filippova
c2e80fb063 Process log message to render links to mentioned users 2020-12-02 22:20:13 +03:00
Angelina Filippova
fd351d63c7 Remove code comment leak 2020-11-29 21:57:17 +03:00
Angelina Filippova
f5b4845aa2 Revert "Merge branch 'feature/edit-tags-manually' into 'develop'"
This reverts commit fd9f0542ce17e26fa7459ad816b7b20c003786ef, reversing
changes made to acfe0dd6a3e600eaf0bb2000ccca6202542c9144.
2020-11-29 21:57:17 +03:00
Angelina Filippova
0fda46954e Update Changelog 2020-11-29 21:42:16 +03:00
Angelina Filippova
536e77cdaa Fix editor inputs 2020-11-29 21:42:15 +03:00
Angelina Filippova
efa4b975d3 Add Websocket based federation settings, fix key for PurgeExpiredActivity setting 2020-11-29 21:42:15 +03:00
Angelina Filippova
050134bfbf Add User Backup settings, fix key for Pleroma.Web.Plugs.RemoteIp 2020-11-29 21:42:15 +03:00
Angelina Filippova
6698a99613 Update Changelog 2020-11-29 21:38:24 +03:00
Angelina Filippova
079ef51efd Fix tests 2020-11-29 21:38:24 +03:00
Angelina Filippova
0f9b15148a Update Changelog 2020-11-29 21:38:24 +03:00
Angelina Filippova
d0c9ecf233 Add textarea input for welcome messages 2020-11-29 21:38:24 +03:00
Angelina Filippova
1ab003bb11 Fix tests after refactoring 2020-11-29 21:38:24 +03:00
Angelina Filippova
9e3dc60373 Refactor filters 2020-11-29 21:38:24 +03:00
Angelina Filippova
c4c547c0e5 Update Changelog 2020-11-29 21:37:55 +03:00
Angelina Filippova
fff34e817a Use actor type filters with search query 2020-11-29 21:34:52 +03:00
Angelina Filippova
ff8a68e720 Add more tests for filtering by actor type 2020-11-29 21:34:52 +03:00
Angelina Filippova
cceed3045d Add two new mock users and fix tests 2020-11-29 21:34:52 +03:00
Angelina Filippova
697138d38b Add test for actor type filter 2020-11-29 21:34:52 +03:00
Angelina Filippova
5dc68eed02 Fix sending actor type filters 2020-11-29 21:34:52 +03:00
Angelina Filippova
80eb0259e2 Return layout tests 2020-11-29 21:34:52 +03:00
Angelina Filippova
05b6992dd4 Add actor_type filter 2020-11-29 21:34:52 +03:00
Angelina Filippova
6b58b4f545 Toggle Actor Type Filters 2020-11-29 21:07:48 +03:00
Angelina Filippova
4316028e41 Add filter by actor type to Users Filter Select 2020-11-29 21:07:48 +03:00
Angelina Filippova
58f0c71ee9 Rename need_confirmed -> unconfirmed 2020-11-29 21:07:48 +03:00
Angelina Filippova
28950a8fb8 Add Unconfirmed filter 2020-11-29 21:07:48 +03:00
Angelina Filippova
182543e55f Update Changelog 2020-11-29 21:07:48 +03:00
Angelina Filippova
46e590c932 Fix moderate user dropdown width 2020-11-29 21:07:48 +03:00
Angelina Filippova
a6202e7460 Add dropdown for changing report's state and moderating user 2020-11-29 21:07:48 +03:00
Angelina Filippova
4851642faf Fix styles for report show page 2020-11-29 21:07:48 +03:00
Mary Kate
5bd81b1901 code review cleanup: center chat show view on page and remove unused chat index page 2020-11-29 21:07:48 +03:00
Mary Kate
4cfab828e7 fix maxId on api 2020-11-29 21:07:48 +03:00
MK Fain
c615902cee Apply 6 suggestion(s) to 3 file(s) 2020-11-29 21:07:48 +03:00
Mary Kate
9629862d56 another hotfix on chat moderation 2020-11-29 21:07:48 +03:00
Mary Kate
2b4d407ea6 chat moderation hotfixes 2020-11-29 21:07:48 +03:00
Mary Kate
3350a501ad add tests for chat show 2020-11-29 21:07:48 +03:00
Mary Kate
0ef644c6cb fix existing tests after adding chat moderation 2020-11-29 21:07:48 +03:00
Mary Kate
f59655995e moderate chat mobile styles 2020-11-29 21:07:48 +03:00
Mary Kate
d843d44d13 chat message pagination 2020-11-29 21:07:48 +03:00
Mary Kate
0153bb98e2 chat show style cleanup and basic message moderation functions 2020-11-29 21:07:48 +03:00
Mary Kate
d65c5a1d29 add author data to messages in chat show 2020-11-29 21:07:48 +03:00
Mary Kate
410ae72b9e basic view chat routing and component structure 2020-11-29 21:07:48 +03:00
Mary Kate
c46793cfaa chat preview in user profile chat card 2020-11-29 21:07:48 +03:00
Mary Kate
ffb8f3412c Chats panel on user profile pulls in list of chats 2020-11-29 21:07:48 +03:00
Angelina Filippova
855f8640b2 Extract Report content into a separate component and reuse it in single report component 2020-11-29 21:07:48 +03:00
Angelina Filippova
3f31748e08 Create show page for a single report 2020-11-29 21:07:48 +03:00
Angelina Filippova
ecf790257c Make report ID in moderation log a link to the respective report 2020-11-29 21:07:48 +03:00
Angelina Filippova
6cdd2f42fe Create api function and module action for fetching single report 2020-11-29 21:07:48 +03:00
Angelina Filippova
c64ccc863c Fix tests 2020-11-29 21:07:48 +03:00
Angelina Filippova
fdbd5fdaf8 Iterate over list of tags to render tags menu when moderating users form Reports 2020-11-29 21:07:48 +03:00
Angelina Filippova
5ed0a6f7f4 Iterate over list of tags to render tags moderation in Multiple Users menu 2020-11-29 21:07:48 +03:00
Angelina Filippova
67ebf12a74 Fix styles 2020-11-29 21:07:47 +03:00
Angelina Filippova
b551987afa Add button for enabling MRF TagPolicy 2020-11-29 21:07:47 +03:00
Angelina Filippova
40e402c780 Move tag moderation to a separate column in users table 2020-11-29 21:07:47 +03:00
Angelina Filippova
4a1c7c2841 Fix adding and removing tags after implementing select 2020-11-29 21:07:47 +03:00
Angelina Filippova
3711248435 Update select for tags in moderation dropdown 2020-11-29 21:07:47 +03:00
Angelina Filippova
e81c80fa9b Remove --detectOpenHandles 2020-11-29 21:07:47 +03:00
Angelina Filippova
408b8db9ad Mock api calls in settings tests 2020-11-29 21:07:47 +03:00
Angelina Filippova
4c58b157f5 Add DetectOpenHandles 2020-11-29 21:07:47 +03:00
Angelina Filippova
f25770ad31 Remove tests with depricated setMethods 2020-11-29 21:07:47 +03:00
Angelina Filippova
be6a3781d1 Mock all api functions in mocks for tests 2020-11-29 21:07:47 +03:00
Angelina Filippova
fedb634c48 Mock app, nodeInfo and settings api in tests 2020-11-29 21:07:47 +03:00
Angelina Filippova
4eed4d0138 Update Changelog 2020-11-29 21:07:47 +03:00
Angelina Filippova
1f5e138c9c Remove layout test 2020-11-29 21:07:47 +03:00
Angelina Filippova
c15265ebef Mock fetching instance document in tests 2020-11-29 21:07:47 +03:00
Angelina Filippova
e7f928a090 Mock app api in user show tests 2020-11-29 21:07:47 +03:00
Angelina Filippova
35c08fcc3c Update Changelog 2020-11-29 21:07:47 +03:00
Angelina Filippova
a90dc10818 Allow using underscores and hyphens in new account's usernames 2020-11-29 21:07:47 +03:00
Angelina Filippova
dcfee0f5de Add headers in table that manages emojis 2020-11-29 21:07:47 +03:00
Angelina Filippova
efbd75834f Add pagination component for remote emoji packs 2020-11-29 21:07:47 +03:00
Angelina Filippova
cd74fa18a2 Add warning about emoji packs names 2020-11-29 21:07:47 +03:00
Angelina Filippova
661b828e5c Update Emoji routes 2020-11-29 21:07:47 +03:00
Angelina Filippova
c5e3aa7f5a Encode emoji packs names to support special chars 2020-11-29 21:07:47 +03:00
Angelina Filippova
7fb00e38ff Update Changelog 2020-11-29 21:07:47 +03:00
Angelina Filippova
6d5add9ee3 Update Changelog 2020-11-29 21:07:47 +03:00
Angelina Filippova
b154213b45 Fix link for downloading local pack's archive 2020-11-29 20:59:46 +03:00
Angelina Filippova
f3c28930ea Implement pagination for emoji files from remote packs 2020-11-29 20:59:46 +03:00
Angelina Filippova
462ca3bf4b Update API urls to support special chars in pack names 2020-11-29 20:58:21 +03:00
Angelina Filippova
f0e0047e92 Add test for wrapping settings with type [list, map] 2020-11-29 20:58:21 +03:00
Angelina Filippova
ec739099b6 Add select for managing tags 2020-11-29 20:58:21 +03:00
Angelina Filippova
37b2fb3199 Add api for fetching a list of tags 2020-11-29 20:58:21 +03:00
Angelina Filippova
457264b72c Mock settings api in reports tests 2020-11-29 20:58:21 +03:00
Angelina Filippova
da2c1c5dfd Update vue/test-utils 2020-11-29 20:58:21 +03:00
Angelina Filippova
6fc6c17d96 Update Changelog 2020-11-29 20:58:20 +03:00
Angelina Filippova
665153c903 Add checking if tag policy is enabled in Reports, add ability to enable it 2020-11-29 20:56:16 +03:00
Angelina Filippova
ee34707047 Move actions that manage users from Reports to reports module 2020-11-29 20:56:16 +03:00
Angelina Filippova
0b81053f24 Update action in dropdown, add confirmation when deleting a user 2020-11-29 20:56:16 +03:00
Angelina Filippova
d008cbdfc7 Add new tag to selected user when creating a new tag 2020-11-29 20:56:16 +03:00
Angelina Filippova
36239cd16f Add ability to collapse tags 2020-11-29 20:56:16 +03:00
Angelina Filippova
f7e9e727ac Mock reports in Layout tests 2020-11-29 20:56:16 +03:00
Angelina Filippova
4a1092d2d6 Fix tests 2020-11-29 20:56:16 +03:00
Angelina Filippova
c08b48dcae Update Changelog 2020-11-29 20:56:16 +03:00
Angelina Filippova
f3f7a155d7 Implement search for Instance panel and Terms of Services 2020-11-29 20:56:16 +03:00
Angelina Filippova
d0f73f4222 Update rendering and data flow for Editor on Other tab 2020-11-29 20:54:54 +03:00
Angelina Filippova
cad7ad8360 Update rendering and data flow for Tiptap Editor on Instance tab 2020-11-29 20:54:54 +03:00
Angelina Filippova
bc812751af Fix test after vue-test-utils update 2020-11-29 20:54:54 +03:00
Angelina Filippova
3ac082b4ab Fix rendering editor input for instance panel 2020-11-29 20:54:54 +03:00
Angelina Filippova
208431dd00 Add Terms of Services on Other tab 2020-11-29 20:54:54 +03:00
Angelina Filippova
d414750cd5 Add ability to remove instance panel doc 2020-11-29 20:52:45 +03:00
Angelina Filippova
b1c22da958 Replace fetch with request 2020-11-29 20:52:45 +03:00
Angelina Filippova
7f59ccb050 Fix updating instance docs 2020-11-29 20:52:45 +03:00
Angelina Filippova
8015b3aa3a Add actions for moderating instance document 2020-11-29 20:52:45 +03:00
Angelina Filippova
27f8ac9801 Add EditorInput component on Instance tab 2020-11-29 20:52:45 +03:00
Angelina Filippova
aa8611ba80 Fix issue with multiple versions of prosemirror-model 2020-11-29 20:52:45 +03:00
Angelina Filippova
3d263f621e Add tiptap, create editor input 2020-11-29 20:52:45 +03:00
Angelina Filippova
39c0773300 Add tiptap icons 2020-11-29 20:52:45 +03:00
Angelina Filippova
b039968517 Add api functions for modifying instance docs 2020-11-29 20:52:45 +03:00
Ilja
413e0f5b7f Add installing dependencies to readme
* For both development (running locally) and building we also need to install the dependencies. I added how I did it.
2020-11-29 20:52:45 +03:00
Angelina Filippova
6069a95768 Add tests for fetching media proxy settings, evicting single and multiple urls 2020-11-29 20:52:45 +03:00
Angelina Filippova
e1b9ccdef1 First green test 2020-11-29 20:52:45 +03:00
Angelina Filippova
14a46f7719 Dispatch URL Search when removing and purging urls 2020-11-29 20:52:45 +03:00
Angelina Filippova
b37f91427f Update Changelog 2020-11-29 20:52:45 +03:00
Angelina Filippova
b251f1034d Add ability to enable media proxy and invalidation from Media proxy tab 2020-11-29 20:52:45 +03:00
Angelina Filippova
ac1864c46f Fetch media proxy settings and render form if it's enabled 2020-11-29 20:52:44 +03:00
Angelina Filippova
dd88974338 Fix fetching MRF data in case it's undefined 2020-11-29 20:52:44 +03:00
Angelina Filippova
767322c355 Update Changelog 2020-11-29 20:52:44 +03:00
Angelina Filippova
72ceba63e6 Move :restrict_unauthenticated settings to Instance tab 2020-11-29 20:52:44 +03:00
Angelina Filippova
e3d5d5b625 Add form for creating new tag 2020-11-29 20:52:44 +03:00
Angelina Filippova
2d70096f51 Add dropdown item and dialog window for creating custom tag 2020-11-29 20:52:44 +03:00
Angelina Filippova
8908ecad81 Update Changelog 2020-11-29 20:52:44 +03:00
Angelina Filippova
a0d0d25bfd Add on confirm success message 2020-11-29 20:46:55 +03:00
Angelina Filippova
a99fe3833a Fix moderation dropdown menu width 2020-11-29 20:46:55 +03:00
Angelina Filippova
fc4a48c1d1 Rename tagPolicies to mrfPolicies 2020-11-29 20:46:55 +03:00
Angelina Filippova
2e397f8790 Fix tests by mocking mrfPolicies field in users state 2020-11-29 20:46:54 +03:00
Angelina Filippova
bf5f6beb75 Return config with TagPolicy 2020-11-29 20:46:54 +03:00
Angelina Filippova
9eb5a1b347 Mock fetching and updating settings for users tests 2020-11-29 20:46:54 +03:00
Angelina Filippova
58ba64b87a Add confirmation message for enabling MRF policies from moderation dropdown 2020-11-29 20:46:54 +03:00
Angelina Filippova
92079893fa Add action that enables MRF TagPolicy, update storage of tagPolicies in state 2020-11-29 20:46:54 +03:00
Angelina Filippova
b5a3a29539 Add option to enable TagPolicy from moderation dropdown 2020-11-29 20:46:54 +03:00
Angelina Filippova
9de860eaac Update Multiple users moderation 2020-11-29 20:46:54 +03:00
Angelina Filippova
8b4fe37a60 Disable tags actions in multiple moderation dropdown when TagPolicy is disabled 2020-11-29 20:46:54 +03:00
Angelina Filippova
d19aef2e94 Disable tags actions in moderation dropdown when TagPolicy is disabled 2020-11-29 20:46:54 +03:00
Angelina Filippova
0fa2d2f267 Save tag policy status in state 2020-11-29 20:46:54 +03:00
c18f167a12 Merge branch 'feature/media-preview-proxy' into 'master'
Ability to configure Media Preview Proxy settings

See merge request pleroma/admin-fe!183
2020-11-18 20:37:59 +00:00
Angelina Filippova
4cc4453a74 Update Changelog 2020-11-18 17:56:55 +03:00
Angelina Filippova
27f11164d8 Fix wrapping :icons setting and parsing tuples in settings with key :headers 2020-11-18 17:52:17 +03:00
Angelina Filippova
06fb9178b7 Update keys for PurgeExpiredActivity and RemoteIp settings 2020-11-18 15:14:14 +03:00
Angelina Filippova
08417331ed Add Media Preview Proxy settings 2020-11-18 15:11:33 +03:00
Angelina Filippova
a028748fb7 Merge branch 'feature/fix-remote-emojis' into 'develop'
Update Changelog, small fix for remote emojis

See merge request pleroma/admin-fe!163
2020-08-25 21:26:40 +00:00
Angelina Filippova
c7fdf64d35 Update Changelog 2020-08-26 00:20:32 +03:00
Angelina Filippova
ea26e75e77 Fix setting remote emoji packs 2020-08-26 00:17:37 +03:00
Angelina Filippova
27be3dd0fc Merge branch 'feature/support-preload-settings' into 'develop'
Support preload settings

Closes #150

See merge request pleroma/admin-fe!162
2020-08-24 20:57:05 +00:00
Angelina Filippova
9d318698f4 Update Changelog 2020-08-24 22:50:51 +03:00
Angelina Filippova
aecd05fb94 Add Pleroma.Web.Preload settings on Frontend tab 2020-08-24 22:50:01 +03:00
Angelina Filippova
b4ed2dc869 Merge branch 'feature/allow-setting-actor-type' into 'develop'
Allow setting actor_type field via Admin API.

Closes #114

See merge request pleroma/admin-fe!161
2020-08-23 21:59:08 +00:00
Angelina Filippova
50bd778252 Update Changelog 2020-08-24 00:50:56 +03:00
Angelina Filippova
cd92dfa695 Add test for updating actor_type 2020-08-24 00:31:38 +03:00
Angelina Filippova
2a42c5ed6b Fix tests 2020-08-23 19:37:40 +03:00
Angelina Filippova
d8b3e9e9df Show actor type on user show page and manage it from that page 2020-08-22 03:04:16 +03:00
Angelina Filippova
a55b76208e Add ability to change actor type from moderation dropdown 2020-08-22 01:33:40 +03:00
Angelina Filippova
a5ab8ceb47 Add select for actor type, remove default select styles 2020-08-20 20:29:58 +03:00
Angelina Filippova
3471f888f8 Merge branch 'fix/relays' into 'develop'
Fix Relays

Closes #85

See merge request pleroma/admin-fe!160
2020-08-19 00:10:24 +00:00
Angelina Filippova
75531b3fcd Update Changelog 2020-08-19 03:05:40 +03:00
Angelina Filippova
d2107a7101 Fix mobile UI 2020-08-19 02:56:05 +03:00
Angelina Filippova
0a146aef7f Fix optimistic update when unfollowing a relay 2020-08-19 01:02:56 +03:00
Angelina Filippova
7e72078f29 Fix adding new relay 2020-08-19 00:53:02 +03:00
Angelina Filippova
04c10cf5e6 Fix fetching relays, add Followed Back field 2020-08-19 00:47:07 +03:00
Angelina Filippova
2eb1d2b840 Update relay URL when unfollowing a relay 2020-08-17 23:44:29 +03:00
Angelina Filippova
9c646f859d Merge branch 'patch-1' into 'develop'
Correct pointer events handling on tabbed submenu

See merge request pleroma/admin-fe!157
2020-08-17 19:51:57 +00:00
Lorenzo Ancora
7cea3012cd Disable pointer events on active menu tab and text selection on all menu tabs. 2020-08-15 12:41:00 +00:00
Angelina Filippova
2880cd2ebb Merge branch 'fix/changelog' into 'develop'
Update Changelog for 2.1 release

See merge request pleroma/admin-fe!156
2020-08-14 00:55:24 +00:00
Angelina Filippova
04335524c5 Update Changelog 2020-08-14 03:46:44 +03:00
Angelina Filippova
eb2b2b2e90 Merge branch 'feature/mediaproxy-cache-pagination-and-search' into 'develop'
Mediaproxy cache pagination and search

See merge request pleroma/admin-fe!155
2020-08-14 00:33:47 +00:00
Angelina Filippova
2dc4a93f18 Merge branch 'develop' into 'feature/mediaproxy-cache-pagination-and-search'
# Conflicts:
#   CHANGELOG.md
2020-08-14 00:27:48 +00:00
Angelina Filippova
8dc408c511 Update Changelog 2020-08-14 03:26:05 +03:00
Angelina Filippova
e4ba720a7d Fix width 2020-08-14 03:17:50 +03:00
Angelina Filippova
7638fa71bd Implement Search for MediaproxyCache 2020-08-14 03:06:51 +03:00
Angelina Filippova
997a9a6d47 Add search input 2020-08-13 15:37:25 +03:00
Angelina Filippova
37df2725ac Merge branch 'feature/add-missing-settings' into 'develop'
Add missing settings

Closes #132

See merge request pleroma/admin-fe!151
2020-08-13 11:51:04 +00:00
Angelina Filippova
4405537fe7 Implement pagination for banned MediaProxy URLs 2020-08-12 03:15:59 +03:00
Angelina Filippova
51da64c138 Merge branch 'fix/update-pending-status' into 'develop'
Update usage of `need_approval` status

See merge request pleroma/admin-fe!154
2020-08-11 23:04:26 +00:00
Angelina Filippova
c9ce3cf231 Update function that removes opposite filters to work with need_approval filter 2020-08-10 01:59:00 +03:00
Angelina Filippova
6bf096b4c8 Fix tag display 2020-08-10 00:39:30 +03:00
Angelina Filippova
ab37ebb00b Update confimation messages for rejecting accounts 2020-08-09 15:37:35 +03:00
Angelina Filippova
7815274d17 Create separate table column for registration reason when need_approval filter activated 2020-08-09 03:04:04 +03:00
Angelina Filippova
efee8997f8 Rename need_approval tag 2020-08-09 01:59:14 +03:00
Angelina Filippova
4fff76a531 Merge branch 'fix-mobile-styles' into 'develop'
Fix message box width on the setting tab in mobile-UI

See merge request pleroma/admin-fe!153
2020-08-07 23:46:37 +00:00
Angelina Filippova
1cdf3aa17a Update Changelog 2020-08-07 21:50:07 +03:00
Angelina Filippova
e85d5123a5 Fix rendering settings that have type ['string', 'image'] 2020-08-07 21:01:31 +03:00
Angelina Filippova
28eabbea4a Merge branch 'pending-approvals' into 'develop'
Admin manage pending accounts

See merge request pleroma/admin-fe!147
2020-08-05 22:53:24 +00:00
MK Fain
ea8374adb7 Admin manage pending accounts 2020-08-05 22:53:23 +00:00
Angelina Filippova
8ce0e8073f Fix message box width 2020-08-06 01:11:51 +03:00
Angelina Filippova
39ef13ff7c Merge branch 'tagnames' into 'develop'
Use tag names from TagPolicy, fixes #134

Closes #134

See merge request pleroma/admin-fe!152
2020-08-05 22:02:02 +00:00
Angelina Filippova
996c493f21 Merge branch 'patch-1' into 'develop'
Fix overflowing text in See Documentation button

See merge request pleroma/admin-fe!149
2020-08-05 21:56:09 +00:00
Angelina Filippova
5ceda826f2 Merge branch 'develop' into 'develop'
Prevent accidental deletion of settings from the database

See merge request pleroma/admin-fe!150
2020-08-05 21:54:29 +00:00
Alex Gleason
e0bfc95a00
Use tag names from TagPolicy, fixes #134 2020-08-04 13:47:06 -05:00
Angelina Filippova
b9f1c93f65 Add :frontends settings on Frontend tab 2020-08-04 03:02:32 +03:00
Angelina Filippova
b36676169a Update Changelog 2020-08-04 01:10:13 +03:00
Angelina Filippova
3b4abed18b Fix tests for args setting in Pleroma.Upload.Filter.Mogrify 2020-08-04 00:57:17 +03:00
Angelina Filippova
8e1825ae1a Fix parsing and wrapping tuple values in Args setting inside Pleroma.Upload.Filter.Mogrify 2020-08-03 22:31:53 +03:00
Angelina Filippova
659adbe6d7 Add test for parsing sender setting in :welcome group 2020-08-03 21:41:25 +03:00
Angelina Filippova
3d1087986f Add parsing Sender settings value 2020-08-03 21:12:13 +03:00
Angelina Filippova
54c8c2ddeb Add special input for Sender setting in Welcome setting group 2020-08-02 03:21:39 +03:00
Angelina Filippova
c12d3c0451 Add favicons and welcome messages settings on Instance tab 2020-07-31 23:29:16 +03:00
Angelina Filippova
b60cd76350 Add :restrict_unauthenticated setting on Authentication tab 2020-07-31 20:10:44 +03:00
Angelina Filippova
198ac3e035 Add Pools, Connections pools and Hackney pools settings on Job Queue tab 2020-07-31 19:44:39 +03:00
Angelina Filippova
7f7a1813c9 Add :modules and Pleroma.Web.ApiSpec.CastAndValidate settings 2020-07-31 19:32:21 +03:00
Lorenzo Ancora
54ccd71b91 Prevent accidental deletion of settings from the database by clicking on the Delete Setting buttons labels. 2020-07-31 13:17:38 +00:00
Lorenzo Ancora
dbe0ad7209 Fix overflowing text in See Documentation button. 2020-07-31 12:29:34 +00:00
Angelina Filippova
11da7c9c7f Fix link formatter tab issue 2020-07-30 00:41:09 +03:00
Angelina Filippova
e8e43c236d Merge branch 'feature/apply-filters-on-users-tab' into 'develop'
Apply default 'local' and 'active' filters on users tab

Closes #133

See merge request pleroma/admin-fe!148
2020-07-28 19:21:01 +00:00
Angelina Filippova
a5b74ef396 Update Changelog 2020-07-28 21:34:50 +03:00
Angelina Filippova
b3423fcf85 Fix styles 2020-07-28 21:32:40 +03:00
Angelina Filippova
065efcab7f Enable active and local filters on users tab by default 2020-07-28 21:04:21 +03:00
Angelina Filippova
ca3745e237 Merge branch 'feature/cache-invalidation' into 'develop'
Add ability to evict and ban URLs from the Pleroma MediaProxy cache

Closes #122

See merge request pleroma/admin-fe!142
2020-07-27 22:36:12 +00:00
Angelina Filippova
fdb2b6d257 Merge branch 'develop' into 'feature/cache-invalidation'
# Conflicts:
#   CHANGELOG.md
#   src/views/settings/components/Inputs.vue
#   src/views/settings/components/tabs.js
2020-07-27 22:29:37 +00:00
Angelina Filippova
7a6b9f2e3f Merge branch 'feature/rename-auto-linker' into 'develop'
Move Auto Linker settings to Link Formatter Tab

Closes #131

See merge request pleroma/admin-fe!146
2020-07-27 22:09:36 +00:00
Angelina Filippova
92881ead81 Fix wrapping atoms that should be prepended with colon 2020-07-27 22:42:44 +03:00
Angelina Filippova
bcf958f196 Update Changelog 2020-07-27 21:31:31 +03:00
Angelina Filippova
e5f037dc46 Fix search for Auto Linker 2020-07-27 19:35:21 +03:00
Angelina Filippova
4339a3a961 Add input for new type ['atom', 'boolean'] 2020-07-26 01:26:34 +03:00
Angelina Filippova
b36e8693b5 Remove partial update check 2020-07-26 01:01:31 +03:00
Angelina Filippova
3cc934efdc Rename Auto Linker input to Link Formatter Input 2020-07-25 01:12:27 +03:00
Angelina Filippova
0c80942777 Rename Auto linker to Link Formatter 2020-07-24 23:29:12 +03:00
Angelina Filippova
55eb374d36 Merge branch 'feature/update-mrf' into 'develop'
Show MRF settings that are enabled in MRF Policies setting

Closes #129 and #126

See merge request pleroma/admin-fe!145
2020-07-24 19:29:09 +00:00
Angelina Filippova
edd86b1181 Update Changelog 2020-07-22 17:58:08 +03:00
Angelina Filippova
81177cc96e Show only those MRF settings that are enabled in MRF policies 2020-07-22 17:36:52 +03:00
Angelina Filippova
94e07f1ead Fix shortening MRF policies on the new tab 2020-07-21 13:29:54 +03:00
Angelina Filippova
ea46a819d4 Update Changelog 2020-07-20 21:34:10 +03:00
Angelina Filippova
753c70114e Add tests for wrappint settings with types that includes map 2020-07-20 15:42:43 +03:00
Angelina Filippova
290ca32fd6 Add test for parsing options setting in MediaProxy.Invalidation.Http group 2020-07-20 12:56:01 +03:00
Angelina Filippova
da6df6f018 Add test for parsing crontab setting 2020-07-19 02:06:27 +03:00
Angelina Filippova
370faf5678 Fix settings types in tests 2020-07-19 01:27:55 +03:00
Angelina Filippova
98e5fa5d36 Save Rate limit values as Numbers instead Strings 2020-07-18 23:08:23 +03:00
Angelina Filippova
75b6f027a2 Update parsing and wrapping editable map values 2020-07-18 22:27:10 +03:00
Angelina Filippova
d7eaf61a95 Merge branch 'feature/confirm-delete-user' into 'develop'
Add confirmation message when deleting a user

Closes #125

See merge request pleroma/admin-fe!144
2020-07-17 21:46:20 +00:00
Angelina Filippova
240340ff83 Update confirmation message 2020-07-18 00:28:04 +03:00
Angelina Filippova
c771ab057c Update Changelog 2020-07-18 00:18:06 +03:00
Angelina Filippova
a70a5bb15c Fix tests 2020-07-18 00:13:06 +03:00
Angelina Filippova
d211d4f934 Fix optimistc update for deleting users 2020-07-17 14:15:39 +03:00
Angelina Filippova
434f8ad2dd Do not fetch user profile when deleting multiple accounts 2020-07-17 13:47:50 +03:00
Angelina Filippova
f8dbcb80ab Add confirmation when deleting a single user 2020-07-17 13:45:39 +03:00
c706d73831 Merge branch 'logo-and-background-upload' into 'develop'
Ability to preview and upload logo and background images

See merge request pleroma/admin-fe!120
2020-07-16 16:47:16 +00:00
Angelina Filippova
702d989c08 Merge branch 'feature/show-open-reports-count' into 'develop'
Show open reports count in Sidebar Menu

Closes #128

See merge request pleroma/admin-fe!143
2020-07-14 16:40:10 +00:00
Angelina Filippova
82255a4bcd Update Changelog 2020-07-14 19:23:59 +03:00
Angelina Filippova
3df6738bc7 Create separate constant in state and action for open reports count 2020-07-14 19:19:42 +03:00
Angelina Filippova
49df2deb31 Add badge for displating open reports count 2020-07-14 18:56:59 +03:00
Angelina Filippova
08bd5dae40 Show reports count in Sidebar 2020-07-14 02:51:51 +03:00
Angelina Filippova
1899450dc1 Rename action that sets reports filter 2020-07-14 02:44:16 +03:00
Angelina Filippova
a710ca9ece Merge branch 'develop' into 'feature/cache-invalidation'
# Conflicts:
#   CHANGELOG.md
2020-07-11 23:42:28 +00:00
Angelina Filippova
090e127f3d Update Changelog 2020-07-12 02:38:00 +03:00
Angelina Filippova
710bb8bfa7 Fix getting data for icon inputs 2020-07-12 02:18:14 +03:00
Angelina Filippova
b6a66ebe20 Fix wrapping values with type map and keyword 2020-07-12 00:55:07 +03:00
Angelina Filippova
0bc5cf9f6b Add new settings to the search 2020-07-11 21:53:23 +03:00
Angelina Filippova
5ae214fbbe Implement types ['map', 'string'] and ['map', ['list', 'string']] 2020-07-11 21:31:19 +03:00
Angelina Filippova
6577376642 Move rendering Crontab settings to Editable keywords after updating its type 2020-07-11 19:42:38 +03:00
Angelina Filippova
3f82738d86 Render editable keyword input for settings that have type ['list', 'tuple'] 2020-07-11 03:28:53 +03:00
Angelina Filippova
13ace35a3c Merge branch 'feature/add-s3-settings' into 'develop'
Add ability to S3 settings on Uploads tab

Closes pleroma#1924

See merge request pleroma/admin-fe!141
2020-07-10 19:53:42 +00:00
Angelina Filippova
55cf52f4de Update Changelog 2020-07-10 18:04:34 +03:00
Angelina Filippova
1e6e006f14 Add ability to configure S3 settings 2020-07-10 18:03:10 +03:00
Angelina Filippova
0323053fee Unify rendering :replace settings as keyword with strings 2020-07-10 03:40:17 +03:00
Angelina Filippova
f34157b1db Add ability to wrap and parse nested settings in keyword inputs 2020-07-10 02:26:57 +03:00
Angelina Filippova
cb89fb09be Add input for settings with type ['keyword', 'string'] 2020-07-09 22:27:18 +03:00
Angelina Filippova
ab0dd31640 Fix removing individual url from Cachex 2020-07-09 20:42:37 +03:00
Angelina Filippova
4c32a0708f Add ability to remove multiple urls 2020-07-08 02:42:57 +03:00
Angelina Filippova
a2649dbb64 Add ability to evict and ban multiple URLs 2020-07-07 23:54:11 +03:00
Angelina Filippova
0b36c5bbb0 Fetch banned objects after banning an url 2020-07-07 22:28:46 +03:00
Angelina Filippova
cd689ac75c Enlarge url input, add headers 2020-07-07 18:16:35 +03:00
Angelina Filippova
cea1485ddc Add Invalidation settings on MediaProxy tab 2020-07-06 00:28:09 +03:00
Angelina Filippova
991c17f88e Add table with banned URLs and ability to remove url from cachex 2020-07-05 23:18:13 +03:00
Angelina Filippova
764621d6fd Create actions for listing banned urls, purge and remove banned urls form cachex 2020-07-05 02:34:40 +03:00
Angelina Filippova
9d2a86556c Add input for evicting and banning urls 2020-07-05 02:33:46 +03:00
Angelina Filippova
0aff86e638 Create API functions for MediaProxy Cache 2020-07-03 03:04:17 +03:00
Angelina Filippova
2881730f33 Create route for MediaProxy Cache 2020-07-03 02:30:15 +03:00
91ccbfeda5 Merge branch 'feature/auto-render-mrf' into 'develop'
Render settings on the MRF tab automatically

Closes #124 and #123

See merge request pleroma/admin-fe!139
2020-07-02 15:46:42 +00:00
Angelina Filippova
866fa29757 Merge branch 'feature/disable-mfa' into 'develop'
Ability to disable MFA

Closes #121

See merge request pleroma/admin-fe!140
2020-07-02 00:16:17 +00:00
Angelina Filippova
71885f017d Update Changelog 2020-07-02 00:16:57 +03:00
Angelina Filippova
0a3cbcb70d Add ability to disable multi-factor authentication for a user 2020-07-02 00:15:41 +03:00
Angelina Filippova
92aef6b180 Add API function and action for disabling MFA 2020-07-01 23:48:04 +03:00
Angelina Filippova
f498dcfefe Fix rate-limiters styles 2020-07-01 01:47:14 +03:00
Angelina Filippova
d447ffd314 Remove repetitive dividers 2020-07-01 01:09:11 +03:00
Angelina Filippova
95615a6bbf Add missing dividers between groups of settings 2020-07-01 00:52:36 +03:00
Angelina Filippova
0936d0def7 Remove unused refs from forms 2020-06-30 02:49:39 +03:00
Angelina Filippova
752e8847eb Remove repetitive labels of setting groups 2020-06-30 02:24:46 +03:00
Angelina Filippova
c3960c472a Fix description's margin 2020-06-30 02:16:20 +03:00
Angelina Filippova
070db1235a Fix parsing values that can be both strings and arrays 2020-06-27 02:10:47 +03:00
Angelina Filippova
05615cddf5 Render MRF settings automatically based on description 2020-06-26 23:37:29 +03:00
Angelina Filippova
f1a9d1726a Merge branch 'feature/emoji-packs-pagination' into 'develop'
Implement emoji packs pagination

Closes #118

See merge request pleroma/admin-fe!137
2020-06-25 23:07:59 +00:00
Angelina Filippova
1bae1cd3c9 Merge branch 'develop' into 'feature/emoji-packs-pagination'
# Conflicts:
#   CHANGELOG.md
2020-06-25 21:57:49 +00:00
Angelina Filippova
e0f93c45f0 Update Changelog 2020-06-26 00:56:23 +03:00
Angelina Filippova
9137362dc7 Fix downloading remote packs 2020-06-26 00:55:43 +03:00
Angelina Filippova
dca1f2cce8 Fix deleting last items on page 2020-06-26 00:05:55 +03:00
Angelina Filippova
ed801c5430 Merge branch 'feature/add-missing-mrf-settings' into 'develop'
Add to MRF settings and update Pleroma.Upload.Filter.Mogrify setting

See merge request pleroma/admin-fe!138
2020-06-25 17:01:31 +00:00
Angelina Filippova
92ede0a35f Update Changelog 2020-06-25 19:44:48 +03:00
Angelina Filippova
fbcc5ee524 Add optimistic update for managing files in pack 2020-06-25 04:15:18 +03:00
Angelina Filippova
ab77704c97 Fix displaying remote emojis 2020-06-25 01:36:08 +03:00
Angelina Filippova
bac50fe62d Remove sorting local emoji packs 2020-06-24 22:10:37 +03:00
Angelina Filippova
acf9012979 Collapse inner items when parent item was closed 2020-06-24 21:41:27 +03:00
Angelina Filippova
84c6319a1f Update function that saves active tabs in state 2020-06-24 21:13:31 +03:00
Angelina Filippova
6a73b4f20c Implement pagination for files in a local emoji pack 2020-06-23 23:08:38 +03:00
Angelina Filippova
a98ee9f4ae Update API and actions to add files pagination 2020-06-23 03:37:37 +03:00
Angelina Filippova
6c35973907 Fix managing Pleroma.Upload.Filter.Mogrify setting 2020-06-22 03:04:53 +03:00
Angelina Filippova
ecebe77c40 Add settingsGroup labels 2020-06-20 17:08:27 +03:00
Angelina Filippova
54e5191d04 Add MRF Activity Expitarion settings 2020-06-20 16:29:55 +03:00
Angelina Filippova
a6a92d34ad Use current page when fetching local emoji packs 2020-06-20 01:51:06 +03:00
Angelina Filippova
918bd18b88 Add pagination to local emoji packs 2020-06-20 01:25:59 +03:00
Angelina Filippova
8d23e36a54 Put managing local and remote packs on tabs 2020-06-19 21:40:08 +03:00
Angelina Filippova
51020a6699 Rename Emoji packs module 2020-06-19 02:55:15 +03:00
Angelina Filippova
c2fc99bce0 Fetch local pack's files only after opening collapse item to manage emojis 2020-06-19 02:09:10 +03:00
Angelina Filippova
d8299972b5 Merge branch 'feature/add-links' into 'develop'
Add links to user's profile page and to user's account in Pleroma

See merge request pleroma/admin-fe!136
2020-06-11 20:23:15 +00:00
Angelina Filippova
17d2a74d5a Fix Changelog 2020-06-11 23:16:52 +03:00
Angelina Filippova
bb4a2527ae Update Changelog 2020-06-11 22:57:59 +03:00
Angelina Filippova
2c6f699a1f Add router link to user's profile to log entry message 2020-06-11 21:41:05 +03:00
Angelina Filippova
f96d495612 Create component for Log Entry Message 2020-06-11 21:20:52 +03:00
Angelina Filippova
d0939463c2 Add link to note's author profile page 2020-06-10 19:33:26 +03:00
Angelina Filippova
a8fb2a7255 In Reports add link to user's profile page in admin-fe and to user's account in Pleroma 2020-06-10 01:49:20 +03:00
Angelina Filippova
1033eee7e8 Remove text decoration underline for internal links 2020-06-09 23:36:14 +03:00
Angelina Filippova
2d510fb348 Add link to user's profile in Pleroma instance 2020-06-09 23:28:24 +03:00
Angelina Filippova
8faf9b18c0 Merge branch 'fix/sorting-emoji-pack' into 'develop'
Sort emoji pack alphabetically

Closes #116 and #119

See merge request pleroma/admin-fe!135
2020-06-08 18:20:42 +00:00
Angelina Filippova
cca3e01979 Merge branch 'feature/do-not-show-users-with-null-nicknames' into 'develop'
Update displaying and managing accounts with invalid nicknames

See merge request pleroma/admin-fe!133
2020-06-06 22:27:03 +00:00
Angelina Filippova
2d6ff4d610 Add translation, fix tag display 2020-06-07 01:09:34 +03:00
Angelina Filippova
5554413a7c Standardize function names, replace display_name with nickname on Status show page 2020-06-07 00:58:51 +03:00
Angelina Filippova
b48e047a07 Fix tests 2020-06-07 00:37:28 +03:00
Angelina Filippova
12bac96c9d Merge branch 'develop' into 'feature/do-not-show-users-with-null-nicknames'
# Conflicts:
#   src/components/Status/index.vue
#   src/views/users/components/ModerationDropdown.vue
#   src/views/users/show.vue
2020-06-06 21:10:12 +00:00
Angelina Filippova
cd126c107f Remove unnecessary styles 2020-06-06 23:02:06 +03:00
Angelina Filippova
d3b1191fb2 Update Changelog 2020-06-06 22:50:43 +03:00
Angelina Filippova
e211e26d16 Fix tests 2020-06-06 22:33:08 +03:00
Angelina Filippova
727f72f058 Add confirmation fot note deletion 2020-06-06 22:17:15 +03:00
Angelina Filippova
789fa36e1a Replace checking if acccount is valid with checking if property exists 2020-06-06 22:16:25 +03:00
Angelina Filippova
a08df92ccc Sort emojis alphabetically 2020-06-05 03:05:58 +03:00
Angelina Filippova
0c1c549631 Fix tooltip width to remove its clipping 2020-06-04 20:46:21 +03:00
Angelina Filippova
77646e3de8 Merge branch 'feature/route-for-status' into 'develop'
Create route for single status

Closes #103

See merge request pleroma/admin-fe!126
2020-06-02 20:53:22 +00:00
Angelina Filippova
7fd8a81301 Update Changelog 2020-06-02 23:46:54 +03:00
Angelina Filippova
0a92e71c44 Fix sorting users when there is a user without a nickname of ID 2020-06-02 23:42:57 +03:00
Angelina Filippova
e67fc33600 Make the whole table row clickable to go to users show page 2020-06-02 22:52:04 +03:00
Angelina Filippova
dcc12137eb Merge branch 'feature/do-not-show-users-with-null-nicknames' of git.pleroma.social:pleroma/admin-fe into feature/do-not-show-users-with-null-nicknames 2020-06-02 00:05:00 +03:00
Angelina Filippova
8b5bd59267 Replace display_name with nickname in Reports and Report Notes, check if account is valid 2020-06-02 00:01:56 +03:00
Angelina Filippova
54f6c90f06 Update user profile page for users without valid nickame 2020-06-01 22:25:08 +03:00
Angelina Filippova
41c26db820 Update user profile page for users without valid nickame 2020-06-01 01:43:03 +03:00
Angelina Filippova
1fa258ff23 Add tag for invalid accounts on User profile 2020-05-30 22:24:56 +03:00
Angelina Filippova
f4d7ad9453 Refactoring and unification of function names 2020-05-30 21:51:13 +03:00
Angelina Filippova
019b24245a Merge branch 'fix/language-inconsistency-in-account-type' into 'develop'
Fix language inconsistency and tag display on Users and User profile pages

Closes #115

See merge request pleroma/admin-fe!132
2020-05-29 19:44:31 +00:00
Angelina Filippova
247fdf61f4 Humanize tags on User Profile page 2020-05-29 22:33:33 +03:00
Angelina Filippova
d92d018831 Put tags and statuses in uppercase 2020-05-29 21:57:43 +03:00
Angelina Filippova
a0cbeefb14 Fix language inconsistency 2020-05-29 21:27:33 +03:00
Angelina Filippova
f22485cc21 Fix styles for Desktop, Mobile and Tablet 2020-05-29 00:51:50 +03:00
Angelina Filippova
b8184c47fe Merge branch 'feature/route-for-status' of git.pleroma.social:pleroma/admin-fe into feature/route-for-status 2020-05-28 22:52:09 +03:00
Angelina Filippova
372d37e3b3 Update reactivity in action that fetches user statuses 2020-05-28 22:46:08 +03:00
Angelina Filippova
63ad2f4524 Fix reactivity flow for user moderation from status show page 2020-05-28 21:15:58 +03:00
Angelina Filippova
03b5c1d76e Fix tests 2020-05-28 16:01:42 +03:00
Angelina Filippova
fe1024be99 Merge branch 'develop' into 'feature/route-for-status'
# Conflicts:
#   CHANGELOG.md
2020-05-27 21:07:22 +00:00
Angelina Filippova
20251b75e5 Update Changelog 2020-05-28 00:06:33 +03:00
Angelina Filippova
d23c9f8130 Update Changelog 2020-05-28 00:01:25 +03:00
Angelina Filippova
3fc779c6fb Add tests for rendering moderation menu and status card 2020-05-27 01:44:26 +03:00
Angelina Filippova
3ded23dfe7 Update test that fetches data on single status show page 2020-05-26 22:38:03 +03:00
Angelina Filippova
2621d7cb51 First green test, fetches single status 2020-05-24 21:14:58 +03:00
Angelina Filippova
a936dfb1e1 Fix status show component's name 2020-05-24 20:09:53 +03:00
Angelina Filippova
1c2691478b Merge branch 'develop' into 'feature/route-for-status'
# Conflicts:
#   src/store/modules/status.js
2020-05-24 17:00:12 +00:00
Angelina Filippova
3e4a3d2609 Add link to user's profile 2020-05-24 01:54:58 +03:00
Angelina Filippova
23ee4813f8 Add links to see user and status in instance 2020-05-23 22:16:18 +03:00
Angelina Filippova
7ca28c7c75 Add stop propagation event modifier 2020-05-23 00:51:46 +03:00
Angelina Filippova
38c3c08533 Fetch single status after its scope was updated 2020-05-22 21:47:18 +03:00
Angelina Filippova
8d7ffcca89 Fix styles on Status show page 2020-05-22 21:02:20 +03:00
eugenijm
10c436b24a Added the ability to upload image as a setting value 2020-05-21 06:41:53 +03:00
Angelina Filippova
7aea244706 Render dialog window for resetting password on Status view page, fix styles 2020-05-20 23:10:32 +03:00
Angelina Filippova
1d2ecc5255 Extract Reset Password Dialog into separate component 2020-05-20 22:40:25 +03:00
Angelina Filippova
4b701ced5f Remove ability to deactivate account from a status view page 2020-05-19 23:30:50 +03:00
Angelina Filippova
1dfc0bacab Fetch single status after user was moderated on the status view page 2020-05-19 23:21:03 +03:00
Angelina Filippova
fd54181805 Save author of the status in state 2020-05-19 23:15:22 +03:00
Angelina Filippova
8fddbb69d2 Update styles for deactivated users 2020-05-18 23:00:23 +03:00
Angelina Filippova
20a56bb21f Clear search and filter inputs when vue instance is destroyed 2020-05-18 22:50:32 +03:00
Angelina Filippova
1c2782a522 Fix sorting users if there are users without nicknames or IDs 2020-05-18 20:10:33 +03:00
Angelina Filippova
7b7a05170a Disable moderation of users that don't have nicknames or IDs 2020-05-18 20:07:26 +03:00
Angelina Filippova
dd4b5b2f21 Merge branch 'feature/remove-settings-that-shouldnt-be-altered' into 'develop'
Remove settings that shouldn't be altered

Closes #110

See merge request pleroma/admin-fe!131
2020-05-17 14:08:22 +00:00
Angelina Filippova
da701058a7 Update Changelog 2020-05-16 20:44:53 +03:00
Angelina Filippova
52453d63bd Remove Http Signatures settings 2020-05-16 20:42:50 +03:00
Angelina Filippova
af929419fb Merge branch 'feature/show-settings-from-whitelist' into 'develop'
Disable tab if its settings are not on the whitelist

Closes #113

See merge request pleroma/admin-fe!130
2020-05-15 22:32:27 +00:00
Angelina Filippova
8e53f52ccf Update Changelog 2020-05-16 01:26:19 +03:00
Angelina Filippova
094ec8956b Do not render dividers and labels if a setting is not in description 2020-05-15 22:22:20 +03:00
Angelina Filippova
342222d45c Check if settings without keys exists in description.exs 2020-05-15 02:48:46 +03:00
Angelina Filippova
88f2859f47 Disable tabs that don't have settings that can be changed 2020-05-15 01:24:12 +03:00
Angelina Filippova
9c28eddec1 Merge branch 'feature/update-status-count' into 'develop'
Update status count when an instance was selected

Closes #112

See merge request pleroma/admin-fe!129
2020-05-13 22:39:58 +00:00
Angelina Filippova
861eb1680b Clear selected users after vue instance was destroyed 2020-05-13 20:35:35 +03:00
Angelina Filippova
008162c508 Tests for handling status select and clearing the state after component was destroyed 2020-05-13 20:34:47 +03:00
Angelina Filippova
cb99014af5 Add test for pagination on Statuses page 2020-05-13 01:45:34 +03:00
Angelina Filippova
bcc1ea16ff Test for fetching statuses from a selected instance 2020-05-12 22:43:15 +03:00
Angelina Filippova
8e671ac984 Update Changelog 2020-05-12 03:53:57 +03:00
Angelina Filippova
6ec7d89a91 Add test for running on mounted actions in Statuses 2020-05-11 21:20:52 +03:00
Angelina Filippova
744872d64a Fix typo 2020-05-11 20:33:16 +03:00
Angelina Filippova
8c2cc6cac1 Add numeral to normalize count 2020-05-11 00:32:54 +03:00
Angelina Filippova
fddc20600d Update style for mobile UI 2020-05-11 00:19:00 +03:00
Angelina Filippova
791f576543 Remove focus and hover styles for statuses count 2020-05-10 23:12:33 +03:00
Angelina Filippova
8d1d9940c9 Clear state after vue instance was destroyed 2020-05-10 21:13:29 +03:00
Angelina Filippova
8e7eb99f1f Update api that fetches statuses count 2020-05-10 18:49:11 +03:00
Angelina Filippova
2f0f424f91 Add API for fetching a single status 2020-05-08 01:54:32 +03:00
Angelina Filippova
3bedf77b44 Merge branch 'fix/log-level-value' into 'develop'
Fix sending booleans as values of single selects

Closes #109

See merge request pleroma/admin-fe!128
2020-05-06 19:59:20 +00:00
Angelina Filippova
43db9abcd5 Use getBooleanValue only for single selects 2020-05-06 22:52:51 +03:00
Angelina Filippova
7d6fc796de Use boolean value if value is 'true' of 'false' in select inputs with reduced labels 2020-05-06 20:18:52 +03:00
Angelina Filippova
4404e87e3d Rename component for specific multiple select, remove ability to create custom values in those selects 2020-05-06 20:06:30 +03:00
Angelina Filippova
9c6acae0cf Use boolean values if value equals 'true' or 'false' 2020-05-06 19:38:02 +03:00
Angelina Filippova
15730cb733 Merge branch 'feature/add-confirmation-to-remove-button' into 'develop'
Add dialog window with confirmation to remove button

Closes #105

See merge request pleroma/admin-fe!127
2020-05-03 22:58:04 +00:00
Angelina Filippova
df178b6407 Fix tabs header position when dialog window is open 2020-05-04 01:33:57 +03:00
Angelina Filippova
cd5ebccc2f Add confirmation message dialog for removing grouped settings 2020-05-03 20:35:53 +03:00
Angelina Filippova
35a9ef2ca9 Add cofirm message dialog on clicking remove button 2020-05-03 20:30:44 +03:00
Angelina Filippova
9ecdddad16 Fix styles 2020-05-02 20:56:00 +03:00
Angelina Filippova
558db9a1c7 Fetch latest user statuses 2020-05-02 20:08:46 +03:00
Angelina Filippova
7cf2878eb8 Render recent statuses on Status show page 2020-05-02 16:59:14 +03:00
Angelina Filippova
5fe5b38c13 Add router link to Status component 2020-05-02 16:35:13 +03:00
Angelina Filippova
cfa85c1e04 Fix styles for reboot button 2020-05-01 23:44:06 +03:00
Angelina Filippova
c20c2060e9 Mock status data 2020-05-01 23:43:38 +03:00
Angelina Filippova
0a4ddd3e6f Fix mounting component 2020-05-01 01:24:43 +03:00
Angelina Filippova
005c8ff161 Update initial values for users module state 2020-05-01 00:52:32 +03:00
Angelina Filippova
ca8df9e726 Render status-card 2020-04-30 23:56:44 +03:00
Angelina Filippova
9c06776154 Create action for fetching single status 2020-04-30 20:32:37 +03:00
Angelina Filippova
5c87ff33a1 Merge branch 'fix/emoji-upload' into 'develop'
Update emoji API

Closes #75

See merge request pleroma/admin-fe!112
2020-04-30 16:36:27 +00:00
Mark Felder
96125402cd Document we are ending development cycle for 2.0.3 2020-04-29 15:45:09 -05:00
Angelina Filippova
cd09e09431 Create route for status show 2020-04-29 23:40:22 +03:00
Angelina Filippova
99ce098c37 Merge branch 'feature/settings-label-position' into 'develop'
Update setting's label position and shorten suggestions in select inputs

Closes #101

See merge request pleroma/admin-fe!124
2020-04-27 22:38:04 +00:00
Angelina Filippova
aea87c46c8 Update changelog 2020-04-28 00:31:16 +03:00
Angelina Filippova
56fa5c1460 Fix the overlap of fixed buttons and settings menu 2020-04-27 23:09:11 +03:00
Angelina Filippova
c94810994f Add allow-create, refactor getting prefixes and rename custom component 2020-04-27 02:34:40 +03:00
Angelina Filippova
4160a89c66 Reduce labels for Scrub policy, Uploader, Filters and Fed publisher modules 2020-04-27 01:11:50 +03:00
Angelina Filippova
f822fb4ba6 Reduce labels for Mailer adapter, Metadata providers, Rich Media parsers and TTL setters 2020-04-26 21:03:05 +03:00
Angelina Filippova
8937cf87d1 Reduce length of suggestions in Captcha method input 2020-04-25 22:38:30 +03:00
Angelina Filippova
e488e3f852 Reduce options and labels for Pleroma authenticator input 2020-04-25 22:07:48 +03:00
Angelina Filippova
09f219c201 Extract Rewrite Policy Input into separate component 2020-04-24 17:20:56 +03:00
Angelina Filippova
3dd498c2e5 Move button that removes settings on mobile devices 2020-04-23 22:26:07 +03:00
Angelina Filippova
02c3059a97 Change the way rewrite policy input is rendered 2020-04-23 20:57:31 +03:00
Angelina Filippova
4752ce96a3 Update label position for Metadata, Other, RateLimiters, Upload and WebPush tabs 2020-04-23 03:20:29 +03:00
Angelina Filippova
abb375d2ac Update label styles on MediaProxy tab 2020-04-23 02:57:40 +03:00
Angelina Filippova
73a87b440a Update label position on Frontend, Gopher, Http, Instance, JobQueue, Logger and Mailer tabs 2020-04-22 20:50:15 +03:00
Angelina Filippova
a31952b8aa Change label position for ActivityPub, Auth, AutoLinker, Captcha and Esshd tabs 2020-04-22 01:54:19 +03:00
Angelina Filippova
bb36813490 Align label on top on MRF tab 2020-04-22 01:28:40 +03:00
Angelina Filippova
08f96d5881 Merge branch 'feature/generate-invite-link' into 'develop'
Generate invite link

Closes #100

See merge request pleroma/admin-fe!123
2020-04-20 22:53:34 +00:00
Angelina Filippova
a806a06107 Generate invite link 2020-04-20 22:53:34 +00:00
Angelina Filippova
a54d09c486 Merge branch 'fix/reports-shows-up-blank' into 'develop'
Fix blank reports page

Closes #99

See merge request pleroma/admin-fe!121
2020-04-18 23:30:03 +00:00
Angelina Filippova
1f7d78406c Update Reports for cases when actor or account is missing 2020-04-19 02:25:04 +03:00
Angelina Filippova
992d07b1c4 Merge branch 'develop' into fix/reports-shows-up-blank 2020-04-19 00:24:47 +03:00
Angelina Filippova
f1e1832c7e Merge branch 'feature/show-reboot-button' into 'develop'
Show reboot button on every page

Closes #98

See merge request pleroma/admin-fe!122
2020-04-17 22:27:00 +00:00
Angelina Filippova
655584c877 Show reboot button on every page 2020-04-17 22:27:00 +00:00
Angelina Filippova
ac6799211d Exclude cases when length can be called on null or undefined 2020-04-08 23:16:14 +03:00
Angelina Filippova
d5e11e279f Update displaying accounts in reports and statuses 2020-04-08 18:56:01 +03:00
Angelina Filippova
66c5a85821 Merge branch 'fix/disable-invites' into 'develop'
Hide Invites from menu when invites are disabled

Closes #69, #54, and #96

See merge request pleroma/admin-fe!119
2020-04-05 14:44:01 +00:00
Angelina Filippova
d0af7e4907 Hide Invites menu item if invites are disabled 2020-04-05 16:58:54 +03:00
Angelina Filippova
9010cbbf3f Remove excess files 2020-04-05 03:31:45 +03:00
Angelina Filippova
3314a0eace Put invitesDisabled in app state 2020-04-05 03:25:01 +03:00
Angelina Filippova
d8cff84bf5 Update changelog 2020-04-04 22:24:04 +03:00
Angelina Filippova
c517f13545 Merge branch 'develop' into fix/disable-invites 2020-04-04 22:22:42 +03:00
Angelina Filippova
be3372518d Merge branch 'master' into develop 2020-04-04 22:20:31 +03:00
Angelina Filippova
8f5d36ee20 Merge branch 'fix/changelog' into 'master'
Update Changelog for 2.0.2 release

See merge request pleroma/admin-fe!118
2020-04-04 18:45:45 +00:00
Angelina Filippova
e4dcbed6ea Update Changelog for 2.0.2 release 2020-04-04 21:39:04 +03:00
Angelina Filippova
9567695186 Update Changelog 2020-04-04 21:25:36 +03:00
Angelina Filippova
86777defc7 Merge branch 'fix/link-registrations-and-invites' into 'develop'
Link enabling registrations and invites in settings

Closes #97

See merge request pleroma/admin-fe!117
2020-04-04 17:49:06 +00:00
Angelina Filippova
e2f3860544 Remove Fetch initial post setting 2020-04-04 20:43:05 +03:00
Angelina Filippova
79afa08f53 Add input for registrations and invites with confirmations 2020-04-02 22:33:12 +03:00
Angelina Filippova
a2072165aa Implement multipart request for uploading emojis 2020-04-01 18:51:17 +03:00
Angelina Filippova
32432e1f6e Update emoji api functions 2020-04-01 16:37:08 +03:00
Angelina Filippova
ee20731a4e Fix link to remote emoji that was copied to local instance 2020-04-01 16:28:42 +03:00
Angelina Filippova
7418324210 Make shortcode optional when emoji is uploaded 2020-04-01 01:12:31 +03:00
Angelina Filippova
cea667e0e3 Fix displaing emoji from remote packs 2020-03-31 23:05:28 +03:00
Angelina Filippova
d131b5bd88 Rename shortcode 2020-03-31 22:24:19 +03:00
Angelina Filippova
0e876da852 Update emoji APIs for adding, updating and removing emoji files 2020-03-31 03:18:20 +03:00
Angelina Filippova
1f488a18be Update API for downloading remote packs 2020-03-30 19:48:41 +03:00
Angelina Filippova
5805792211 Update Import from FS and ListRemotePacks APIs 2020-03-30 18:50:36 +03:00
Angelina Filippova
34f14c93f7 Merge branch 'fix/login-add-link' into 'develop'
Add link to the docs when a non-admin user logs in

See merge request pleroma/admin-fe!111
2020-03-29 19:58:38 +00:00
Angelina Filippova
2c8270f24c Put message in a variable 2020-03-29 22:52:32 +03:00
Angelina Filippova
b5aba2cc81 Link to docs when a non-admin user tries to log in 2020-03-29 22:21:09 +03:00
Angelina Filippova
0ac84426f7 Merge branch 'fix/uploading-remote-emoji' into 'develop'
Fix fetching remote emoji packs

Closes #95

See merge request pleroma/admin-fe!110
2020-03-29 18:18:23 +00:00
Angelina Filippova
2a38907ebe Load emoji packs that are open in collapse 2020-03-29 20:42:24 +03:00
Angelina Filippova
ca9e84ad4b Add loading when fetching remote packs 2020-03-28 01:52:53 +03:00
Angelina Filippova
759dab4729 Split Emoji pack component into local and remote emoji pack 2020-03-28 01:31:07 +03:00
Angelina Filippova
c7ebd70069 Merge branch 'fix/login-without-roles' into 'develop'
Make error message more user-friendly when non-admin user tries to log in

Closes #87

See merge request pleroma/admin-fe!109
2020-03-26 19:46:51 +00:00
Angelina Filippova
e7167b88f3 Make error message more user-friendly when non-admin user tries to log in 2020-03-26 22:29:41 +03:00
Angelina Filippova
2e22228dd2 Merge branch 'fix/styles-for-resetting-password' into 'develop'
Update security settings dialog on user's page

See merge request pleroma/admin-fe!108
2020-03-25 23:21:26 +00:00
Angelina Filippova
6d11e30b65 Update security settings dialog on user's page 2020-03-25 23:21:26 +00:00
Angelina Filippova
05bc582512 Merge branch 'fix/download-emoji-pack-url' into 'develop'
Fix links for downloading remote emoji packs

Closes #91

See merge request pleroma/admin-fe!107
2020-03-25 00:00:47 +00:00
Angelina Filippova
b30d2553c5 Update Changelog 2020-03-25 02:23:36 +03:00
Angelina Filippova
05abaf1916 Fix link for downloading emoji pack to instance 2020-03-25 02:20:56 +03:00
Angelina Filippova
1bcf33abdc Change link for downloading emoji packs 2020-03-25 01:53:50 +03:00
Angelina Filippova
747dc65e9b Merge branch 'user-edit' into 'develop'
Add the ability to set user password and email

Closes #69

See merge request pleroma/admin-fe!92
2020-03-24 20:59:12 +00:00
Angelina Filippova
cdb922fa19 Merge branch 'fix/settings-submit-button' into 'develop'
Fix settings submit button position on wide screens

See merge request pleroma/admin-fe!106
2020-03-24 16:22:54 +00:00
Angelina Filippova
c99e47e098 Update Changelog 2020-03-24 19:18:07 +03:00
Angelina Filippova
b15f88947d Fix styles for wide screen when sidebar menu is open 2020-03-24 19:14:36 +03:00
Angelina Filippova
8e3256ad9e Fix styles for submit button with wide screen 2020-03-24 15:41:28 +03:00
Angelina Filippova
81f050f9aa Fix tablet width 2020-03-22 20:44:08 +03:00
Angelina Filippova
343f9506f2 Merge branch 'feature/add_settings_search' into 'develop'
Implement settings search

Closes #35

See merge request pleroma/admin-fe!102
2020-03-21 18:18:53 +00:00
Angelina Filippova
da67936a63 Update changelog 2020-03-21 20:43:18 +03:00
Angelina Filippova
c65ddfde6c Add required prop showCheckbox in tests for Status component 2020-03-21 20:38:36 +03:00
Angelina Filippova
cf9b0c5688 Fix tests after updating vue-test-utils 2020-03-21 20:33:13 +03:00
Angelina Filippova
044cfbc246 Test if tab changes after setting was selected 2020-03-21 03:21:05 +03:00
Angelina Filippova
0e972e44e1 Add test for forming search object 2020-03-21 00:58:40 +03:00
Angelina Filippova
2d7b742bda Rename search object variable 2020-03-21 00:58:14 +03:00
Angelina Filippova
4b9c5df5f2 Add test for SetActiveTab arguments 2020-03-20 01:06:22 +03:00
Angelina Filippova
f4df449f1a Check if tabs is changed when search value was selected 2020-03-19 23:06:23 +03:00
Angelina Filippova
d021c77a3e Merge branch 'fix/emails-with-symbols' into 'develop'
Fix parsing emails with symbols

See merge request pleroma/admin-fe!105
2020-03-18 21:13:39 +00:00
Angelina Filippova
88b5abc6a3 Fix parsing emails with symbols 2020-03-19 00:03:33 +03:00
Angelina Filippova
ce3d3387cf Merge branch 'feature/display-status-counts-by-scope' into 'develop'
Display status counts by scope

Closes #54

See merge request pleroma/admin-fe!104
2020-03-18 18:51:35 +00:00
Angelina Filippova
85664ffb54 Display status count by visibility scope 2020-03-18 21:46:14 +03:00
Angelina Filippova
1d21dc5192 Update header margin 2020-03-18 21:09:25 +03:00
Angelina Filippova
4f61344c50 Add api function and action that fetches statuses count by scope 2020-03-17 02:20:51 +03:00
Angelina Filippova
0cbebe2832 First green test for settings search 2020-03-16 22:47:08 +03:00
Angelina Filippova
a83d61ed9f Add data-search attribute when necessary 2020-03-16 22:40:16 +03:00
Angelina Filippova
619831dbb5 Add Pleroma.Emails.NewUsersDigestEmail setting 2020-03-16 22:36:40 +03:00
Angelina Filippova
7f01e26a2d Adapt search for auto linker, admin token and auth settings 2020-03-15 22:44:36 +03:00
Angelina Filippova
148d7b3298 Make search work with settings without keys 2020-03-15 01:31:47 +03:00
Angelina Filippova
5bea899efd Add missing settings to tabs 2020-03-15 01:23:26 +03:00
Angelina Filippova
41e94628cb Merge branch 'develop' into feature/add_settings_search 2020-03-14 21:44:01 +03:00
Angelina Filippova
0556b874cf Scroll to selected setting 2020-03-12 23:48:50 +03:00
Angelina Filippova
9bca5fbdad Add description of settings by tabs 2020-03-11 15:05:07 +03:00
Angelina Filippova
584401a3d7 Add ability to select a setting and go to the tab of the selected setting 2020-03-10 00:43:32 +03:00
Angelina Filippova
26889c28e3 Add info about group and setting key into search object 2020-03-09 22:09:32 +03:00
eugenijm
9395cc782f Add the Security Settings modal for setting the user's email and password 2020-03-09 17:01:08 +03:00
Angelina Filippova
ab5a7158b5 Replace regular tabs with tabs rendered dynamically 2020-02-25 19:59:47 +03:00
Angelina Filippova
12b708404b Update the search 2020-02-25 18:57:38 +03:00
Angelina Filippova
b6d678b423 Add search engine to settings 2020-02-25 16:35:56 +03:00
Angelina Filippova
d0c885c295 Form search object and put it in state 2020-02-25 00:24:46 +03:00
Angelina Filippova
55832cb890 Add search input 2020-02-24 00:17:24 +03:00
235 changed files with 15789 additions and 10329 deletions

58
.woodpecker.yml Normal file
View file

@ -0,0 +1,58 @@
pipeline:
lint:
when:
event:
- push
- pull_request
image: node:14
commands:
- git config --global url."https://github.com/".insteadOf git://github.com/
- yarn
- yarn lint
test:
when:
event:
- push
- pull_request
image: node:14
commands:
- apt update
- apt install firefox-esr -y --no-install-recommends
- git config --global url."https://github.com/".insteadOf git://github.com/
- yarn
- yarn test
build:
when:
event:
- push
branch:
- develop
- stable
image: node:14
commands:
- git config --global url."https://github.com/".insteadOf git://github.com/
- yarn
- yarn build:prod
release:
when:
event:
- push
branch:
- develop
- stable
image: node:16
secrets:
- SCW_ACCESS_KEY
- SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID
commands:
- apt-get update && apt-get install -y rclone wget zip
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
- chmod +x scaleway-cli
- ./scaleway-cli object config install type=rclone
- zip admin-fe.zip -r dist
- rclone copyto admin-fe.zip scaleway:akkoma-updates/frontend/$CI_COMMIT_BRANCH/admin-fe.zip

View file

@ -8,13 +8,142 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
### Changed
### Fixed
## [2.4.0] - 2021-08-01
### Added
- Evicting and banning objects from the MediaProxy cache is disabled if MediaProxy is disabled on the Settings tab. Add ability to enable MediaProxy and Invalidation from MediaProxy tab.
- Allow to upload the custom Terms of Service and Instance Panel HTML pages via Admin API
- Add Report show page and link Moderation log references to the respective reports
- Add Unconfimed filter for Users table
- Filter users by actor type: Person, Bot or Application
- Add ability to configure Media Preview Proxy, User Backup, Websocket based federation and Pleroma.Web.Endpoint.MetricsExporter settings
- Mobile and Tablet UI for Single Report show page
- Ability to set rules and conditions for rendering settings (e.g. `:proxy_remote` setting is hidden if `:uploader` setting is set to `Pleroma.Uploaders.Local`)
- Ability to install new frontends from the Frontend tab in the Settings section
### Changed
- **Breaking**: AdminAPI changed User field `confirmation_pending` to `is_confirmed`
- **Breaking**: AdminAPI changed User field `approval_pending` to `is_approved`
- **Breaking**: AdminAPI changed User field `deactivated` to `is_active`
- Hide Tag actions on Users tab if MRF TagPolicy is disabled. Add ability to enable TagPolicy from Moderation menu
- Move `:restrict_unauthenticated` settings from Authentication tab to Instance tab
- Replace regular inputs with textareas for setting welcome messages in the Settings section
- Remove Websocket based federation settings
- Move Settings tab navigation from the tabbed menu to the main sidebar menu. A separate route is created for each tab.
- Move Emoji packs configuration to the Emoji tab in the Settings section
- 401 and 404 error pages updated
- Remove unused components
### Fixed
- Fix depricatied action names in Reports, move actions that manage users from Reports to reports module
- Allow using underscores and hyphens in new account's usernames
- Fix wrapping `:icons` setting and parsing tuples in settings with key `:headers`
- Update keys for Pleroma.Web.Plugs.RemoteIp and PurgeExpiredActivity settings
- Update switching between local and remote emoji packs panels: the panel with the pack's metadata will be closed when another panel is opened
- Fix displaying messages for multiple errors
## [2.2] - 2020-11-18
### Added
- Ability to configure Media Preview Proxy settings on MediaProxy tab
### Fixed
- Update keys for PurgeExpiredActivity and RemoteIp settings
- Fix wrapping `:icons` setting and parsing tuples in settings with key `:headers`
## [2.1] - 2020-08-26
### Added
- Create `/statuses/:id` route that shows single status
- Add link to the user's account in Pleroma on the user's profile page
- On Reports page add links to reported account and the author of the report
- In Notes add link to the note author's profile page
- In Moderation log add link to the actor's profile page
- Support pagination of local emoji packs and files
- Add MRF Activity Expiration setting
- Add ability to disable multi-factor authentication for a user
- Add ability to configure Invalidation settings on MediaProxy tab
- Ability to configure `S3` settings on Upload tab, `Pleroma.Web.ApiSpec.CastAndValidate` and `:modules` settings on Other tab, `:pools`, `:connections_pool` and `:hackney_pools` settings on Job Queue tab, `:restrict_unauthenticated` settings on Authentication tab, `:favicons` and `:welcome` settings on Instance tab, `:frontends` and `Pleroma.Web.Preload` settings on Frontend tab
- Show number of open reports in Sidebar Menu
- Add confirmation message when deleting a user
- Add new MediaProxy Cache Tab with ability to manually evict and ban objects from the Pleroma MediaProxy cache
- Allow managing user's actor_type field via Admin API
### Changed
- Statuses count changes when an instance is selected and shows the amount of statuses from an originating instance
- Add a confirmation dialog window when Remove button is clicked on the Settings page
- Disable tab on the Settings page if there are no settings on this tab that can be changed in Admin FE
- Settings that can't be altered in Admin FE are removed: HTTP Signatures settings, Federation publisher modules and Oban Repo
- When rendering user's profile, statuses, reports and notes check if required properties exist
- Remove ability to moderate users that don't have valid nicknames
- Displays both labels and description in the header of group of settiings
- Ability to add custom values in Pleroma.Upload.Filter.Mogrify setting in the following format: '{"implode", "1"}'
- Change types of the following settings: ':groups', ':replace', ':federated_timeline_removal', ':reject', ':match_actor'. Update functions that parses and wraps settings data according to this change.
- Move rendering Crontab setting from a separate component to EditableKeyword component
- Show only those MRF settings that have been enabled in MRF Policies setting
- Move Auto Linker settings to Link Formatter Tab as its configuration was moved to :pleroma, Pleroma.Formatter
- Active and Local filters are applied by default on the Users tab
- Update Emoji Packs API to support special chars in pack names
### Fixed
- Send `true` and `false` as booleans if they are values of single selects on the Settings page
- Fix sorting users on Users page if there is an acount with missing nickname or ID
- Add new type of settings: `['string', 'image']`. Render Image upload Input depending on the type of setting, not its key
- Fix displaying `Pending` tag and filtering by Pending Approval status
- Fix following and unfollowing relays from Admin-FE, update mobile UI
- Support special chars in Emoji packs names
## [2.0.3] - 2020-04-29
### Added
- Link settings that enable registrations and invites
- Ability to upload logo, background, default user avatar, instance thumbnail, and NSFW hiding images
### Changed
- Put Instance Reboot button on all pages of admin-fe
- Make Instance Reboot button's positon fixed on Settings page
- Update jest and babel-jest
- Generate an invite link when an invite token has been generated
- Put labels on top of inputs in mobile version
- Shorten suggestions for a series of select inputs: Rewrite policy, Pleroma Authenticator, Captcha Method, Mailer adapter, Metadata providers, Rich Media parsers, TTL setters, Scrub policy, Uploader, Filters and Federation publisher modules
### Fixed
- Disable Invites tab when invites are disabled on BE
## [2.0.2] - 2020-04-01
### Added
- Ability to see local statuses in Statuses by instance section - Ability to see local statuses in Statuses by instance section
- Ability to configure Oban.Cron settings and settings for notifications streamer - Ability to configure Oban.Cron settings and settings for notifications streamer
- Settings search
- Ability to set user's password and email on user's page
- Display status count by scope on Statuses page
### Changed
- Link to Pleroma docs when a non-admin user tries to log in
### Fixed ### Fixed
- Fix parsing tuples in Pleroma.Upload.Filter.Mogrify and Pleroma.Emails.Mailer settings - Fix parsing tuples in Pleroma.Upload.Filter.Mogrify and Pleroma.Emails.Mailer settings
- Fix settings submit button position on wide screens when sidebar menu is open - Fix settings submit button position on wide screens when sidebar menu is open
- Updates links for downloading remote emoji packs
- Fix parsing emails that have symbols in it
## [2.0] - 2020-02-27 ## [2.0] - 2020-02-27

View file

@ -31,11 +31,31 @@ AdminFE is bundled with Pleroma, i.e. you can just visit `https://your.instance/
### Development ### Development
To run AdminFE locally execute `yarn dev` To run AdminFE locally execute
```
# install dependencies
npm install -g yarn
yarn
# run AdminFE locally
yarn dev
```
### Build ### Build
To compile everything for production run `yarn build:prod`, this will build admin-fe into `dist` folder, which you will need to upload to your server and/or point your webserver of choice to. To compile everything for production run
```
# install dependencies
npm install -g yarn
yarn
# compile everything for production
yarn build:prod
```
This will build admin-fe into `dist` folder, which you will need to upload to your server and/or point your webserver of choice to.
#### Disabling features #### Disabling features

9
admin-fe.iml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -2,6 +2,6 @@ module.exports = {
NODE_ENV: '"production"', NODE_ENV: '"production"',
ENV_CONFIG: '"prod"', ENV_CONFIG: '"prod"',
BASE_API: '"https://api-prod"', BASE_API: '"https://api-prod"',
DISABLED_FEATURES: '["emoji-packs"]', DISABLED_FEATURES: '[""]',
ASSETS_PUBLIC_PATH: '/pleroma/admin/' ASSETS_PUBLIC_PATH: '/pleroma/admin/'
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "vue-element-admin", "name": "vue-element-admin",
"version": "3.10.0", "version": "3.11.0",
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features", "description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>", "author": "Pan <panfree23@gmail.com>",
"license": "MIT", "license": "MIT",
@ -29,10 +29,13 @@
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git" "url": "git+https://akkoma.dev/AkkomaGang/admin-fe.git"
},
"resolutions": {
"prosemirror-model": "1.9.1"
}, },
"bugs": { "bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues" "url": "https://akkoma.dev/AkkomaGang/admin-fe/-/issues"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.3.4", "@babel/runtime": "^7.3.4",
@ -60,11 +63,13 @@
"screenfull": "4.0.0", "screenfull": "4.0.0",
"showdown": "1.8.6", "showdown": "1.8.6",
"sortablejs": "1.7.0", "sortablejs": "1.7.0",
"tiptap": "^1.29.6",
"tiptap-extensions": "^1.32.7",
"tui-editor": "1.2.7", "tui-editor": "1.2.7",
"vue": "^2.6.8", "vue": "^2.6.8",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-i18n": "^8.9.0", "vue-i18n": "^8.9.0",
"vue-router": "3.0.2", "vue-router": "^3.5.1",
"vue-splitpane": "1.0.2", "vue-splitpane": "1.0.2",
"vuedraggable": "^2.16.0", "vuedraggable": "^2.16.0",
"vuex": "3.0.1", "vuex": "3.0.1",
@ -77,11 +82,11 @@
"@babel/preset-env": "^7.3.4", "@babel/preset-env": "^7.3.4",
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.2", "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.2",
"@vue/babel-preset-jsx": "^1.0.0-beta.2", "@vue/babel-preset-jsx": "^1.0.0-beta.2",
"@vue/test-utils": "^1.0.0-beta.29", "@vue/test-utils": "^1.1.0",
"autoprefixer": "8.5.0", "autoprefixer": "8.5.0",
"babel-eslint": "8.2.6", "babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3", "babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-jest": "^24.1.0", "babel-jest": "^25.3.0",
"babel-loader": "^8.0.5", "babel-loader": "^8.0.5",
"babel-plugin-dynamic-import-node-babel-7": "^2.0.7", "babel-plugin-dynamic-import-node-babel-7": "^2.0.7",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@ -101,12 +106,12 @@
"hash-sum": "1.0.2", "hash-sum": "1.0.2",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"husky": "0.14.3", "husky": "0.14.3",
"jest": "^24.1.0", "jest": "^25.3.0",
"jest-transform-stub": "^2.0.0", "jest-transform-stub": "^2.0.0",
"lint-staged": "7.2.2", "lint-staged": "7.2.2",
"mini-css-extract-plugin": "0.4.1", "mini-css-extract-plugin": "0.4.1",
"node-notifier": "5.2.1", "node-notifier": "5.2.1",
"node-sass": "^4.12.0", "node-sass": "^7.0.1",
"optimize-css-assets-webpack-plugin": "5.0.0", "optimize-css-assets-webpack-plugin": "5.0.0",
"ora": "3.0.0", "ora": "3.0.0",
"path-to-regexp": "2.4.0", "path-to-regexp": "2.4.0",
@ -131,7 +136,7 @@
"webpack": "^4.29.6", "webpack": "^4.29.6",
"webpack-bundle-analyzer": "2.13.1", "webpack-bundle-analyzer": "2.13.1",
"webpack-cli": "^3.2.3", "webpack-cli": "^3.2.3",
"webpack-dev-server": "3.1.14", "webpack-dev-server": "3.11.0",
"webpack-merge": "4.1.4" "webpack-merge": "4.1.4"
}, },
"engines": { "engines": {

7
src/api/__mocks__/app.js Normal file
View file

@ -0,0 +1,7 @@
export async function needReboot(authHost, token) {
return Promise.resolve({ data: false })
}
export async function restartApp(authHost, token) {
return Promise.resolve()
}

View file

@ -0,0 +1,51 @@
export async function addNewEmojiFile(packName, file, shortcode, filename, host, token) {
return Promise.resolve()
}
export function addressOfEmojiInPack(host, packName, name) {
return Promise.resolve()
}
export async function createPack(host, token, packName) {
return Promise.resolve()
}
export async function deleteEmojiFile(packName, shortcode, host, token) {
return Promise.resolve()
}
export async function deletePack(host, token, packName) {
return Promise.resolve()
}
export async function downloadFrom(instanceAddress, packName, as, host, token) {
return Promise.resolve()
}
export async function fetchPack(packName, page, pageSize, host, token) {
return Promise.resolve()
}
export async function importFromFS(host, token) {
return Promise.resolve()
}
export async function listPacks(page, pageSize, host, token) {
return Promise.resolve()
}
export async function listRemotePacks(instance, page, pageSize, host, token) {
return Promise.resolve()
}
export async function reloadEmoji(host, token) {
return Promise.resolve()
}
export async function savePackMetadata(host, token, packName, metadata) {
return Promise.resolve()
}
export async function updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, host, token) {
return Promise.resolve()
}

View file

@ -43,7 +43,7 @@ export function getUserInfo(token, authHost) {
'statuses_count': 0, 'statuses_count': 0,
'cover_photo': '', 'cover_photo': '',
'hide_follows': false, 'hide_follows': false,
'pleroma': { 'confirmation_pending': false, 'deactivated': false, 'tags': ['force_nsfw'], 'is_admin': true }, 'pleroma': { 'is_confirmed': true, 'is_active': true, 'tags': ['force_nsfw'], 'is_admin': true },
'profile_image_url_original': '', 'profile_image_url_original': '',
'created_at': 'Fri Mar 01 15:15:19 +0000 2019', 'created_at': 'Fri Mar 01 15:15:19 +0000 2019',
'fields': [], 'fields': [],

View file

@ -0,0 +1,20 @@
const urls = [
'http://example.com/media/a688346.jpg',
'http://example.com/media/fb1f4d.jpg'
]
export async function listBannedUrls(page, pageSize, authHost, token) {
return Promise.resolve({ data: { page_size: 1, count: 2, urls }})
}
export async function purgeUrls(urls, ban, authHost, token) {
return Promise.resolve()
}
export async function removeBannedUrls(urls, authHost, token) {
return Promise.resolve()
}
export async function searchBannedUrls(query, page, pageSize, authHost, token) {
return Promise.resolve()
}

View file

@ -0,0 +1,3 @@
export function uploadMedia({ formData, authHost }) {
return Promise.resolve()
}

View file

@ -0,0 +1,11 @@
export async function fetchLog(authHost, token, params, page = 1) {
return Promise.resolve()
}
export async function fetchAdmins(authHost, token) {
return Promise.resolve()
}
export async function fetchModerators(authHost, token) {
return Promise.resolve()
}

View file

@ -0,0 +1,4 @@
export async function fetchPeers(authHost, token) {
const data = ['lain.com', 'heaven.com']
return Promise.resolve({ data })
}

View file

@ -0,0 +1,11 @@
export async function fetchRelays(authHost, token) {
return Promise.resolve()
}
export async function addRelay(relay_url, authHost, token) {
return Promise.resolve()
}
export async function deleteRelay(relay_url, authHost, token) {
return Promise.resolve()
}

View file

@ -1,14 +1,14 @@
const reports = [ const reports = [
{ created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '2', content: 'This is a report', statuses: [] }, { created_at: '2019-05-21T21:35:33.000Z', account: { nickname: 'benjamin', tags: [] }, actor: {}, state: 'open', id: '2', content: 'This is a report', statuses: [] },
{ created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] }, { created_at: '2019-05-20T22:45:33.000Z', account: { nickname: 'alice', tags: [] }, actor: {}, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] },
{ created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '3', content: '', statuses: [] }, { created_at: '2019-05-18T13:01:33.000Z', account: { nickname: 'nick_keys', tags: [] }, actor: {}, state: 'closed', id: '3', content: '', statuses: [] },
{ created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '5', content: 'This is a report', statuses: [] }, { created_at: '2019-05-21T21:35:33.000Z', account: { nickname: 'benjamin', tags: [] }, actor: {}, state: 'open', id: '5', content: 'This is a report', statuses: [] },
{ created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '7', content: 'Please block this user', statuses: [ { created_at: '2019-05-20T22:45:33.000Z', account: { nickname: 'alice', tags: [] }, actor: {}, state: 'resolved', id: '7', content: 'Please block this user', statuses: [
{ account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'public', sensitive: false, id: '11', content: 'Hey!', url: '', created_at: '2019-05-10T21:35:33.000Z' }, { account: { nickname: 'alice', avatar: '' }, visibility: 'public', sensitive: false, id: '11', content: 'Hey!', url: '', created_at: '2019-05-10T21:35:33.000Z' },
{ account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'unlisted', sensitive: true, id: '10', content: 'Bye!', url: '', created_at: '2019-05-10T21:00:33.000Z' } { account: { nickname: 'alice', avatar: '' }, visibility: 'unlisted', sensitive: true, id: '10', content: 'Bye!', url: '', created_at: '2019-05-10T21:00:33.000Z' }
] }, ] },
{ created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '6', content: '', statuses: [] }, { created_at: '2019-05-18T13:01:33.000Z', account: { nickname: 'nick_keys', tags: [] }, actor: {}, state: 'closed', id: '6', content: '', statuses: [] },
{ created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] } { created_at: '2019-05-18T13:01:33.000Z', account: { nickname: 'nick_keys', tags: [] }, actor: {}, state: 'closed', id: '4', content: '', statuses: [] }
] ]
export async function fetchReports(filter, page, pageSize, authHost, token) { export async function fetchReports(filter, page, pageSize, authHost, token) {
@ -21,11 +21,19 @@ export async function changeState(reportsData, authHost, token) {
return Promise.resolve({ data: '' }) return Promise.resolve({ data: '' })
} }
export async function changeStatusScope(id, sensitive, visibility, authHost, token) { export async function createNote(content, reportID, authHost, token) {
const status = reports[4].statuses[0]
return Promise.resolve({ data: { ...status, sensitive, visibility }})
}
export async function deleteStatus(statusId, authHost, token) {
return Promise.resolve() return Promise.resolve()
} }
export async function deleteNote(noteID, reportID, authHost, token) {
return Promise.resolve()
}
// export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
// const status = reports[4].statuses[0]
// return Promise.resolve({ data: { ...status, sensitive, visibility }})
// }
// export async function deleteStatus(statusId, authHost, token) {
// return Promise.resolve()
// }

View file

@ -0,0 +1,59 @@
const configsWithTagPolicy = {
configs: [{
group: ':pleroma',
key: ':mrf',
value: [
{ tuple: [':policies', ['Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy', 'Pleroma.Web.ActivityPub.MRF.TagPolicy']] },
{ tuple: [':transparency', true] },
{ tuple: [':transparency_exclusions', []] }
] },
{
group: ':pleroma',
key: ':media_proxy',
value: [
{ tuple: [':enabled', true] },
{ tuple: [':invalidation', [
{ tuple: [':provider', 'Pleroma.Web.MediaProxy.Invalidation.Script'] },
{ tuple: [':enabled', true] }
]] }
] }],
need_reboot: false
}
const configAfterUpdate = {
configs: [{
db: [':policies'],
group: ':pleroma',
key: ':mrf',
value: [{ tuple: [':policies', ['Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy', 'Pleroma.Web.ActivityPub.MRF.TagPolicy']] }]
}],
need_reboot: false
}
export async function fetchSettings(authHost, token) {
return Promise.resolve({ data: configsWithTagPolicy })
}
export async function getInstanceDocument(name, authHost, token) {
return Promise.resolve({ data: '<h1>Instance panel</h1>' })
}
export async function updateSettings(configs, authHost, token) {
return Promise.resolve({ data: configAfterUpdate })
}
export async function deleteInstanceDocument(name, authHost, token) {
return Promise.resolve()
}
export async function fetchDescription(authHost, token) {
return Promise.resolve()
}
export async function updateInstanceDocument(name, formData, authHost, token) {
return Promise.resolve()
}
export async function removeSettings(configs, authHost, token) {
return Promise.resolve()
}

View file

@ -5,3 +5,93 @@ export async function changeStatusScope(id, sensitive, visibility, authHost, tok
export async function deleteStatus(id, authHost, token) { export async function deleteStatus(id, authHost, token) {
return Promise.resolve() return Promise.resolve()
} }
export async function fetchStatus(id, authHost, token) {
const data = {
account: {
id: '9n1bySks25olxWrku0',
avatar: 'http://localhost:4000/images/avi.png',
nickname: 'dolin',
tags: ['mrf_tag:media-strip', 'mrf_tag:sandbox', 'mrf_tag:disable-any-subscription', 'mrf_tag:media-force-nsfw'],
url: 'http://localhost:4000/users/dolin'
},
content: 'pizza makes everything better',
created_at: '2020-05-22T17:34:34.000Z',
id: '9vJOO3iFPyjNaEhJ5s',
media_attachments: [],
poll: null,
sensitive: false,
spoiler_text: '',
visibility: 'public',
url: 'http://localhost:4000/notice/9vJOO3iFPyjNaEhJ5s'
}
return Promise.resolve({ data })
}
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
let data
if (pageSize === 1) {
data = page === 1 || page === 2
? [{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'nickname': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'A nice young couple contacted us from Brazil to decorate their newly acquired apartment.',
'created_at': '2020-01-31T18:20:01.000Z',
'id': '9rZIr0Jzao5Gjgfmro',
'sensitive': false,
'url': 'http://localhost:4000/objects/7af9abbd-fb6c-4318-aeb7-6636c138ac98',
'visibility': 'unlisted'
}]
: []
} else {
data = [
{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'nickname': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'i love parks&rec',
'created_at': '2020-04-12T18:20:01.000Z',
'id': 'o5Gjgfmro9rZIr0Jza',
'sensitive': false,
'url': 'http://localhost:4000/objects/7af9abbd-aeb7-6636c138ac98-fb6c-4318',
'visibility': 'unlisted'
},
{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'nickname': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'the happiest man ever',
'created_at': '2019-11-23T12:56:18.000Z',
'id': '9pFoVfWMU3A96Rzq3k',
'sensitive': false,
'url': 'http://localhost:4000/objects/449c90fe-c457-4c64-baf2-fe6d0a59ca25',
'visibility': 'unlisted'
}]
}
return Promise.resolve({ data })
}
export async function fetchStatusesCount(instance, authHost, token) {
const data = instance === 'heaven.com'
? {
'status_visibility':
{ 'direct': 1, 'private': 2, 'public': 3, 'unlisted': 0 }
}
: {
'status_visibility':
{ 'direct': 4, 'private': 10, 'public': 4, 'unlisted': 10 }
}
return Promise.resolve({ data })
}
export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
return Promise.resolve()
}

View file

@ -1,53 +1,46 @@
export let users = [ export let users = [
{ active: true, deactivated: false, id: '2', nickname: 'allis', local: true, external: false, roles: { admin: true, moderator: false }, tags: [] }, { is_confirmed: true, is_approved: true, is_active: true, id: '2', nickname: 'allis', local: true, external: false, roles: { admin: true, moderator: false }, tags: [], actor_type: 'Person' },
{ active: true, deactivated: false, id: '10', nickname: 'bob', local: false, external: true, roles: { admin: false, moderator: false }, tags: ['sandbox'] }, { is_confirmed: true, is_approved: true, is_active: true, id: '10', nickname: 'bob', local: true, external: false, roles: { admin: false, moderator: false }, tags: ['mrf_tag:sandbox'], actor_type: 'Person' },
{ active: false, deactivated: true, id: 'abc', nickname: 'john', local: true, external: false, roles: { admin: false, moderator: false }, tags: ['strip_media'] } { is_confirmed: true, is_approved: false, is_active: true, id: '567', nickname: 'ded', local: false, external: true, roles: { admin: false, moderator: false }, tags: [], actor_type: 'Person' },
{ is_confirmed: true, is_approved: true, is_active: false, id: 'abc', nickname: 'john', local: true, external: false, roles: { admin: false, moderator: false }, tags: ['mrf_tag:media-strip'], actor_type: 'Person' },
{ is_confirmed: true, is_approved: false, is_active: true, id: '100', nickname: 'sally', local: true, external: false, roles: { admin: false, moderator: false }, tags: [], actor_type: 'Service' },
{ is_confirmed: true, is_approved: false, is_active: true, id: '123', nickname: 'bot', local: true, external: false, roles: { admin: false, moderator: false }, tags: [], actor_type: 'Application' }
] ]
const userProfile = { avatar: 'avatar.jpg', display_name: 'Allis', nickname: 'allis', id: '2', tags: [], roles: { admin: true, moderator: false }, local: true, external: false } const userProfile = { avatar: 'avatar.jpg', nickname: 'allis', id: '2', tags: [], roles: { admin: true, moderator: false }, local: true, external: false }
const userStatuses = [] const userStatuses = [
{ account: { id: '9n1bySks25olxWrku0', nickname: 'dolin' }, content: 'pizza makes everything better', id: '9vJOO3iFPyjNaEhJ5s', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' },
const filterUsers = (str) => { { account: { id: '9n1bySks25olxWrku0', nickname: 'dolin' }, content: 'pizza time', id: '9vJPD5XKOdzQ0bvGLY', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' },
const filters = str.split(',').filter(item => item.length > 0) { account: { id: '9n1bySks25olxWrku0', nickname: 'dolin' }, content: 'what is yout favorite pizza?', id: '9jop82OBXeFPYulVjM', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' }
if (filters.length === 0) { ]
return users
}
const applyFilters = (acc, filters, users) => {
if (filters.length === 0) {
return acc
}
const filteredUsers = users.filter(user => user[filters[0]])
const newAcc = [...filteredUsers]
return applyFilters(newAcc, filters.slice(1), filteredUsers)
}
return applyFilters([], filters, users)
}
export async function fetchUser(id, authHost, token) { export async function fetchUser(id, authHost, token) {
return Promise.resolve({ data: userProfile }) return Promise.resolve({ data: userProfile })
} }
export async function fetchUsers(filters, authHost, token, page = 1) { export async function fetchUserCredentials(nickname, authHost, token) {
const filteredUsers = filterUsers(filters) return Promise.resolve({ data: {}})
}
export async function fetchUsers(filters, actorTypeFilters, authHost, token, page = 1) {
return Promise.resolve({ data: { return Promise.resolve({ data: {
users: filteredUsers, users,
count: filteredUsers.length, count: users.length,
page_size: 50 page_size: 50
}}) }})
} }
export async function fetchUserStatuses(id, authHost, godmode, token) { export async function fetchUserStatuses(id, authHost, godmode, token) {
return Promise.resolve({ data: userStatuses }) return Promise.resolve({ data: { activities: userStatuses }})
} }
export async function getPasswordResetToken(nickname, authHost, token) { export async function getPasswordResetToken(nickname, authHost, token) {
return Promise.resolve({ data: { token: 'g05lxnBJQnL', link: 'http://url/api/pleroma/password_reset/g05lxnBJQnL' }}) return Promise.resolve({ data: { token: 'g05lxnBJQnL', link: 'http://url/api/v1/pleroma/password_reset/g05lxnBJQnL' }})
} }
export async function searchUsers(query, filters, authHost, token, page = 1) { export async function searchUsers(query, filters, actorTypeFilters, authHost, token, page = 1) {
const filteredUsers = filterUsers(filters) const response = users.filter(user => user.nickname === query)
const response = filteredUsers.filter(user => user.nickname === query)
return Promise.resolve({ data: { return Promise.resolve({ data: {
users: response, users: response,
count: response.length, count: response.length,
@ -58,7 +51,7 @@ export async function searchUsers(query, filters, authHost, token, page = 1) {
export async function activateUsers(nicknames, authHost, token) { export async function activateUsers(nicknames, authHost, token) {
const response = nicknames.map(nickname => { const response = nicknames.map(nickname => {
const currentUser = users.find(user => user.nickname === nickname) const currentUser = users.find(user => user.nickname === nickname)
return { ...currentUser, deactivated: false } return { ...currentUser, is_active: true }
}) })
return Promise.resolve({ data: response }) return Promise.resolve({ data: response })
} }
@ -72,7 +65,15 @@ export async function addRight(nicknames, right, authHost, token) {
export async function deactivateUsers(nicknames, authHost, token) { export async function deactivateUsers(nicknames, authHost, token) {
const response = nicknames.map(nickname => { const response = nicknames.map(nickname => {
const currentUser = users.find(user => user.nickname === nickname) const currentUser = users.find(user => user.nickname === nickname)
return { ...currentUser, deactivated: true } return { ...currentUser, is_active: false }
})
return Promise.resolve({ data: response })
}
export async function approveUserAccount(nicknames, authHost, token) {
const response = nicknames.map(nickname => {
const currentUser = users.find(user => user.nickname === nickname)
return { ...currentUser, is_approved: true }
}) })
return Promise.resolve({ data: response }) return Promise.resolve({ data: response })
} }
@ -98,7 +99,27 @@ export async function untagUser(nickname, tag, authHost, token) {
} }
export async function createNewAccount(nickname, email, password, authHost, token) { export async function createNewAccount(nickname, email, password, authHost, token) {
const newUser = { active: true, deactivated: false, id: '15', nickname, local: true, external: false, roles: { admin: false, moderator: false }, tags: [] } const newUser = { active: true, is_active: true, id: '15', nickname, local: true, external: false, roles: { admin: false, moderator: false }, tags: [] }
users = [...users, newUser] users = [...users, newUser]
return Promise.resolve() return Promise.resolve()
} }
export async function updateUserCredentials(nickname, credentials, authHost, token) {
return Promise.resolve()
}
export async function disableMfa(nickname, authHost, token) {
return Promise.resolve()
}
export async function forcePasswordReset(nicknames, authHost, token) {
return Promise.resolve()
}
export async function confirmUserEmail(nicknames, authHost, token) {
return Promise.resolve()
}
export async function resendConfirmationEmail(nicknames, authHost, token) {
return Promise.resolve()
}

23
src/api/app.js Normal file
View file

@ -0,0 +1,23 @@
import request from '@/utils/request'
import { getToken } from '@/utils/auth'
import { baseName } from './utils'
export async function needReboot(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/need_reboot`,
method: 'get',
headers: authHeaders(token)
})
}
export async function restartApp(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/restart`,
method: 'get',
headers: authHeaders(token)
})
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

View file

@ -2,22 +2,74 @@ import request from '@/utils/request'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { baseName } from './utils' import { baseName } from './utils'
import _ from 'lodash' export async function addNewEmojiFile(packName, file, shortcode, filename, host, token) {
const data = new FormData()
if (filename.trim() !== '') {
data.set('filename', filename)
}
if (shortcode.trim() !== '') {
data.set('shortcode', shortcode)
}
data.set('file', file)
export async function deletePack(host, token, name) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}`, url: `/api/v1/pleroma/emoji/packs/files?name=${packName}`,
method: 'post',
headers: authHeaders(token),
data
})
}
export function addressOfEmojiInPack(host, packName, name) {
return `${baseName(host)}/emoji/${encodeUri(packName)}/${name}`
}
export async function createPack(host, token, packName) {
return await request({
baseURL: baseName(host),
url: `/api/v1/pleroma/emoji/pack?name=${packName}`,
method: 'post',
headers: authHeaders(token)
})
}
export async function deleteEmojiFile(packName, shortcode, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/v1/pleroma/emoji/packs/files?name=${packName}&shortcode=${shortcode}`,
method: 'delete', method: 'delete',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function reloadEmoji(host, token) { export async function deletePack(host, token, packName) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: '/api/pleroma/admin/reload_emoji', url: `/api/v1/pleroma/emoji/pack?name=${packName}`,
method: 'delete',
headers: authHeaders(token)
})
}
export async function downloadFrom(instanceAddress, packName, as, host, token) {
return await request({
baseURL: baseName(host),
url: '/api/v1/pleroma/emoji/packs/download',
method: 'post', method: 'post',
headers: authHeaders(token),
data: as.trim() === ''
? { url: baseName(instanceAddress), name: packName }
: { url: baseName(instanceAddress), name: packName, as },
timeout: 0
})
}
export async function fetchPack(packName, page, pageSize, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/v1/pleroma/emoji/pack?name=${packName}&page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
@ -25,132 +77,60 @@ export async function reloadEmoji(host, token) {
export async function importFromFS(host, token) { export async function importFromFS(host, token) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: '/api/pleroma/emoji/packs/import_from_fs', url: '/api/v1/pleroma/emoji/packs/import',
method: 'get',
headers: authHeaders(token)
})
}
export async function listPacks(page, pageSize, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/v1/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function listRemotePacks(instance, page, pageSize, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/v1/pleroma/emoji/packs/remote?url=${baseName(instance)}&page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function reloadEmoji(host, token) {
return await request({
baseURL: baseName(host),
url: '/api/v1/pleroma/admin/reload_emoji',
method: 'post', method: 'post',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function createPack(host, token, name) { export async function savePackMetadata(host, token, packName, metadata) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}`, url: `/api/v1/pleroma/emoji/pack?name=${packName}`,
method: 'put', method: 'patch',
headers: authHeaders(token)
})
}
export async function listPacks(host) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/`,
method: 'get'
})
}
export async function listRemotePacks(host, token, instance) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/list_from`,
method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { instance_address: baseName(instance) } data: { metadata },
})
}
export async function downloadFrom(host, instance_address, pack_name, as, token) {
if (as.trim() === '') {
as = null
}
return await request({
baseURL: baseName(host),
url: '/api/pleroma/emoji/packs/download_from',
method: 'post',
headers: authHeaders(token),
data: { instance_address: baseName(instance_address), pack_name, as },
timeout: 0
})
}
export async function savePackMetadata(host, token, name, new_data) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}/update_metadata`,
method: 'post',
headers: authHeaders(token),
data: { name, new_data },
timeout: 0 // This might take a long time timeout: 0 // This might take a long time
}) })
} }
function fileUpdateFormData(d) { export async function updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, host, token) {
const data = new FormData()
_.each(d, (v, k) => {
data.set(k, v)
})
return data
}
export async function updatePackFile(host, token, args) {
let data = null
switch (args.action) {
case 'add': {
const { shortcode, file, fileName } = args
data = fileUpdateFormData({
action: 'add',
shortcode: shortcode,
file: file
})
if (fileName.trim() !== '') {
data.set('filename', fileName)
}
break
}
case 'update': {
const { oldName, newName, newFilename } = args
data = fileUpdateFormData({
action: 'update',
shortcode: oldName,
new_shortcode: newName,
new_filename: newFilename
})
break
}
case 'remove': {
const { name } = args
data = fileUpdateFormData({
action: 'remove',
shortcode: name
})
break
}
}
const { packName } = args
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}/update_file`, url: `/api/v1/pleroma/emoji/packs/files?name=${packName}`,
method: 'post', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: data, data: { shortcode, new_shortcode: newShortcode, new_filename: newFilename, force }
timeout: 0
}) })
} }
export function addressOfEmojiInPack(host, packName, name) {
return `${baseName(host)}/emoji/${packName}/${name}`
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}
const encodeUri = (name) => encodeURIComponent(name)

View file

@ -5,7 +5,7 @@ import { baseName } from './utils'
export async function generateInviteToken(max_use, expires_at, authHost, token) { export async function generateInviteToken(max_use, expires_at, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/invite_token`, url: `/api/v1/pleroma/admin/users/invite_token`,
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: expires_at && expires_at.length > 0 ? { max_use, expires_at } : { max_use } data: expires_at && expires_at.length > 0 ? { max_use, expires_at } : { max_use }
@ -16,7 +16,7 @@ export async function inviteViaEmail(email, name, authHost, token) {
const data = name.length > 0 ? { email, name } : { email } const data = name.length > 0 ? { email, name } : { email }
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/email_invite', url: '/api/v1/pleroma/admin/users/email_invite',
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data data
@ -26,7 +26,7 @@ export async function inviteViaEmail(email, name, authHost, token) {
export async function listInviteTokens(authHost, token) { export async function listInviteTokens(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/invites`, url: `/api/v1/pleroma/admin/users/invites`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -35,7 +35,7 @@ export async function listInviteTokens(authHost, token) {
export async function revokeToken(tokenToRevoke, authHost, token) { export async function revokeToken(tokenToRevoke, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/revoke_invite`, url: `/api/v1/pleroma/admin/users/revoke_invite`,
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { token: tokenToRevoke } data: { token: tokenToRevoke }

View file

@ -0,0 +1,43 @@
import request from '@/utils/request'
import { getToken } from '@/utils/auth'
import { baseName } from './utils'
export async function listBannedUrls(page, pageSize, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/media_proxy_caches?page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function purgeUrls(urls, ban, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/media_proxy_caches/purge`,
method: 'post',
headers: authHeaders(token),
data: { urls, ban }
})
}
export async function removeBannedUrls(urls, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/media_proxy_caches/delete`,
method: 'post',
headers: authHeaders(token),
data: { urls }
})
}
export async function searchBannedUrls(query, page, pageSize, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/media_proxy_caches?query=${query}&page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token)
})
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

19
src/api/mediaUpload.js Normal file
View file

@ -0,0 +1,19 @@
import { getToken } from '@/utils/auth'
import { baseName } from './utils'
const UPLOAD_URL = '/api/v1/media'
export function uploadMedia({ formData, authHost }) {
const url = baseName(authHost) + UPLOAD_URL
return fetch(url, {
body: formData,
method: 'POST',
headers: authHeaders()
})
.then((data) => data.json())
}
const authHeaders = () => {
return { 'Authorization': `Bearer ${getToken()}` }
}

View file

@ -11,7 +11,7 @@ export async function fetchLog(authHost, token, params, page = 1) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/moderation_log?${normalizedParams}`, url: `/api/v1/pleroma/admin/moderation_log?${normalizedParams}`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -20,7 +20,7 @@ export async function fetchLog(authHost, token, params, page = 1) {
export async function fetchAdmins(authHost, token) { export async function fetchAdmins(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?filters=is_admin`, url: `/api/v1/pleroma/admin/users?filters=is_admin`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -29,7 +29,7 @@ export async function fetchAdmins(authHost, token) {
export async function fetchModerators(authHost, token) { export async function fetchModerators(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?filters=is_moderator`, url: `/api/v1/pleroma/admin/users?filters=is_moderator`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })

View file

@ -5,29 +5,29 @@ import { baseName } from './utils'
export async function fetchRelays(authHost, token) { export async function fetchRelays(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/relay', url: '/api/v1/pleroma/admin/relay',
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function addRelay(relay, authHost, token) { export async function addRelay(relay_url, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/relay', url: '/api/v1/pleroma/admin/relay',
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { relay_url: relay } data: { relay_url }
}) })
} }
export async function deleteRelay(relay, authHost, token) { export async function deleteRelay(relay_url, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/relay', url: '/api/v1/pleroma/admin/relay',
method: 'delete', method: 'delete',
headers: authHeaders(token), headers: authHeaders(token),
data: { relay_url: `https://${relay}/actor` } data: { relay_url }
}) })
} }

View file

@ -5,7 +5,7 @@ import { baseName } from './utils'
export async function changeState(reports, authHost, token) { export async function changeState(reports, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/reports`, url: `/api/v1/pleroma/admin/reports`,
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { reports } data: { reports }
@ -14,8 +14,8 @@ export async function changeState(reports, authHost, token) {
export async function fetchReports(filter, page, pageSize, authHost, token) { export async function fetchReports(filter, page, pageSize, authHost, token) {
const url = filter.length > 0 const url = filter.length > 0
? `/api/pleroma/admin/reports?state=${filter}&page=${page}&page_size=${pageSize}` ? `/api/v1/pleroma/admin/reports?state=${filter}&page=${page}&page_size=${pageSize}`
: `/api/pleroma/admin/reports?page=${page}&page_size=${pageSize}` : `/api/v1/pleroma/admin/reports?page=${page}&page_size=${pageSize}`
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url, url,
@ -24,10 +24,19 @@ export async function fetchReports(filter, page, pageSize, authHost, token) {
}) })
} }
export async function fetchSingleReport(id, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/reports/${id}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function createNote(content, reportID, authHost, token) { export async function createNote(content, reportID, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/reports/${reportID}/notes`, url: `/api/v1/pleroma/admin/reports/${reportID}/notes`,
method: `post`, method: `post`,
headers: authHeaders(token), headers: authHeaders(token),
data: { content } data: { content }
@ -37,7 +46,7 @@ export async function createNote(content, reportID, authHost, token) {
export async function deleteNote(noteID, reportID, authHost, token) { export async function deleteNote(noteID, reportID, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/reports/${reportID}/notes/${noteID}`, url: `/api/v1/pleroma/admin/reports/${reportID}/notes/${noteID}`,
method: `delete`, method: `delete`,
headers: authHeaders(token) headers: authHeaders(token)
}) })

View file

@ -1,218 +0,0 @@
export const reports = [
{
id: '1',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #1', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '1', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '2', timestamp: '2019/4/13' }
]
},
{
id: '2',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #2',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '3', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '4', timestamp: '2019/4/3' }
]
},
{
id: '3',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #3',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '5', timestamp: '2019/3/1' }]
},
{
id: '4',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #4', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '6', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '7', timestamp: '2019/4/13' }
]
},
{
id: '5',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #5',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '8', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '9', timestamp: '2019/4/3' }
]
},
{
id: '6',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #6',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '10', timestamp: '2019/3/1' }]
},
{
id: '7',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #7', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '11', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '12', timestamp: '2019/4/13' }
]
},
{
id: '8',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #8',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '13', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '14', timestamp: '2019/4/3' }
]
},
{
id: '9',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #9',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '15', timestamp: '2019/3/1' }]
},
{
id: '10',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #10', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '16', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '17', timestamp: '2019/4/13' }
]
},
{
id: '11',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #11',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '18', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '19', timestamp: '2019/4/3' }
]
},
{
id: '12',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #12',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '20', timestamp: '2019/3/1' }]
},
{
id: '13',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #13', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '21', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '22', timestamp: '2019/4/13' }
]
},
{
id: '14',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #14',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '23', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '24', timestamp: '2019/4/3' }
]
},
{
id: '15',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #15',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '25', timestamp: '2019/3/1' }]
},
{
id: '16',
timestamp: '2019/4/12',
local: true,
from: 'John', // actor nickname
object: 'Bob', // user nickname
header: 'Report #16', // content
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Nick', text: 'Lorem ipsum', id: '26', timestamp: '2019/4/13' },
{ author: 'Val', text: 'dolor sit amet', id: '27', timestamp: '2019/4/13' }
]
},
{
id: '17',
timestamp: '2019/4/1',
local: true,
from: 'Max',
object: 'Vic',
header: 'Report #17',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [
{ author: 'Tony', text: 'consectetur adipiscing elit', id: '28', timestamp: '2019/4/2' },
{ author: 'Zac', text: 'sed do eiusmod tempor incididunt', id: '29', timestamp: '2019/4/3' }
]
},
{
id: '18',
timestamp: '2019/2/28',
local: true,
from: 'Tim',
object: 'Jen',
header: 'Report #18',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
notes: [{ author: 'Bruce', text: 'ut labore et dolore magna aliqua', id: '30', timestamp: '2019/3/1' }]
}
]

View file

@ -1,11 +1,30 @@
import request from '@/utils/request' import request from '@/utils/request'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { baseName } from './utils' import { baseName } from './utils'
import _ from 'lodash'
export async function deleteInstanceDocument(name, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/instance_document/${name}`,
method: 'delete',
headers: authHeaders(token)
})
}
export async function fetchDescription(authHost, token) { export async function fetchDescription(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/config/descriptions`, url: `/api/v1/pleroma/admin/config/descriptions`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchDescription2(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v2/pleroma/admin/config/descriptions`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -14,16 +33,35 @@ export async function fetchDescription(authHost, token) {
export async function fetchSettings(authHost, token) { export async function fetchSettings(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/config`, url: `/api/v1/pleroma/admin/config`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function getInstanceDocument(name, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/instance_document/${name}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function updateInstanceDocument(name, formData, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/instance_document/${name}`,
method: 'patch',
data: formData,
headers: { ...authHeaders(token), 'Content-Type': 'multipart/form-data' }
})
}
export async function updateSettings(configs, authHost, token) { export async function updateSettings(configs, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/config`, url: `/api/v1/pleroma/admin/config`,
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { configs } data: { configs }
@ -33,20 +71,31 @@ export async function updateSettings(configs, authHost, token) {
export async function removeSettings(configs, authHost, token) { export async function removeSettings(configs, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/config`, url: `/api/v1/pleroma/admin/config`,
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { configs } data: { configs }
}) })
} }
export async function restartApp(authHost, token) { export async function fetchFrontends(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/restart`, url: `/api/v1/pleroma/admin/frontends`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function installFrontend(data, authHost, token) {
const filteredData = _.pickBy(data)
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/frontends/install`,
method: 'post',
headers: authHeaders(token),
data: filteredData
})
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

View file

@ -5,7 +5,7 @@ import { baseName } from './utils'
export async function changeStatusScope(id, sensitive, visibility, authHost, token) { export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/statuses/${id}`, url: `/api/v1/pleroma/admin/statuses/${id}`,
method: 'put', method: 'put',
headers: authHeaders(token), headers: authHeaders(token),
data: { sensitive, visibility } data: { sensitive, visibility }
@ -15,25 +15,34 @@ export async function changeStatusScope(id, sensitive, visibility, authHost, tok
export async function deleteStatus(id, authHost, token) { export async function deleteStatus(id, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/statuses/${id}`, url: `/api/v1/pleroma/admin/statuses/${id}`,
method: 'delete', method: 'delete',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function fetchStatus(id, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/statuses/${id}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) { export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/statuses?godmode=${godmode}&local_only=${localOnly}&page=${page}&page_size=${pageSize}`, url: `/api/v1/pleroma/admin/statuses?godmode=${godmode}&local_only=${localOnly}&page=${page}&page_size=${pageSize}`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function fetchStatusesCount(authHost, token) { export async function fetchStatusesCount(instance, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/stats`, url: instance ? `/api/v1/pleroma/admin/stats?instance=${instance}` : `/api/v1/pleroma/admin/stats`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -42,7 +51,7 @@ export async function fetchStatusesCount(authHost, token) {
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) { export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/instances/${instance}/statuses?page=${page}&page_size=${pageSize}`, url: `/api/v1/pleroma/admin/instances/${instance}/statuses?page=${page}&page_size=${pageSize}`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })

View file

@ -5,7 +5,7 @@ import { baseName } from './utils'
export async function activateUsers(nicknames, authHost, token) { export async function activateUsers(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/activate`, url: `/api/v1/pleroma/admin/users/activate`,
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -15,7 +15,7 @@ export async function activateUsers(nicknames, authHost, token) {
export async function addRight(nicknames, right, authHost, token) { export async function addRight(nicknames, right, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/permission_group/${right}`, url: `/api/v1/pleroma/admin/users/permission_group/${right}`,
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -25,7 +25,7 @@ export async function addRight(nicknames, right, authHost, token) {
export async function createNewAccount(nickname, email, password, authHost, token) { export async function createNewAccount(nickname, email, password, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users', url: '/api/v1/pleroma/admin/users',
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token),
data: { users: [{ nickname, email, password }] } data: { users: [{ nickname, email, password }] }
@ -35,7 +35,7 @@ export async function createNewAccount(nickname, email, password, authHost, toke
export async function deactivateUsers(nicknames, authHost, token) { export async function deactivateUsers(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/deactivate`, url: `/api/v1/pleroma/admin/users/deactivate`,
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -45,7 +45,7 @@ export async function deactivateUsers(nicknames, authHost, token) {
export async function deleteRight(nicknames, right, authHost, token) { export async function deleteRight(nicknames, right, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/permission_group/${right}`, url: `/api/v1/pleroma/admin/users/permission_group/${right}`,
method: 'delete', method: 'delete',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -55,17 +55,27 @@ export async function deleteRight(nicknames, right, authHost, token) {
export async function deleteUsers(nicknames, authHost, token) { export async function deleteUsers(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users`, url: `/api/v1/pleroma/admin/users`,
method: 'delete', method: 'delete',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
}) })
} }
export async function disableMfa(nickname, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v1/pleroma/admin/users/disable_mfa`,
method: 'put',
headers: authHeaders(token),
data: { nickname }
})
}
export async function fetchUser(id, authHost, token) { export async function fetchUser(id, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${id}`, url: `/api/v1/pleroma/admin/users/${id}`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -74,7 +84,7 @@ export async function fetchUser(id, authHost, token) {
export async function fetchUserCredentials(nickname, authHost, token) { export async function fetchUserCredentials(nickname, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`, url: `/api/v1/pleroma/admin/users/${nickname}/credentials`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -83,17 +93,24 @@ export async function fetchUserCredentials(nickname, authHost, token) {
export async function updateUserCredentials(nickname, credentials, authHost, token) { export async function updateUserCredentials(nickname, credentials, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`, url: `/api/v1/pleroma/admin/users/${nickname}/credentials`,
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: credentials data: credentials
}) })
} }
export async function fetchUsers(filters, authHost, token, page = 1) { export async function fetchUsers(filters, actorTypeFilters, authHost, token, page = 1) {
const url = actorTypeFilters.length === 0
? `/api/v1/pleroma/admin/users?page=${page}&filters=${filters}`
: actorTypeFilters.reduce((acc, filter) => {
const newAcc = acc.concat(`&actor_types[]=${filter}`)
return newAcc
}, `/api/v1/pleroma/admin/users?page=${page}&filters=${filters}`)
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?page=${page}&filters=${filters}`, url,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -102,7 +119,7 @@ export async function fetchUsers(filters, authHost, token, page = 1) {
export async function getPasswordResetToken(nickname, authHost, token) { export async function getPasswordResetToken(nickname, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/password_reset`, url: `/api/v1/pleroma/admin/users/${nickname}/password_reset`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -111,17 +128,24 @@ export async function getPasswordResetToken(nickname, authHost, token) {
export async function forcePasswordReset(nicknames, authHost, token) { export async function forcePasswordReset(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/force_password_reset`, url: `/api/v1/pleroma/admin/users/force_password_reset`,
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
}) })
} }
export async function searchUsers(query, filters, authHost, token, page = 1) { export async function searchUsers(query, filters, actorTypeFilters, authHost, token, page = 1) {
const url = actorTypeFilters.length === 0
? `/api/v1/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`
: actorTypeFilters.reduce((acc, filter) => {
const newAcc = acc.concat(`&actor_types[]=${filter}`)
return newAcc
}, `/api/v1/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`)
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`, url,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
@ -130,7 +154,7 @@ export async function searchUsers(query, filters, authHost, token, page = 1) {
export async function tagUser(nicknames, tags, authHost, token) { export async function tagUser(nicknames, tags, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/tag', url: '/api/v1/pleroma/admin/users/tag',
method: 'put', method: 'put',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames, tags } data: { nicknames, tags }
@ -140,7 +164,7 @@ export async function tagUser(nicknames, tags, authHost, token) {
export async function untagUser(nicknames, tags, authHost, token) { export async function untagUser(nicknames, tags, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/tag', url: '/api/v1/pleroma/admin/users/tag',
method: 'delete', method: 'delete',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames, tags } data: { nicknames, tags }
@ -150,16 +174,26 @@ export async function untagUser(nicknames, tags, authHost, token) {
export async function fetchUserStatuses(id, authHost, godmode, token) { export async function fetchUserStatuses(id, authHost, godmode, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${id}/statuses?godmode=${godmode}`, url: `/api/v1/pleroma/admin/users/${id}/statuses?godmode=${godmode}`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function approveUserAccount(nicknames, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: '/api/v1/pleroma/admin/users/approve',
method: 'patch',
headers: authHeaders(token),
data: { nicknames }
})
}
export async function confirmUserEmail(nicknames, authHost, token) { export async function confirmUserEmail(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/confirm_email', url: '/api/v1/pleroma/admin/users/confirm_email',
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -169,7 +203,7 @@ export async function confirmUserEmail(nicknames, authHost, token) {
export async function resendConfirmationEmail(nicknames, authHost, token) { export async function resendConfirmationEmail(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/resend_confirmation_email', url: '/api/v1/pleroma/admin/users/resend_confirmation_email',
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,36 @@
<template>
<el-tooltip v-if="needReboot" :content="$t('settings.restartApp')" placement="bottom-end">
<el-button type="warning" class="reboot-button" @click="restartApp">
<span>
<i class="el-icon-refresh"/>
{{ $t('settings.instanceReboot') }}
</span>
</el-button>
</el-tooltip>
</template>
<script>
import i18n from '@/lang'
export default {
name: 'RebootButton',
computed: {
needReboot() {
return this.$store.state.app.needReboot
}
},
methods: {
async restartApp() {
try {
await this.$store.dispatch('RestartApplication')
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.restartSuccess')
})
}
}
}
</script>

View file

@ -1,81 +1,78 @@
<template> <template>
<div> <el-card v-if="!status.deleted" class="status-card" @click.native="handleRouteChange()">
<el-card v-if="!status.deleted" class="status-card"> <div slot="header">
<div slot="header"> <div class="status-header">
<div class="status-header"> <div class="status-account-container">
<div class="status-account-container"> <div class="status-account">
<div class="status-account"> <el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/>
<el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(status.account)"/> <router-link
<img :src="status.account.avatar" class="status-avatar-img"> v-if="propertyExists(account, 'id')"
<h3 class="status-account-name">{{ status.account.display_name }}</h3> :to="{ name: 'UsersShow', params: { id: account.id }}"
</div> class="router-link"
<a :href="status.account.url" target="_blank" class="account"> @click.native.stop>
@{{ status.account.acct }} <div class="status-card-header">
</a> <img v-if="propertyExists(account, 'avatar')" :src="account.avatar" class="status-avatar-img">
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">{{ account.nickname }}</span>
<span v-else>
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">
{{ account.nickname }}
</span>
<span v-else class="status-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
</span>
</div>
</router-link>
</div> </div>
<div class="status-actions"> </div>
<div class="status-actions">
<div class="status-tags">
<el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag> <el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag>
<el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag> <el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
<el-dropdown trigger="click">
<el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
{{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-if="!status.sensitive"
@click.native="changeStatus(status.id, true, status.visibility)">
{{ $t('reports.addSensitive') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.sensitive"
@click.native="changeStatus(status.id, false, status.visibility)">
{{ $t('reports.removeSensitive') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'public'"
@click.native="changeStatus(status.id, status.sensitive, 'public')">
{{ $t('reports.public') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'private'"
@click.native="changeStatus(status.id, status.sensitive, 'private')">
{{ $t('reports.private') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'unlisted'"
@click.native="changeStatus(status.id, status.sensitive, 'unlisted')">
{{ $t('reports.unlisted') }}
</el-dropdown-item>
<el-dropdown-item
@click.native="deleteStatus(status.id)">
{{ $t('reports.deleteStatus') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div> </div>
<el-dropdown trigger="click" @click.native.stop>
<el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
{{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-if="!status.sensitive"
@click.native="changeStatus(status.id, true, status.visibility)">
{{ $t('reports.addSensitive') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.sensitive"
@click.native="changeStatus(status.id, false, status.visibility)">
{{ $t('reports.removeSensitive') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'public'"
@click.native="changeStatus(status.id, status.sensitive, 'public')">
{{ $t('reports.public') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'private'"
@click.native="changeStatus(status.id, status.sensitive, 'private')">
{{ $t('reports.private') }}
</el-dropdown-item>
<el-dropdown-item
v-if="status.visibility !== 'unlisted'"
@click.native="changeStatus(status.id, status.sensitive, 'unlisted')">
{{ $t('reports.unlisted') }}
</el-dropdown-item>
<el-dropdown-item
@click.native="deleteStatus(status.id)">
{{ $t('reports.deleteStatus') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div> </div>
</div> </div>
<div class="status-body"> </div>
<div v-if="status.spoiler_text"> <div class="status-body">
<strong>{{ status.spoiler_text }}</strong> <div v-if="status.spoiler_text">
<el-button v-if="!showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = true">Show more</el-button> <strong>{{ status.spoiler_text }}</strong>
<el-button v-if="showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = false">Show less</el-button> <el-button v-if="!showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = true">Show more</el-button>
<div v-if="showHiddenStatus"> <el-button v-if="showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = false">Show less</el-button>
<span class="status-content" v-html="status.content"/> <div v-if="showHiddenStatus">
<div v-if="status.poll" class="poll">
<ul>
<li v-for="(option, index) in status.poll.options" :key="index">
{{ option.title }}
<el-progress :percentage="optionPercent(status.poll, option)" />
</li>
</ul>
</div>
<div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
<img :src="attachment.preview_url">
</div>
</div>
</div>
<div v-if="!status.spoiler_text">
<span class="status-content" v-html="status.content"/> <span class="status-content" v-html="status.content"/>
<div v-if="status.poll" class="poll"> <div v-if="status.poll" class="poll">
<ul> <ul>
@ -89,30 +86,52 @@
<img :src="attachment.preview_url"> <img :src="attachment.preview_url">
</div> </div>
</div> </div>
<a :href="status.url" target="_blank" class="account"> </div>
{{ parseTimestamp(status.created_at) }} <div v-if="!status.spoiler_text">
<span class="status-content" v-html="status.content"/>
<div v-if="status.poll" class="poll">
<ul>
<li v-for="(option, index) in status.poll.options" :key="index">
{{ option.title }}
<el-progress :percentage="optionPercent(status.poll, option)" />
</li>
</ul>
</div>
<div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
<img :src="attachment.preview_url">
</div>
</div>
<div class="status-footer">
<span class="status-created-at">{{ parseTimestamp(status.created_at) }}</span>
<a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop>
{{ $t('statuses.openStatusInInstance') }}
<i class="el-icon-top-right"/>
</a> </a>
</div> </div>
</el-card> </div>
<el-card v-else class="status-card"> </el-card>
<div slot="header"> <el-card v-else class="status-card">
<div class="status-header"> <div slot="header">
<div class="status-account-container"> <div class="status-header">
<div class="status-account"> <div class="status-account-container">
<h4 class="status-deleted">{{ $t('reports.statusDeleted') }}</h4> <div class="status-account">
</div> <h4 class="status-deleted">{{ $t('reports.statusDeleted') }}</h4>
</div> </div>
</div> </div>
</div> </div>
<div class="status-body"> </div>
<span v-if="status.content" class="status-content" v-html="status.content"/> <div class="status-body">
<span v-else class="status-without-content">no content</span> <span v-if="status.content" class="status-content" v-html="status.content"/>
</div> <span v-else class="status-without-content">no content</span>
<a v-if="status.created_at" :href="status.url" target="_blank" class="account"> </div>
{{ parseTimestamp(status.created_at) }} <div class="status-footer">
<span v-if="status.created_at" class="status-created-at">{{ parseTimestamp(status.created_at) }}</span>
<a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop>
Open status in instance
<i class="el-icon-top-right"/>
</a> </a>
</el-card> </div>
</div> </el-card>
</template> </template>
<script> <script>
@ -121,6 +140,11 @@ import moment from 'moment'
export default { export default {
name: 'Status', name: 'Status',
props: { props: {
account: {
type: Object,
required: false,
default: () => { return {} }
},
fetchStatusesByInstance: { fetchStatusesByInstance: {
type: Boolean, type: Boolean,
required: false, required: false,
@ -158,6 +182,7 @@ export default {
}, },
methods: { methods: {
capitalizeFirstLetter(str) { capitalizeFirstLetter(str) {
if (!str) return ''
return str.charAt(0).toUpperCase() + str.slice(1) return str.charAt(0).toUpperCase() + str.slice(1)
}, },
changeStatus(statusId, isSensitive, visibility) { changeStatus(statusId, isSensitive, visibility) {
@ -195,6 +220,12 @@ export default {
}) })
}) })
}, },
handleStatusSelection(account) {
this.$emit('status-selection', account)
},
handleRouteChange() {
this.$router.push({ name: 'StatusShow', params: { id: this.status.id }})
},
optionPercent(poll, pollOption) { optionPercent(poll, pollOption) {
const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0) const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
if (allVotes === 0) { if (allVotes === 0) {
@ -205,8 +236,11 @@ export default {
parseTimestamp(timestamp) { parseTimestamp(timestamp) {
return moment(timestamp).format('YYYY-MM-DD HH:mm') return moment(timestamp).format('YYYY-MM-DD HH:mm')
}, },
handleStatusSelection(account) { propertyExists(account, property, _secondProperty) {
this.$emit('status-selection', account) if (_secondProperty) {
return account[property] && account[_secondProperty]
}
return account[property]
} }
} }
} }
@ -215,10 +249,19 @@ export default {
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
.status-card { .status-card {
margin-bottom: 10px; margin-bottom: 10px;
cursor: pointer;
.account { .account {
text-decoration: underline;
line-height: 26px; line-height: 26px;
font-size: 13px; font-size: 13px;
color: #606266;
}
.account:hover {
text-decoration: underline;
}
.deactivated {
color: gray;
line-height: 28px;
vertical-align: middle;
} }
.image { .image {
width: 20%; width: 20%;
@ -226,6 +269,9 @@ export default {
width: 100%; width: 100%;
} }
} }
.router-link {
text-decoration: none;
}
.show-more-button { .show-more-button {
margin-left: 5px; margin-left: 5px;
} }
@ -242,12 +288,17 @@ export default {
.status-account-name { .status-account-name {
display: inline-block; display: inline-block;
margin: 0; margin: 0;
height: 22px; font-size: 15px;
font-weight: 500;
} }
.status-body { .status-body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.status-card-header {
display: flex;
align-items: center;
}
.status-checkbox { .status-checkbox {
margin-right: 7px; margin-right: 7px;
} }
@ -255,13 +306,26 @@ export default {
font-size: 15px; font-size: 15px;
line-height: 26px; line-height: 26px;
} }
.status-created-at {
font-size: 13px;
color: #606266;
}
.status-deleted { .status-deleted {
font-style: italic; font-style: italic;
margin-top: 3px; margin-top: 3px;
} }
.status-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.status-header { .status-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
}
.status-tags {
display: inline;
} }
.status-without-content { .status-without-content {
font-style: italic; font-style: italic;
@ -280,7 +344,7 @@ export default {
padding: 10px 17px; padding: 10px 17px;
} }
.el-tag { .el-tag {
margin: 3px 4px 3px 0; margin: 3px 0;
} }
.status-account-container { .status-account-container {
margin-bottom: 5px; margin-bottom: 5px;
@ -289,12 +353,20 @@ export default {
margin: 3px 0 3px; margin: 3px 0 3px;
} }
.status-actions { .status-actions {
width: 100%;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between;
}
.status-footer {
flex-direction: column;
align-items: flex-start;
margin-top: 10px;
} }
.status-header { .status-header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start;
} }
} }
} }

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M5,14 C7.76005315,14.0033061 9.99669388,16.2399468 10,19 C10,21.7614237 7.76142375,24 5,24 C2.23857625,24 1.77635684e-15,21.7614237 1.77635684e-15,19 C1.77635684e-15,16.2385763 2.23857625,14 5,14 Z M7.5,19.9375 C8.01776695,19.9375 8.4375,19.517767 8.4375,19 C8.4375,18.482233 8.01776695,18.0625 7.5,18.0625 L6.25,18.0625 C6.07741102,18.0625 5.9375,17.922589 5.9375,17.75 L5.9375,16.5 C5.9375,15.982233 5.51776695,15.5625 5,15.5625 C4.48223305,15.5625 4.0625,15.982233 4.0625,16.5 L4.0625,17.75 C4.0625,17.922589 3.92258898,18.0625 3.75,18.0625 L2.5,18.0625 C1.98223305,18.0625 1.5625,18.482233 1.5625,19 C1.5625,19.517767 1.98223305,19.9375 2.5,19.9375 L3.75,19.9375 C3.92258898,19.9375 4.0625,20.077411 4.0625,20.25 L4.0625,21.5 C4.0625,22.017767 4.48223305,22.4375 5,22.4375 C5.51776695,22.4375 5.9375,22.017767 5.9375,21.5 L5.9375,20.25 C5.9375,20.077411 6.07741102,19.9375 6.25,19.9375 L7.5,19.9375 Z M16,19 C16,20.6568542 17.3431458,22 19,22 C20.6568542,22 22,20.6568542 22,19 L22,5 C22,3.34314575 20.6568542,2 19,2 C17.3431458,2 16,3.34314575 16,5 L16,19 Z M14,19 L14,5 C14,2.23857625 16.2385763,0 19,0 C21.7614237,0 24,2.23857625 24,5 L24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19,14 C21.7600532,14.0033061 23.9966939,16.2399468 24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 C14,16.2385763 16.2385763,14 19,14 Z M21.5,19.9375 C22.017767,19.9375 22.4375,19.517767 22.4375,19 C22.4375,18.482233 22.017767,18.0625 21.5,18.0625 L20.25,18.0625 C20.077411,18.0625 19.9375,17.922589 19.9375,17.75 L19.9375,16.5 C19.9375,15.982233 19.517767,15.5625 19,15.5625 C18.482233,15.5625 18.0625,15.982233 18.0625,16.5 L18.0625,17.75 C18.0625,17.922589 17.922589,18.0625 17.75,18.0625 L16.5,18.0625 C15.982233,18.0625 15.5625,18.482233 15.5625,19 C15.5625,19.517767 15.982233,19.9375 16.5,19.9375 L17.75,19.9375 C17.922589,19.9375 18.0625,20.077411 18.0625,20.25 L18.0625,21.5 C18.0625,22.017767 18.482233,22.4375 19,22.4375 C19.517767,22.4375 19.9375,22.017767 19.9375,21.5 L19.9375,20.25 C19.9375,20.077411 20.077411,19.9375 20.25,19.9375 L21.5,19.9375 Z M2,19 C2,20.6568542 3.34314575,22 5,22 C6.65685425,22 8,20.6568542 8,19 L8,5 C8,3.34314575 6.65685425,2 5,2 C3.34314575,2 2,3.34314575 2,5 L2,19 Z M-2.7585502e-16,19 L5.81397739e-16,5 C-1.37692243e-16,2.23857625 2.23857625,0 5,0 C7.76142375,0 10,2.23857625 10,5 L10,19 C10,21.7614237 7.76142375,24 5,24 C2.23857625,24 4.43234962e-16,21.7614237 -2.7585502e-16,19 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19,0 C21.7600532,0.00330611633 23.9966939,2.23994685 24,5 C24,7.76142375 21.7614237,10 19,10 C16.2385763,10 14,7.76142375 14,5 C14,2.23857625 16.2385763,0 19,0 Z M21.5,5.9375 C22.017767,5.9375 22.4375,5.51776695 22.4375,5 C22.4375,4.48223305 22.017767,4.0625 21.5,4.0625 L20.25,4.0625 C20.077411,4.0625 19.9375,3.92258898 19.9375,3.75 L19.9375,2.5 C19.9375,1.98223305 19.517767,1.5625 19,1.5625 C18.482233,1.5625 18.0625,1.98223305 18.0625,2.5 L18.0625,3.75 C18.0625,3.92258898 17.922589,4.0625 17.75,4.0625 L16.5,4.0625 C15.982233,4.0625 15.5625,4.48223305 15.5625,5 C15.5625,5.51776695 15.982233,5.9375 16.5,5.9375 L17.75,5.9375 C17.922589,5.9375 18.0625,6.07741102 18.0625,6.25 L18.0625,7.5 C18.0625,8.01776695 18.482233,8.4375 19,8.4375 C19.517767,8.4375 19.9375,8.01776695 19.9375,7.5 L19.9375,6.25 C19.9375,6.07741102 20.077411,5.9375 20.25,5.9375 L21.5,5.9375 Z M5,16 C3.34314575,16 2,17.3431458 2,19 C2,20.6568542 3.34314575,22 5,22 L19,22 C20.6568542,22 22,20.6568542 22,19 C22,17.3431458 20.6568542,16 19,16 L5,16 Z M5,14 L19,14 C21.7614237,14 24,16.2385763 24,19 C24,21.7614237 21.7614237,24 19,24 L5,24 C2.23857625,24 3.38176876e-16,21.7614237 0,19 C-1.2263553e-15,16.2385763 2.23857625,14 5,14 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19,14 C21.7600532,14.0033061 23.9966939,16.2399468 24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 C14,16.2385763 16.2385763,14 19,14 Z M21.5,19.9375 C22.017767,19.9375 22.4375,19.517767 22.4375,19 C22.4375,18.482233 22.017767,18.0625 21.5,18.0625 L20.25,18.0625 C20.077411,18.0625 19.9375,17.922589 19.9375,17.75 L19.9375,16.5 C19.9375,15.982233 19.517767,15.5625 19,15.5625 C18.482233,15.5625 18.0625,15.982233 18.0625,16.5 L18.0625,17.75 C18.0625,17.922589 17.922589,18.0625 17.75,18.0625 L16.5,18.0625 C15.982233,18.0625 15.5625,18.482233 15.5625,19 C15.5625,19.517767 15.982233,19.9375 16.5,19.9375 L17.75,19.9375 C17.922589,19.9375 18.0625,20.077411 18.0625,20.25 L18.0625,21.5 C18.0625,22.017767 18.482233,22.4375 19,22.4375 C19.517767,22.4375 19.9375,22.017767 19.9375,21.5 L19.9375,20.25 C19.9375,20.077411 20.077411,19.9375 20.25,19.9375 L21.5,19.9375 Z M5,2 C3.34314575,2 2,3.34314575 2,5 C2,6.65685425 3.34314575,8 5,8 L19,8 C20.6568542,8 22,6.65685425 22,5 C22,3.34314575 20.6568542,2 19,2 L5,2 Z M5,0 L19,0 C21.7614237,-5.07265313e-16 24,2.23857625 24,5 C24,7.76142375 21.7614237,10 19,10 L5,10 C2.23857625,10 3.38176876e-16,7.76142375 0,5 C-1.2263553e-15,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>text-bold</title><path d="M17.194,10.962A6.271,6.271,0,0,0,12.844.248H4.3a1.25,1.25,0,0,0,0,2.5H5.313a.25.25,0,0,1,.25.25V21a.25.25,0,0,1-.25.25H4.3a1.25,1.25,0,1,0,0,2.5h9.963a6.742,6.742,0,0,0,2.93-12.786Zm-4.35-8.214a3.762,3.762,0,0,1,0,7.523H8.313a.25.25,0,0,1-.25-.25V3a.25.25,0,0,1,.25-.25Zm1.42,18.5H8.313a.25.25,0,0,1-.25-.25V13.021a.25.25,0,0,1,.25-.25h4.531c.017,0,.033,0,.049,0l.013,0h1.358a4.239,4.239,0,0,1,0,8.477Z"/></svg>

After

Width:  |  Height:  |  Size: 505 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>checklist-alternate</title><path d="M21,0H3A3,3,0,0,0,0,3V21a3,3,0,0,0,3,3H21a3,3,0,0,0,3-3V3A3,3,0,0,0,21,0Zm1,21a1,1,0,0,1-1,1H3a1,1,0,0,1-1-1V3A1,1,0,0,1,3,2H21a1,1,0,0,1,1,1Z"/><path d="M11.249,4.5a1.251,1.251,0,0,0-1.75.25L7.365,7.6l-.482-.481A1.25,1.25,0,0,0,5.116,8.883l1.5,1.5A1.262,1.262,0,0,0,8.5,10.249l3-4A1.25,1.25,0,0,0,11.249,4.5Z"/><path d="M11.249,13.5a1.251,1.251,0,0,0-1.75.25L7.365,16.6l-.482-.481a1.25,1.25,0,1,0-1.767,1.768l1.5,1.5A1.265,1.265,0,0,0,8.5,19.249l3-4A1.25,1.25,0,0,0,11.249,13.5Z"/><path d="M18.5,7.749H14a1.25,1.25,0,0,0,0,2.5h4.5a1.25,1.25,0,0,0,0-2.5Z"/><path d="M18.5,15.749H14a1.25,1.25,0,0,0,0,2.5h4.5a1.25,1.25,0,1,0,0-2.5Z"/></svg>

After

Width:  |  Height:  |  Size: 743 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>angle-brackets</title><path d="M9.147,21.552a1.244,1.244,0,0,1-.895-.378L.84,13.561a2.257,2.257,0,0,1,0-3.125L8.252,2.823a1.25,1.25,0,0,1,1.791,1.744l-6.9,7.083a.5.5,0,0,0,0,.7l6.9,7.082a1.25,1.25,0,0,1-.9,2.122Z"/><path d="M14.854,21.552a1.25,1.25,0,0,1-.9-2.122l6.9-7.083a.5.5,0,0,0,0-.7l-6.9-7.082a1.25,1.25,0,0,1,1.791-1.744l7.411,7.612a2.257,2.257,0,0,1,0,3.125l-7.412,7.614A1.244,1.244,0,0,1,14.854,21.552Zm6.514-9.373h0Z"/></svg>

After

Width:  |  Height:  |  Size: 504 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M2,19 C2,20.6568542 3.34314575,22 5,22 L19,22 C20.6568542,22 22,20.6568542 22,19 L22,5 C22,3.34314575 20.6568542,2 19,2 L5,2 C3.34314575,2 2,3.34314575 2,5 L2,19 Z M-1.16403344e-15,19 L-3.0678068e-16,5 C-6.44957556e-16,2.23857625 2.23857625,0 5,0 L19,0 C21.7614237,0 24,2.23857625 24,5 L24,19 C24,21.7614237 21.7614237,24 19,24 L5,24 C2.23857625,24 9.50500275e-16,21.7614237 -1.16403344e-15,19 Z M12,10 C12.5522847,10 13,10.4477153 13,11 L13,13 C13,13.5522847 12.5522847,14 12,14 C11.4477153,14 11,13.5522847 11,13 L11,11 C11,10.4477153 11.4477153,10 12,10 Z M12,16 C12.5522847,16 13,16.4477153 13,17 L13,20 C13,20.5522847 12.5522847,21 12,21 C11.4477153,21 11,20.5522847 11,20 L11,17 C11,16.4477153 11.4477153,16 12,16 Z M12,3 C12.5522847,3 13,3.44771525 13,4 L13,7 C13,7.55228475 12.5522847,8 12,8 C11.4477153,8 11,7.55228475 11,7 L11,4 C11,3.44771525 11.4477153,3 12,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 979 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12.6414391,21.9312708 C12.9358807,22.5689168 13.3234155,23.1547532 13.7866134,23.6713497 C13.2317936,23.8836754 12.6294813,24 12,24 C9.23857625,24 7,21.7614237 7,19 L7,5 C7,2.23857625 9.23857625,0 12,0 C14.7614237,0 17,2.23857625 17,5 L17,12.2898787 C16.2775651,12.5048858 15.6040072,12.8333806 15,13.2546893 L15,5 C15,3.34314575 13.6568542,2 12,2 C10.3431458,2 9,3.34314575 9,5 L9,19 C9,20.6568542 10.3431458,22 12,22 C12.220157,22 12.4347751,21.9762852 12.6414391,21.9312708 Z M19,14 C21.7600532,14.0033061 23.9966939,16.2399468 24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 C14,16.2385763 16.2385763,14 19,14 Z M16.5,19.9375 L21.5,19.9375 C22.017767,19.9375 22.4375,19.517767 22.4375,19 C22.4375,18.482233 22.017767,18.0625 21.5,18.0625 L16.5,18.0625 C15.982233,18.0625 15.5625,18.482233 15.5625,19 C15.5625,19.517767 15.982233,19.9375 16.5,19.9375 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 990 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M13.2546893,15 C12.8333806,15.6040072 12.5048858,16.2775651 12.2898787,17 L5,17 C2.23857625,17 3.38176876e-16,14.7614237 0,12 C-1.2263553e-15,9.23857625 2.23857625,7 5,7 L19,7 C21.7614237,7 24,9.23857625 24,12 C24,12.6294813 23.8836754,13.2317936 23.6713497,13.7866134 C23.1547532,13.3234155 22.5689168,12.9358807 21.9312708,12.6414391 C21.9762852,12.4347751 22,12.220157 22,12 C22,10.3431458 20.6568542,9 19,9 L5,9 C3.34314575,9 2,10.3431458 2,12 C2,13.6568542 3.34314575,15 5,15 L13.2546893,15 Z M19,14 C21.7600532,14.0033061 23.9966939,16.2399468 24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 C14,16.2385763 16.2385763,14 19,14 Z M16.5,19.9375 L21.5,19.9375 C22.017767,19.9375 22.4375,19.517767 22.4375,19 C22.4375,18.482233 22.017767,18.0625 21.5,18.0625 L16.5,18.0625 C15.982233,18.0625 15.5625,18.482233 15.5625,19 C15.5625,19.517767 15.982233,19.9375 16.5,19.9375 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1,008 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19,14 C21.7600532,14.0033061 23.9966939,16.2399468 24,19 C24,21.7614237 21.7614237,24 19,24 C16.2385763,24 14,21.7614237 14,19 C14,16.2385763 16.2385763,14 19,14 Z M16.5,19.9375 L21.5,19.9375 C22.017767,19.9375 22.4375,19.517767 22.4375,19 C22.4375,18.482233 22.017767,18.0625 21.5,18.0625 L16.5,18.0625 C15.982233,18.0625 15.5625,18.482233 15.5625,19 C15.5625,19.517767 15.982233,19.9375 16.5,19.9375 Z M12.2898787,17 L9,17 L9,22 L12.6736312,22 C13.0297295,22.7496048 13.515133,23.4258795 14.1010173,24 L5,24 C2.23857625,24 -1.43817996e-15,21.7614237 -1.77635684e-15,19 L-3.55271368e-15,5 C-3.89089055e-15,2.23857625 2.23857625,5.07265313e-16 5,-1.77635684e-15 L19,-1.77635684e-15 C21.7614237,-2.28362215e-15 24,2.23857625 24,5 L24,7.82313285 C24.0122947,7.88054124 24.0187107,7.93964623 24.0187107,8 C24.0187107,8.06035377 24.0122947,8.11945876 24,8.17686715 L24,14.1010173 C23.4258795,13.515133 22.7496048,13.0297295 22,12.6736312 L22,9 L17,9 L17,12.2898787 C16.2775651,12.5048858 15.6040072,12.8333806 15,13.2546893 L15,9 L9,9 L9,15 L13.2546893,15 C12.8333806,15.6040072 12.5048858,16.2775651 12.2898787,17 Z M17,7 L22,7 L22,5 C22,3.34314575 20.6568542,2 19,2 L17,2 L17,7 Z M15,7 L15,2 L9,2 L9,7 L15,7 Z M7,2 L5,2 C3.34314575,2 2,3.34314575 2,5 L2,7 L7,7 L7,2 Z M2,9 L2,15 L7,15 L7,9 L2,9 Z M2,17 L2,19 C2,20.6568542 3.34314575,22 5,22 L7,22 L7,17 L2,17 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M11.999,0.5 C5.649,0.5 0.5,5.648 0.5,12 C0.5,17.082 3.794,21.392 8.365,22.914 C8.939,23.017 9.121,22.678 9.121,22.373 C9.121,22.099 9.127,21.336 9.121,20.376 C5.923,21.07 5.26,18.861 5.26,18.861 C4.737,17.532 3.985,17.179 3.985,17.179 C2.94,16.465 4.062,16.48 4.062,16.48 C5.215,16.56 5.824,17.664 5.824,17.664 C6.85,19.422 8.515,18.914 9.17,18.62 C9.276,17.878 9.572,17.369 9.901,17.084 C7.347,16.792 4.663,15.807 4.663,11.398 C4.663,10.143 5.111,9.117 5.847,8.312 C5.729,8.023 5.333,6.852 5.959,5.269 C5.959,5.269 6.926,4.96 9.121,6.449 C10.039,6.193 11.023,6.066 12.001,6.061 C12.977,6.066 13.961,6.193 14.881,6.449 C17.076,4.961 18.04,5.269 18.04,5.269 C18.667,6.852 18.272,8.023 18.154,8.312 C18.89,9.117 19.337,10.143 19.337,11.398 C19.337,15.818 16.648,16.789 14.086,17.072 C14.498,17.429 14.873,18.119 14.873,19.192 C14.873,20.63 14.873,21.998 14.873,22.376 C14.873,22.684 15.059,23.023 15.643,22.912 C20.209,21.389 23.5,17.08 23.5,12 C23.5,5.648 18.352,0.5 11.999,0.5 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M5,13 C4.44771525,13 4,12.5522847 4,12 C4,11.4477153 4.44771525,11 5,11 L19,11 C19.5522847,11 20,11.4477153 20,12 C20,12.5522847 19.5522847,13 19,13 L5,13 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 262 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>paginate-filter-picture-alternate</title><circle cx="9.75" cy="6.247" r="2.25"/><path d="M16.916,8.71A1.027,1.027,0,0,0,16,8.158a1.007,1.007,0,0,0-.892.586L13.55,12.178a.249.249,0,0,1-.422.053l-.82-1.024a1,1,0,0,0-.813-.376,1.007,1.007,0,0,0-.787.426L7.59,15.71A.5.5,0,0,0,8,16.5H20a.5.5,0,0,0,.425-.237.5.5,0,0,0,.022-.486Z"/><path d="M22,0H5.5a2,2,0,0,0-2,2V18.5a2,2,0,0,0,2,2H22a2,2,0,0,0,2-2V2A2,2,0,0,0,22,0Zm-.145,18.354a.5.5,0,0,1-.354.146H6a.5.5,0,0,1-.5-.5V2.5A.5.5,0,0,1,6,2H21.5a.5.5,0,0,1,.5.5V18A.5.5,0,0,1,21.855,18.351Z"/><path d="M19.5,22H2.5a.5.5,0,0,1-.5-.5V4.5a1,1,0,0,0-2,0V22a2,2,0,0,0,2,2H19.5a1,1,0,0,0,0-2Z"/></svg>

After

Width:  |  Height:  |  Size: 707 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>text-italic</title><path d="M22.5.248H14.863a1.25,1.25,0,0,0,0,2.5h1.086a.25.25,0,0,1,.211.384L4.78,21.017a.5.5,0,0,1-.422.231H1.5a1.25,1.25,0,0,0,0,2.5H9.137a1.25,1.25,0,0,0,0-2.5H8.051a.25.25,0,0,1-.211-.384L19.22,2.98a.5.5,0,0,1,.422-.232H22.5a1.25,1.25,0,0,0,0-2.5Z"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>hyperlink-2</title><path d="M12.406,14.905a1,1,0,0,0-.543,1.307,1,1,0,0,1-.217,1.09L8.818,20.131a2,2,0,0,1-2.828,0L3.868,18.01a2,2,0,0,1,0-2.829L6.7,12.353a1.013,1.013,0,0,1,1.091-.217,1,1,0,0,0,.763-1.849,3.034,3.034,0,0,0-3.268.652L2.454,13.767a4.006,4.006,0,0,0,0,5.657l2.122,2.121a4,4,0,0,0,5.656,0l2.829-2.828a3.008,3.008,0,0,0,.651-3.27A1,1,0,0,0,12.406,14.905Z"/><path d="M7.757,16.241a1.011,1.011,0,0,0,1.414,0L16.95,8.463a1,1,0,0,0-1.414-1.414L7.757,14.827A1,1,0,0,0,7.757,16.241Z"/><path d="M21.546,4.574,19.425,2.453a4.006,4.006,0,0,0-5.657,0L10.939,5.281a3.006,3.006,0,0,0-.651,3.269,1,1,0,1,0,1.849-.764A1,1,0,0,1,12.354,6.7l2.828-2.828a2,2,0,0,1,2.829,0l2.121,2.121a2,2,0,0,1,0,2.829L17.3,11.645a1.015,1.015,0,0,1-1.091.217,1,1,0,0,0-.765,1.849,3.026,3.026,0,0,0,3.27-.651l2.828-2.828A4.007,4.007,0,0,0,21.546,4.574Z"/></svg>

After

Width:  |  Height:  |  Size: 907 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>read-email-at-alternate</title><path d="M12,.5A11.634,11.634,0,0,0,.262,12,11.634,11.634,0,0,0,12,23.5a11.836,11.836,0,0,0,6.624-2,1.25,1.25,0,1,0-1.393-2.076A9.34,9.34,0,0,1,12,21a9.132,9.132,0,0,1-9.238-9A9.132,9.132,0,0,1,12,3a9.132,9.132,0,0,1,9.238,9v.891a1.943,1.943,0,0,1-3.884,0V12A5.355,5.355,0,1,0,12,17.261a5.376,5.376,0,0,0,3.861-1.634,4.438,4.438,0,0,0,7.877-2.736V12A11.634,11.634,0,0,0,12,.5Zm0,14.261A2.763,2.763,0,1,1,14.854,12,2.812,2.812,0,0,1,12,14.761Z"/></svg>

After

Width:  |  Height:  |  Size: 549 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>list-numbers</title><path d="M7.75,4.5h15a1,1,0,0,0,0-2h-15a1,1,0,0,0,0,2Z"/><path d="M22.75,11h-15a1,1,0,1,0,0,2h15a1,1,0,0,0,0-2Z"/><path d="M22.75,19.5h-15a1,1,0,0,0,0,2h15a1,1,0,0,0,0-2Z"/><path d="M2.212,17.248A2,2,0,0,0,.279,18.732a.75.75,0,1,0,1.45.386.5.5,0,1,1,.483.63.75.75,0,1,0,0,1.5.5.5,0,1,1-.482.635.75.75,0,1,0-1.445.4,2,2,0,1,0,3.589-1.648.251.251,0,0,1,0-.278,2,2,0,0,0-1.662-3.111Z"/><path d="M4.25,10.748a2,2,0,0,0-4,0,.75.75,0,0,0,1.5,0,.5.5,0,0,1,1,0,1.031,1.031,0,0,1-.227.645L.414,14.029A.75.75,0,0,0,1,15.248H3.5a.75.75,0,0,0,0-1.5H3.081a.249.249,0,0,1-.195-.406L3.7,12.33A2.544,2.544,0,0,0,4.25,10.748Z"/><path d="M4,5.248H3.75A.25.25,0,0,1,3.5,5V1.623A1.377,1.377,0,0,0,2.125.248H1.5a.75.75,0,0,0,0,1.5h.25A.25.25,0,0,1,2,2V5a.25.25,0,0,1-.25.25H1.5a.75.75,0,0,0,0,1.5H4a.75.75,0,0,0,0-1.5Z"/></svg>

After

Width:  |  Height:  |  Size: 894 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>paragraph</title><path d="M22.5.248H7.228a6.977,6.977,0,1,0,0,13.954H9.546a.25.25,0,0,1,.25.25V22.5a1.25,1.25,0,0,0,2.5,0V3a.25.25,0,0,1,.25-.25h3.682a.25.25,0,0,1,.25.25V22.5a1.25,1.25,0,0,0,2.5,0V3a.249.249,0,0,1,.25-.25H22.5a1.25,1.25,0,0,0,0-2.5ZM9.8,11.452a.25.25,0,0,1-.25.25H7.228a4.477,4.477,0,1,1,0-8.954H9.546A.25.25,0,0,1,9.8,3Z"/></svg>

After

Width:  |  Height:  |  Size: 416 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>close-quote</title><path d="M18.559,3.932a4.942,4.942,0,1,0,0,9.883,4.609,4.609,0,0,0,1.115-.141.25.25,0,0,1,.276.368,6.83,6.83,0,0,1-5.878,3.523,1.25,1.25,0,0,0,0,2.5,9.71,9.71,0,0,0,9.428-9.95V8.873A4.947,4.947,0,0,0,18.559,3.932Z"/><path d="M6.236,3.932a4.942,4.942,0,0,0,0,9.883,4.6,4.6,0,0,0,1.115-.141.25.25,0,0,1,.277.368A6.83,6.83,0,0,1,1.75,17.565a1.25,1.25,0,0,0,0,2.5,9.711,9.711,0,0,0,9.428-9.95V8.873A4.947,4.947,0,0,0,6.236,3.932Z"/></svg>

After

Width:  |  Height:  |  Size: 521 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>redo</title><path d="M22.608.161a.5.5,0,0,0-.545.108L19.472,2.86a.25.25,0,0,1-.292.045A12.537,12.537,0,0,0,6.214,3.77,12.259,12.259,0,0,0,6.1,23.632a1.25,1.25,0,0,0,1.476-2.018A9.759,9.759,0,0,1,7.667,5.805a10,10,0,0,1,9.466-1.1.25.25,0,0,1,.084.409l-1.85,1.85a.5.5,0,0,0,.354.853h6.7a.5.5,0,0,0,.5-.5V.623A.5.5,0,0,0,22.608.161Z"/></svg>

After

Width:  |  Height:  |  Size: 406 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>delete-2-alternate</title><path d="M20.485,3.511A12.01,12.01,0,1,0,24,12,12.009,12.009,0,0,0,20.485,3.511Zm-1.767,15.21A9.51,9.51,0,1,1,21.5,12,9.508,9.508,0,0,1,18.718,18.721Z"/><path d="M16.987,7.01a1.275,1.275,0,0,0-1.8,0l-3.177,3.177L8.829,7.01A1.277,1.277,0,0,0,7.024,8.816L10.2,11.993,7.024,15.171a1.277,1.277,0,0,0,1.805,1.806L12.005,13.8l3.177,3.178a1.277,1.277,0,0,0,1.8-1.806l-3.176-3.178,3.176-3.177A1.278,1.278,0,0,0,16.987,7.01Z"/></svg>

After

Width:  |  Height:  |  Size: 518 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>text-strike-through</title><path d="M23.75,12.952A1.25,1.25,0,0,0,22.5,11.7H13.564a.492.492,0,0,1-.282-.09c-.722-.513-1.482-.981-2.218-1.432-2.8-1.715-4.5-2.9-4.5-4.863,0-2.235,2.207-2.569,3.523-2.569a4.54,4.54,0,0,1,3.081.764A2.662,2.662,0,0,1,13.615,5.5l0,.3a1.25,1.25,0,1,0,2.5,0l0-.268A4.887,4.887,0,0,0,14.95,1.755C13.949.741,12.359.248,10.091.248c-3.658,0-6.023,1.989-6.023,5.069,0,2.773,1.892,4.512,4,5.927a.25.25,0,0,1-.139.458H1.5a1.25,1.25,0,0,0,0,2.5H12.477a.251.251,0,0,1,.159.058,4.339,4.339,0,0,1,1.932,3.466c0,3.268-3.426,3.522-4.477,3.522-1.814,0-3.139-.405-3.834-1.173a3.394,3.394,0,0,1-.65-2.7,1.25,1.25,0,0,0-2.488-.246A5.76,5.76,0,0,0,4.4,21.753c1.2,1.324,3.114,2,5.688,2,4.174,0,6.977-2.42,6.977-6.022a6.059,6.059,0,0,0-.849-3.147.25.25,0,0,1,.216-.377H22.5A1.25,1.25,0,0,0,23.75,12.952Z"/></svg>

After

Width:  |  Height:  |  Size: 885 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M17,17 L17,22 L19,22 C20.6568542,22 22,20.6568542 22,19 L22,17 L17,17 Z M15,17 L9,17 L9,22 L15,22 L15,17 Z M17,15 L22,15 L22,9 L17,9 L17,15 Z M15,15 L15,9 L9,9 L9,15 L15,15 Z M17,7 L22,7 L22,5 C22,3.34314575 20.6568542,2 19,2 L17,2 L17,7 Z M15,7 L15,2 L9,2 L9,7 L15,7 Z M24,16.1768671 L24,19 C24,21.7614237 21.7614237,24 19,24 L5,24 C2.23857625,24 2.11453371e-15,21.7614237 1.77635684e-15,19 L0,5 C-3.38176876e-16,2.23857625 2.23857625,2.28362215e-15 5,0 L19,0 C21.7614237,-5.07265313e-16 24,2.23857625 24,5 L24,7.82313285 C24.0122947,7.88054124 24.0187107,7.93964623 24.0187107,8 C24.0187107,8.06035377 24.0122947,8.11945876 24,8.17686715 L24,15.8231329 C24.0122947,15.8805412 24.0187107,15.9396462 24.0187107,16 C24.0187107,16.0603538 24.0122947,16.1194588 24,16.1768671 Z M7,2 L5,2 C3.34314575,2 2,3.34314575 2,5 L2,7 L7,7 L7,2 Z M2,9 L2,15 L7,15 L7,9 L2,9 Z M2,17 L2,19 C2,20.6568542 3.34314575,22 5,22 L7,22 L7,17 L2,17 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>list-bullets</title><circle cx="2.5" cy="3.998" r="2.5"/><path d="M8.5,5H23a1,1,0,0,0,0-2H8.5a1,1,0,0,0,0,2Z"/><circle cx="2.5" cy="11.998" r="2.5"/><path d="M23,11H8.5a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/><circle cx="2.5" cy="19.998" r="2.5"/><path d="M23,19H8.5a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/></svg>

After

Width:  |  Height:  |  Size: 369 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>text-underline</title><path d="M22.5,21.248H1.5a1.25,1.25,0,0,0,0,2.5h21a1.25,1.25,0,0,0,0-2.5Z"/><path d="M1.978,2.748H3.341a.25.25,0,0,1,.25.25v8.523a8.409,8.409,0,0,0,16.818,0V3a.25.25,0,0,1,.25-.25h1.363a1.25,1.25,0,0,0,0-2.5H16.3a1.25,1.25,0,0,0,0,2.5h1.363a.25.25,0,0,1,.25.25v8.523a5.909,5.909,0,0,1-11.818,0V3a.25.25,0,0,1,.25-.25H7.7a1.25,1.25,0,1,0,0-2.5H1.978a1.25,1.25,0,0,0,0,2.5Z"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>undo</title><path d="M17.786,3.77A12.542,12.542,0,0,0,4.821,2.905a.249.249,0,0,1-.292-.045L1.937.269A.507.507,0,0,0,1.392.16a.5.5,0,0,0-.308.462v6.7a.5.5,0,0,0,.5.5h6.7a.5.5,0,0,0,.354-.854L6.783,5.115a.253.253,0,0,1-.068-.228.249.249,0,0,1,.152-.181,10,10,0,0,1,9.466,1.1,9.759,9.759,0,0,1,.094,15.809A1.25,1.25,0,0,0,17.9,23.631a12.122,12.122,0,0,0,5.013-9.961A12.125,12.125,0,0,0,17.786,3.77Z"/></svg>

After

Width:  |  Height:  |  Size: 472 B

View file

@ -65,10 +65,24 @@ export default {
externalLink: 'External Link', externalLink: 'External Link',
users: 'Users', users: 'Users',
reports: 'Reports', reports: 'Reports',
invites: 'Invites',
statuses: 'Statuses',
settings: 'Settings', settings: 'Settings',
moderationLog: 'Moderation Log', moderationLog: 'Moderation Log',
relays: 'Relays',
mediaProxyCache: 'MediaProxy Cache',
'emoji-packs': 'Emoji packs' 'emoji-packs': 'Emoji packs'
}, },
errLog: {
error401: 'Oops! 401 Error',
error404: 'Oops! 404 Error',
pageNotFound: 'Page not found',
correctUrl: 'Please make sure you URL is correct',
unauth: 'Unauthorized',
back: 'Back',
login: 'Login',
homePage: 'Home Page'
},
navbar: { navbar: {
logOut: 'Log Out', logOut: 'Log Out',
dashboard: 'Dashboard', dashboard: 'Dashboard',
@ -82,13 +96,30 @@ export default {
logInViaPleromaFE: 'Log in via PleromaFE', logInViaPleromaFE: 'Log in via PleromaFE',
username: 'username@host', username: 'username@host',
password: 'password', password: 'password',
omitHostname: 'omit hostname if Pleroma is located on this domain', omitHostname: 'Omit hostname if Pleroma is located on this domain',
errorMessage: 'Username must contain username and host, e.g. john@pleroma.social', errorMessage: 'Username must contain username and host, e.g. john@pleroma.social',
any: 'any', any: 'any',
thirdparty: 'Or connect with', thirdparty: 'Or connect with',
pleromaFELoginFailed: 'Failed to login via PleromaFE, please login with username/password', pleromaFELoginFailed: 'Failed to login via PleromaFE, please login with username/password',
pleromaFELoginSucceed: 'Logged in via PleromaFE' pleromaFELoginSucceed: 'Logged in via PleromaFE'
}, },
mediaProxyCache: {
mediaProxyCache: 'MediaProxy Cache',
ban: 'Ban',
url: 'URL',
evict: 'Evict',
evictedMessage: 'This URL was evicted',
actions: 'Actions',
remove: 'Remove from Cachex',
evictObjectsHeader: 'Evict object from the MediaProxy cache',
listBannedUrlsHeader: 'List of all banned MediaProxy URLs',
multipleInput: 'You can enter a single URL or several comma separated links',
removeSelected: 'Remove Selected',
enable: 'Enable',
invalidationAndMediaProxy: 'MediaProxy and Invalidation to evict and ban MediaProxy objects',
confirmEnablingMediaProxy: 'Are you sure you want to enable Media Proxy and Media Cache object Invalidation?',
enableMediaProxySuccessMessage: 'Media Proxy and Media Cache object Invalidation were enabled'
},
documentation: { documentation: {
documentation: 'Documentation', documentation: 'Documentation',
github: 'Github Repository' github: 'Github Repository'
@ -134,12 +165,8 @@ export default {
draft: 'Draft', draft: 'Draft',
delete: 'Delete', delete: 'Delete',
cancel: 'Cancel', cancel: 'Cancel',
confirm: 'Confirm' confirm: 'Confirm',
}, unfollow: 'Unfollow'
errorLog: {
tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
documentation: 'Document introduction'
}, },
excel: { excel: {
export: 'Export', export: 'Export',
@ -171,16 +198,17 @@ export default {
id: 'ID', id: 'ID',
name: 'Name', name: 'Name',
status: 'Status', status: 'Status',
local: 'local', local: 'Local',
external: 'external', external: 'External',
deactivated: 'deactivated', deactivated: 'Deactivated',
active: 'active', active: 'Active',
unconfirmed: 'unconfirmed', unapproved: 'Pending',
unconfirmed: 'Unconfirmed',
actions: 'Actions', actions: 'Actions',
activate: 'Activate', activate: 'Activate',
deactivate: 'Deactivate', deactivate: 'Deactivate',
admin: 'admin', admin: 'Admin',
moderator: 'moderator', moderator: 'Moderator',
moderation: 'Moderation', moderation: 'Moderation',
revokeAdmin: 'Revoke Admin', revokeAdmin: 'Revoke Admin',
grantAdmin: 'Grant Admin', grantAdmin: 'Grant Admin',
@ -201,20 +229,25 @@ export default {
disableAnySubscription: 'Disallow following user at all', disableAnySubscription: 'Disallow following user at all',
disableAnySubscriptionForMultiple: 'Disallow following users at all', disableAnySubscriptionForMultiple: 'Disallow following users at all',
requirePasswordReset: 'Require password reset on next login', requirePasswordReset: 'Require password reset on next login',
disableMfa: 'Disable multi-factor authentication',
selectUsers: 'Select users to apply actions to multiple users', selectUsers: 'Select users to apply actions to multiple users',
moderateUser: 'Moderate user', moderateUser: 'Moderate user',
moderateUsers: 'Moderate multiple users', moderateUsers: 'Moderate multiple users',
createAccount: 'Create new account', createAccount: 'Create new account',
apply: 'apply', apply: 'Apply',
remove: 'remove', remove: 'Remove',
grantRightConfirmation: 'Are you sure you want to grant {right} rights to all selected users?', grantRightConfirmation: 'Are you sure you want to grant {right} rights to all selected users?',
revokeRightConfirmation: 'Are you sure you want to revoke {right} rights from all selected users?', revokeRightConfirmation: 'Are you sure you want to revoke {right} rights from all selected users?',
activateMultipleUsersConfirmation: 'Are you sure you want to activate accounts of all selected users?', activateMultipleUsersConfirmation: 'Are you sure you want to activate accounts of all selected users?',
deactivateMultipleUsersConfirmation: 'Are you sure you want to deactivate accounts of all selected users?', deactivateMultipleUsersConfirmation: 'Are you sure you want to deactivate accounts of all selected users?',
deleteMultipleUsersConfirmation: 'Are you sure you want to delete accounts of all selected users?', deleteUserConfirmation: 'Are you sure you want to delete this account? This action cannot be undone.',
rejectAccountConfirmation: 'Are you sure you want to reject this account? This account will be deleted and it cannot be undone.',
deleteMultipleUsersConfirmation: 'Are you sure you want to delete accounts of all selected users? This action cannot be undone.',
addTagForMultipleUsersConfirmation: 'Are you sure you want to apply tag to all selected users?', addTagForMultipleUsersConfirmation: 'Are you sure you want to apply tag to all selected users?',
removeTagFromMultipleUsersConfirmation: 'Are you sure you want to remove tag from all selected users?', removeTagFromMultipleUsersConfirmation: 'Are you sure you want to remove tag from all selected users?',
requirePasswordResetConfirmation: 'Are you sure you want to require password reset for all selected users?', requirePasswordResetConfirmation: 'Are you sure you want to require password reset for all selected users?',
approveAccountsConfirmation: 'Are you sure you want to approve accounts for all selected users?',
rejectAccountsConfirmation: 'Are you sure you want to reject accounts for all selected users? These accounts will be deleted and it cannot be undone.',
confirmAccountsConfirmation: 'Are you sure you want to confirm emails for all selected users?', confirmAccountsConfirmation: 'Are you sure you want to confirm emails for all selected users?',
resendEmailConfirmation: 'Are you sure you want to resend confirmation email for all selected users?', resendEmailConfirmation: 'Are you sure you want to resend confirmation email for all selected users?',
mailerMustBeEnabled: 'To require user\'s password reset you must enable mailer.', mailerMustBeEnabled: 'To require user\'s password reset you must enable mailer.',
@ -235,10 +268,25 @@ export default {
getPasswordResetToken: 'Get password reset token', getPasswordResetToken: 'Get password reset token',
passwordResetTokenCreated: 'Password reset token was created', passwordResetTokenCreated: 'Password reset token was created',
accountCreated: 'New account was created!', accountCreated: 'New account was created!',
approveAccount: 'Approve account',
approveAccounts: 'Approve accounts',
unapprovedAccount: 'User account is pending approval',
unconfirmedEmail: 'User didn\'t confirm the email', unconfirmedEmail: 'User didn\'t confirm the email',
confirmAccount: 'Confirm account', confirmAccount: 'Confirm account',
confirmAccounts: 'Confirm accounts', confirmAccounts: 'Confirm accounts',
resendConfirmation: 'Resend confirmation email' rejectAccount: 'Reject account',
rejectAccounts: 'Reject accounts',
resendConfirmation: 'Resend confirmation email',
invalidAccount: 'This account has invalid nickname and can\'t be modified',
invalidNickname: 'invalid nickname',
passwordResetTokenGenerated: 'Password reset token was generated:',
linkToResetPassword: 'You can also use this link to reset password:',
registrationReason: 'Registration Reason',
service: 'Service',
person: 'Person',
enableTagPolicy: 'Enable MRF TagPolicy to manage user tags',
confirmEnablingTagPolicy: 'Are you sure you want to add TagPolicy to the list of enabled MRF policies?',
enableTagPolicySuccessMessage: 'MRF TagPolicy was enabled'
}, },
statuses: { statuses: {
statuses: 'Statuses', statuses: 'Statuses',
@ -250,22 +298,28 @@ export default {
direct: 'Direct', direct: 'Direct',
private: 'Private', private: 'Private',
public: 'Public', public: 'Public',
unlisted: 'Unlisted' unlisted: 'Unlisted',
openStatusInInstance: 'Open status in instance'
}, },
userProfile: { userProfile: {
tags: 'Tags', tags: 'Tags',
moderator: 'Moderator', moderator: 'Moderator',
admin: 'Admin', admin: 'Admin',
local: 'local', local: 'Local',
external: 'external', external: 'External',
localUppercase: 'Local', accountType: 'Account Type',
actorType: 'Actor Type',
nickname: 'Nickname', nickname: 'Nickname',
recentStatuses: 'Recent Statuses', recentStatuses: 'Recent Statuses',
roles: 'Roles', roles: 'Roles',
activeUppercase: 'Active', active: 'Active',
active: 'active', status: 'Status',
deactivated: 'deactivated', reason: 'Registration Reason',
deactivated: 'Deactivated',
pending: 'Pending',
noStatuses: 'No statuses to show', noStatuses: 'No statuses to show',
noMessages: 'No messages to show',
openAccountInInstance: 'Open account in instance',
securitySettings: { securitySettings: {
email: 'Email', email: 'Email',
password: 'Password', password: 'Password',
@ -284,15 +338,22 @@ export default {
}, },
usersFilter: { usersFilter: {
inputPlaceholder: 'Select filter', inputPlaceholder: 'Select filter',
byUserType: 'By user type', byAccountType: 'By account type',
byActorType: 'By actor type',
local: 'Local', local: 'Local',
external: 'External', external: 'External',
byStatus: 'By status', byStatus: 'By status',
active: 'Active', active: 'Active',
deactivated: 'Deactivated' pending: 'Pending Approval',
deactivated: 'Deactivated',
unconfirmed: 'Unconfirmed',
person: 'Person',
bot: 'Bot',
application: 'Application'
}, },
reports: { reports: {
reports: 'Reports', reports: 'Reports',
report: 'Report',
reply: 'Reply', reply: 'Reply',
from: 'From', from: 'From',
showNotes: 'Show notes', showNotes: 'Show notes',
@ -321,6 +382,7 @@ export default {
unlisted: 'Make status unlisted', unlisted: 'Make status unlisted',
sensitive: 'Sensitive', sensitive: 'Sensitive',
deleteStatus: 'Delete status', deleteStatus: 'Delete status',
deleteMessage: 'Delete message',
reportOn: 'Report on', reportOn: 'Report on',
reportsOn: 'Reports on', reportsOn: 'Reports on',
id: 'ID', id: 'ID',
@ -330,9 +392,12 @@ export default {
content: 'Content', content: 'Content',
reportedStatus: 'Reported status', reportedStatus: 'Reported status',
statusDeleted: 'This status has been deleted', statusDeleted: 'This status has been deleted',
messageDeleted: 'This message has been deleted',
messageModeration: 'Message options',
leaveNote: 'Leave a note', leaveNote: 'Leave a note',
postNote: 'Send', postNote: 'Send',
deleteNote: 'Delete' deleteNote: 'Delete',
notFound: 'account not found'
}, },
reportsFilter: { reportsFilter: {
inputPlaceholder: 'Select filter', inputPlaceholder: 'Select filter',
@ -344,30 +409,27 @@ export default {
moderationLog: 'Moderation Log' moderationLog: 'Moderation Log'
}, },
settings: { settings: {
submit: 'Submit',
settings: 'Settings', settings: 'Settings',
instance: 'Instance', instance: 'Instance',
search: 'Search',
upload: 'Upload', upload: 'Upload',
mailer: 'Mailer', mailer: 'Mailer',
linkFormatter: 'Link Formatter',
logger: 'Logger', logger: 'Logger',
activityPub: 'ActivityPub', activityPub: 'ActivityPub',
auth: 'Authentication', auth: 'Authentication',
autoLinker: 'Auto Linker',
captcha: 'Captcha', captcha: 'Captcha',
emoji: 'Emoji',
frontend: 'Frontend', frontend: 'Frontend',
http: 'HTTP', http: 'HTTP',
mrf: 'MRF', mrf: 'MRF',
mediaProxy: 'Media Proxy', mediaProxy: 'Media Proxy',
metadata: 'Metadata', metadata: 'Metadata',
gopher: 'Gopher',
jobQueue: 'Job queue', jobQueue: 'Job queue',
webPush: 'Web push encryption', webPush: 'Web push encryption',
esshd: 'BBS / SSH access',
rateLimiters: 'Rate limiters', rateLimiters: 'Rate limiters',
other: 'Other', other: 'Other',
relays: 'Relays',
follow: 'Follow',
followRelay: 'Follow new relay',
instanceUrl: 'Instance URL',
success: 'Settings changed successfully!', success: 'Settings changed successfully!',
description: 'Description', description: 'Description',
removeFromDB: 'Remove setting from the DB', removeFromDB: 'Remove setting from the DB',
@ -379,13 +441,44 @@ export default {
files: 'files', files: 'files',
successfullyRemoved: 'Setting removed successfully!', successfullyRemoved: 'Setting removed successfully!',
seeDocs: 'See Documentation', seeDocs: 'See Documentation',
assets: 'Assets', instanceReboot: 'Reboot Instance',
emoji: 'Emoji',
markup: 'Markup settings',
corsPlug: 'CORS plug config',
instanceReboot: 'Instance Reboot',
restartApp: 'You must restart the instance to apply settings', restartApp: 'You must restart the instance to apply settings',
restartSuccess: 'Instance rebooted successfully!' restartSuccess: 'Instance rebooted successfully!',
removeSettingConfirmation: 'Are you sure you want to remove this setting\'s value from the database?',
changeImage: 'Change image',
uploadImage: 'Upload image',
remove: 'Remove',
instancePanel: 'Instance Panel Document',
termsOfServices: 'Terms of Service',
availableFrontends: 'Available Frontends',
installFrontends: 'This is the list of available frontends. You can switch to one of the listed frontends or specify all the required options and install another frontend',
install: 'Install',
installed: 'Installed',
name: 'Name',
git: 'Git',
installAnotherFrontend: 'Install another frontend',
addKeyValuePair: 'Add another `key - value` pair to this icon',
addIconConfig: 'Add another icon configuration',
setLimits: 'Set different limits for unauthenticated and authenticated users',
unauthenticatedUsers: 'Unauthenticated users',
authenticatedUsers: 'Authenticated users',
scale: 'Timespan (ms)',
limit: 'Requests',
setLimitsForAll: 'Set limit for all users',
ref: 'Ref',
file: 'File',
buildUrl: 'Build URL',
buildDir: 'Build Directory',
frontendSuccess: 'Frontend installed successfully!',
frontendStartedInstallation: 'Installation started',
inProcess: 'In process'
},
relays: {
relays: 'Relays',
follow: 'Follow',
followRelay: 'Follow new relay',
followedBack: 'Followed Back',
instanceUrl: 'Instance URL'
}, },
invites: { invites: {
inviteTokens: 'Invite tokens', inviteTokens: 'Invite tokens',
@ -395,6 +488,7 @@ export default {
expiresAt: 'Expires at', expiresAt: 'Expires at',
tokenCreated: 'Invite token was created', tokenCreated: 'Invite token was created',
token: 'Token', token: 'Token',
inviteLink: 'Invite link',
uses: 'Uses', uses: 'Uses',
used: 'Used', used: 'Used',
cancel: 'Cancel', cancel: 'Cancel',
@ -411,7 +505,8 @@ export default {
invalidEmailError: 'Please input valid e-mail', invalidEmailError: 'Please input valid e-mail',
emailSent: 'Invite was sent', emailSent: 'Invite was sent',
submitFormError: 'There are invalid values in the form. Please fix them before continuing.', submitFormError: 'There are invalid values in the form. Please fix them before continuing.',
inviteViaEmailAlert: 'To send invite via email make sure to enable `invites_enabled` and disable `registrations_open`' inviteViaEmailAlert: 'To send invite via email make sure to enable `invites_enabled` and disable `registrations_open`',
copyLink: 'Copy link'
}, },
emoji: { emoji: {
emojiPacks: 'Emoji packs', emojiPacks: 'Emoji packs',
@ -465,6 +560,9 @@ export default {
specifyShortcode: 'Specify a custom shortcode', specifyShortcode: 'Specify a custom shortcode',
specifyFilename: 'Specify a custom filename', specifyFilename: 'Specify a custom filename',
copy: 'Copy', copy: 'Copy',
copyToLocalPack: 'Copy to local pack' copyToLocalPack: 'Copy to local pack',
emptyPack: 'This emoji pack is empty',
emojiWarning: 'Pack names cannot include any of the following characters: # / < > & +',
image: 'Image'
} }
} }

View file

@ -127,11 +127,6 @@ export default {
cancel: 'Cancelar', cancel: 'Cancelar',
confirm: 'Confirmar' confirm: 'Confirmar'
}, },
errorLog: {
tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
documentation: 'Documento de introducción'
},
excel: { excel: {
export: 'Exportar', export: 'Exportar',
selectedExport: 'Exportar seleccionados', selectedExport: 'Exportar seleccionados',

View file

@ -128,11 +128,6 @@ export default {
cancel: 'Anullar', cancel: 'Anullar',
confirm: 'Confirmar' confirm: 'Confirmar'
}, },
errorLog: {
tips: 'Mercés de clicar l’icòna del babau amont a man drecha',
description: 'Ara que lo sistèma de gestion es coma un spa, melhora lexperiéncia dels utilizaire mas aumenta tanben lo risc de problèmas sus la pagina, una pichona negligéncia pòt menar a un blocatge complèt de la pagina. Urosament Vue fornís de manièras per gerir las excepcions, trobar las errors o senhalar las excepcions.',
documentation: 'Presentacion del document'
},
excel: { excel: {
export: 'Exportar', export: 'Exportar',
selectedExport: 'Exportar los elements seleccionats', selectedExport: 'Exportar los elements seleccionats',

View file

@ -127,11 +127,6 @@ export default {
cancel: '取 消', cancel: '取 消',
confirm: '确 定' confirm: '确 定'
}, },
errorLog: {
tips: '请点击右上角bug小图标',
description: '现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。',
documentation: '文档介绍'
},
excel: { excel: {
export: '导出', export: '导出',
selectedExport: '导出已选择项', selectedExport: '导出已选择项',

View file

@ -28,12 +28,17 @@ export const beforeEachRoute = (to, from, next) => {
store.dispatch('GetUserInfo').then(res => { store.dispatch('GetUserInfo').then(res => {
const roles = res.data.pleroma.is_admin ? ['admin'] : [] const roles = res.data.pleroma.is_admin ? ['admin'] : []
store.dispatch('GenerateRoutes', { roles }).then(() => { store.dispatch('GenerateRoutes', { roles }).then(() => {
router.addRoutes(store.getters.addRouters) store.getters.addRouters.forEach(route => router.addRoute(route))
next({ ...to, replace: true }) next({ ...to, replace: true })
}) })
}).catch((err) => { }).catch((err) => {
store.dispatch('FedLogOut').then(() => { store.dispatch('FedLogOut').then(() => {
Message.error(err) Message({
dangerouslyUseHTMLString: true,
message: err,
type: 'error',
duration: 10 * 1000
})
next({ path: '/' }) next({ path: '/' })
}) })
}) })

View file

@ -3,24 +3,44 @@ import Router from 'vue-router'
Vue.use(Router) Vue.use(Router)
const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) { return originalPush.call(this, location, onResolve, onReject) }
return originalPush.call(this, location).catch((err) => {
if (Router.isNavigationFailure(err)) {
// resolve err
return err
}
// rethrow error
return Promise.reject(err)
})
}
/* Layout */ /* Layout */
import Layout from '@/views/layout/Layout' import Layout from '@/views/layout/Layout'
const disabledFeatures = process.env.DISABLED_FEATURES || [] const disabledFeatures = process.env.DISABLED_FEATURES || []
const settingsDisabled = disabledFeatures.includes('settings') const settingsDisabled = disabledFeatures.includes('settings')
const settingsChildren = () => {
return localStorage.getItem('settingsTabs')
? JSON.parse(localStorage.getItem('settingsTabs')).map(({ label, path }) => {
return {
path,
component: () => import(`@/views/settings`),
name: label,
meta: { title: label }
}
})
: []
}
const settings = { const settings = {
path: '/settings', path: '/settings',
component: Layout, component: Layout,
children: [ name: 'Settings',
{ hasSubmenu: true,
path: 'index', meta: { title: 'settings', icon: 'el-icon-setting', noCache: true },
component: () => import('@/views/settings/index'), children: settingsChildren()
name: 'Settings',
meta: { title: 'Settings', icon: 'settings', noCache: true }
}
]
} }
const statusesDisabled = disabledFeatures.includes('statuses') const statusesDisabled = disabledFeatures.includes('statuses')
const statuses = { const statuses = {
path: '/statuses', path: '/statuses',
@ -30,7 +50,7 @@ const statuses = {
path: 'index', path: 'index',
component: () => import('@/views/statuses/index'), component: () => import('@/views/statuses/index'),
name: 'Statuses', name: 'Statuses',
meta: { title: 'Statuses', icon: 'form', noCache: true } meta: { title: 'statuses', icon: 'el-icon-chat-line-square', noCache: true }
} }
] ]
} }
@ -44,7 +64,7 @@ const reports = {
path: 'index', path: 'index',
component: () => import('@/views/reports/index'), component: () => import('@/views/reports/index'),
name: 'Reports', name: 'Reports',
meta: { title: 'Reports', icon: 'documentation', noCache: true } meta: { title: 'reports', icon: 'el-icon-receiving', noCache: true }
} }
] ]
} }
@ -58,21 +78,21 @@ const invites = {
path: 'index', path: 'index',
component: () => import('@/views/invites/index'), component: () => import('@/views/invites/index'),
name: 'Invites', name: 'Invites',
meta: { title: 'Invites', icon: 'guide', noCache: true } meta: { title: 'invites', icon: 'el-icon-postcard', noCache: true }
} }
] ]
} }
const emojiPacksDisabled = disabledFeatures.includes('emoji-packs') const relaysDisabled = disabledFeatures.includes('relays')
const emojiPacks = { const relays = {
path: '/emoji_packs', path: '/relays',
component: Layout, component: Layout,
children: [ children: [
{ {
path: 'index', path: 'index',
component: () => import('@/views/emojiPacks/index'), component: () => import('@/views/relays/index'),
name: 'Emoji Packs', name: 'Relays',
meta: { title: 'Emoji Packs', icon: 'eye-open', noCache: true } meta: { title: 'relays', icon: 'el-icon-connection', noCache: true }
} }
] ]
} }
@ -84,9 +104,23 @@ const moderationLog = {
children: [ children: [
{ {
path: 'index', path: 'index',
component: () => import('@/views/moderation_log/index'), component: () => import('@/views/moderationLog/index'),
name: 'Moderation Log', name: 'Moderation Log',
meta: { title: 'moderationLog', icon: 'list', noCache: true } meta: { title: 'moderationLog', icon: 'el-icon-notebook-2', noCache: true }
}
]
}
const mediaProxyCacheDisabled = disabledFeatures.includes('media-proxy-cache')
const mediaProxyCache = {
path: '/media_proxy_cache',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/mediaProxyCache/index'),
name: 'MediaProxy Cache',
meta: { title: 'mediaProxyCache', icon: 'el-icon-coin', noCache: true }
} }
] ]
} }
@ -131,7 +165,8 @@ export const constantRouterMap = [
{ {
path: '', path: '',
component: Layout, component: Layout,
redirect: '/users/index' redirect: '/users/index',
hidden: true
} }
] ]
@ -150,15 +185,16 @@ export const asyncRouterMap = [
path: 'index', path: 'index',
component: () => import('@/views/users/index'), component: () => import('@/views/users/index'),
name: 'Users', name: 'Users',
meta: { title: 'users', icon: 'peoples', noCache: true } meta: { title: 'users', icon: 'el-icon-user', noCache: true }
} }
] ]
}, },
...(statusesDisabled ? [] : [statuses]), ...(statusesDisabled ? [] : [statuses]),
...(reportsDisabled ? [] : [reports]), ...(reportsDisabled ? [] : [reports]),
...(invitesDisabled ? [] : [invites]), ...(invitesDisabled ? [] : [invites]),
...(emojiPacksDisabled ? [] : [emojiPacks]),
...(moderationLogDisabled ? [] : [moderationLog]), ...(moderationLogDisabled ? [] : [moderationLog]),
...(relaysDisabled ? [] : [relays]),
...(mediaProxyCacheDisabled ? [] : [mediaProxyCache]),
...(settingsDisabled ? [] : [settings]), ...(settingsDisabled ? [] : [settings]),
{ {
path: '/users/:id', path: '/users/:id',
@ -172,5 +208,29 @@ export const asyncRouterMap = [
], ],
hidden: true hidden: true
}, },
{
path: '/statuses/:id',
component: Layout,
children: [
{
path: '',
name: 'StatusShow',
component: () => import('@/views/statuses/show')
}
],
hidden: true
},
{
path: '/reports/:id',
component: Layout,
children: [
{
path: '',
name: 'ReportsShow',
component: () => import('@/views/reports/show')
}
],
hidden: true
},
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]

View file

@ -1,36 +0,0 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/views/layout/Layout'
const chartsRouter = {
path: '/charts',
component: Layout,
redirect: 'noredirect',
name: 'Charts',
meta: {
title: 'charts',
icon: 'chart'
},
children: [
{
path: 'keyboard',
component: () => import('@/views/charts/keyboard'),
name: 'KeyboardChart',
meta: { title: 'keyboardChart', noCache: true }
},
{
path: 'line',
component: () => import('@/views/charts/line'),
name: 'LineChart',
meta: { title: 'lineChart', noCache: true }
},
{
path: 'mixchart',
component: () => import('@/views/charts/mixChart'),
name: 'MixChart',
meta: { title: 'mixChart', noCache: true }
}
]
}
export default chartsRouter

View file

@ -1,66 +0,0 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/views/layout/Layout'
const nestedRouter = {
path: '/nested',
component: Layout,
redirect: '/nested/menu1/menu1-1',
name: 'Nested',
meta: {
title: 'nested',
icon: 'nested'
},
children: [
{
path: 'menu1',
component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'Menu1',
meta: { title: 'menu1' },
redirect: '/nested/menu1/menu1-1',
children: [
{
path: 'menu1-1',
component: () => import('@/views/nested/menu1/menu1-1'),
name: 'Menu1-1',
meta: { title: 'menu1-1' }
},
{
path: 'menu1-2',
component: () => import('@/views/nested/menu1/menu1-2'),
name: 'Menu1-2',
redirect: '/nested/menu1/menu1-2/menu1-2-1',
meta: { title: 'menu1-2' },
children: [
{
path: 'menu1-2-1',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
name: 'Menu1-2-1',
meta: { title: 'menu1-2-1' }
},
{
path: 'menu1-2-2',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
name: 'Menu1-2-2',
meta: { title: 'menu1-2-2' }
}
]
},
{
path: 'menu1-3',
component: () => import('@/views/nested/menu1/menu1-3'),
name: 'Menu1-3',
meta: { title: 'menu1-3' }
}
]
},
{
path: 'menu2',
name: 'Menu2',
component: () => import('@/views/nested/menu2/index'),
meta: { title: 'menu2' }
}
]
}
export default nestedRouter

View file

@ -17,6 +17,7 @@ const getters = {
errorLogs: state => state.errorLog.logs, errorLogs: state => state.errorLog.logs,
users: state => state.users.fetchedUsers, users: state => state.users.fetchedUsers,
authHost: state => state.user.authHost, authHost: state => state.user.authHost,
settings: state => state.settings settings: state => state.settings,
tabs: state => state.settings.tabs
} }
export default getters export default getters

View file

@ -1,9 +1,12 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import app from './modules/app' import app from './modules/app'
import emojiPacks from './modules/emojiPacks'
import errorLog from './modules/errorLog' import errorLog from './modules/errorLog'
import moderationLog from './modules/moderationLog' import getters from './getters'
import invites from './modules/invites' import invites from './modules/invites'
import mediaProxyCache from './modules/mediaProxyCache'
import moderationLog from './modules/moderationLog'
import peers from './modules/peers' import peers from './modules/peers'
import permission from './modules/permission' import permission from './modules/permission'
import relays from './modules/relays' import relays from './modules/relays'
@ -14,8 +17,6 @@ import tagsView from './modules/tagsView'
import user from './modules/user' import user from './modules/user'
import userProfile from './modules/userProfile' import userProfile from './modules/userProfile'
import users from './modules/users' import users from './modules/users'
import getters from './getters'
import emojiPacks from './modules/emojiPacks.js'
Vue.use(Vuex) Vue.use(Vuex)
@ -23,8 +24,10 @@ const store = new Vuex.Store({
modules: { modules: {
app, app,
errorLog, errorLog,
moderationLog, emojiPacks,
invites, invites,
mediaProxyCache,
moderationLog,
peers, peers,
permission, permission,
relays, relays,
@ -34,8 +37,7 @@ const store = new Vuex.Store({
tagsView, tagsView,
user, user,
userProfile, userProfile,
users, users
emojiPacks
}, },
getters getters
}) })

View file

@ -1,4 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { needReboot, restartApp } from '@/api/app'
const app = { const app = {
state: { state: {
@ -8,7 +9,9 @@ const app = {
}, },
device: 'desktop', device: 'desktop',
language: Cookies.get('language') || 'en', language: Cookies.get('language') || 'en',
size: Cookies.get('size') || 'medium' needReboot: false,
size: Cookies.get('size') || 'medium',
invitesEnabled: false
}, },
mutations: { mutations: {
TOGGLE_SIDEBAR: state => { TOGGLE_SIDEBAR: state => {
@ -28,30 +31,47 @@ const app = {
TOGGLE_DEVICE: (state, device) => { TOGGLE_DEVICE: (state, device) => {
state.device = device state.device = device
}, },
SET_INVITES_ENABLED: (state, invitesEnabled) => {
state.invitesEnabled = invitesEnabled
},
SET_LANGUAGE: (state, language) => { SET_LANGUAGE: (state, language) => {
state.language = language state.language = language
Cookies.set('language', language) Cookies.set('language', language)
}, },
TOGGLE_REBOOT: (state, needReboot) => {
state.needReboot = needReboot
},
SET_SIZE: (state, size) => { SET_SIZE: (state, size) => {
state.size = size state.size = size
Cookies.set('size', size) Cookies.set('size', size)
} }
}, },
actions: { actions: {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) { closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation) commit('CLOSE_SIDEBAR', withoutAnimation)
}, },
toggleDevice({ commit }, device) { async NeedReboot({ commit, getters }) {
commit('TOGGLE_DEVICE', device) const response = await needReboot(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', response.data['need_reboot'])
},
async RestartApplication({ commit, getters }) {
await restartApp(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', false)
},
SetInvitesEnabled({ commit }, invitesEnabled) {
commit('SET_INVITES_ENABLED', invitesEnabled)
}, },
setLanguage({ commit }, language) { setLanguage({ commit }, language) {
commit('SET_LANGUAGE', language) commit('SET_LANGUAGE', language)
}, },
setSize({ commit }, size) { setSize({ commit }, size) {
commit('SET_SIZE', size) commit('SET_SIZE', size)
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
},
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
} }
} }
} }

View file

@ -1,31 +1,72 @@
import { import {
addNewEmojiFile,
createPack,
deleteEmojiFile,
deletePack,
downloadFrom,
fetchPack,
importFromFS,
listPacks, listPacks,
listRemotePacks, listRemotePacks,
downloadFrom,
reloadEmoji, reloadEmoji,
createPack,
deletePack,
savePackMetadata, savePackMetadata,
importFromFS, updateEmojiFile
updatePackFile } from '@/api/emojiPacks' } from '@/api/emojiPacks'
import i18n from '@/lang' import i18n from '@/lang'
import { Message } from 'element-ui' import { Message } from 'element-ui'
import Vue from 'vue' import Vue from 'vue'
const packs = { const emojiPacks = {
state: { state: {
currentLocalFilesPage: 1,
currentLocalPacksPage: 1,
currentRemoteFilesPage: 1,
currentRemotePacksPage: 1,
filesPageSize: 30,
localPackFilesCount: 0,
localPacks: {}, localPacks: {},
localPacksCount: 0,
pageSize: 50,
remoteInstance: '', remoteInstance: '',
remotePacks: {} remotePackFilesCount: 0,
remotePacks: {},
remotePacksCount: 0
}, },
mutations: { mutations: {
SET_LOCAL_FILES_COUNT: (state, count) => {
state.localPackFilesCount = count
},
SET_LOCAL_FILES_PAGE: (state, page) => {
state.currentLocalFilesPage = page
},
SET_LOCAL_PACKS: (state, packs) => { SET_LOCAL_PACKS: (state, packs) => {
state.localPacks = packs state.localPacks = packs
}, },
SET_LOCAL_PACKS_COUNT: (state, count) => {
state.localPacksCount = count
},
SET_LOCAL_PACK_FILES: (state, { name, files }) => {
state.localPacks = { ...state.localPacks, [name]: { ...state.localPacks[name], files }}
},
SET_LOCAL_PAGE: (state, page) => {
state.currentLocalPacksPage = page
},
SET_REMOTE_FILES_COUNT: (state, count) => {
state.remotePackFilesCount = count
},
SET_REMOTE_FILES_PAGE: (state, page) => {
state.currentRemoteFilesPage = page
},
SET_REMOTE_INSTANCE: (state, name) => { SET_REMOTE_INSTANCE: (state, name) => {
state.remoteInstance = name state.remoteInstance = name
}, },
SET_REMOTE_PACKS_COUNT: (state, count) => {
state.remotePacksCount = count
},
SET_REMOTE_PACK_FILES: (state, { name, files }) => {
state.remotePacks = { ...state.remotePacks, [name]: { ...state.remotePacks[name], files }}
},
SET_REMOTE_PACKS: (state, packs) => { SET_REMOTE_PACKS: (state, packs) => {
state.remotePacks = packs state.remotePacks = packs
}, },
@ -45,6 +86,41 @@ const packs = {
} }
}, },
actions: { actions: {
async AddNewEmojiFile({ commit, getters }, { packName, file, shortcode, filename }) {
let result
try {
result = await addNewEmojiFile(packName, file, shortcode, filename, getters.authHost, getters.token)
} catch (_e) {
return
}
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
},
async DeleteEmojiFile({ commit, dispatch, getters, state }, { packName, shortcode }) {
const { [shortcode]: value, ...updatedPackFiles } = state.localPacks[packName].files
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: updatedPackFiles })
try {
await deleteEmojiFile(packName, shortcode, getters.authHost, getters.token)
} catch (_e) {
return
}
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
if (Object.keys(updatedPackFiles).length === 0 && state.currentLocalFilesPage > 1) {
dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage - 1 })
} else {
dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage })
}
},
async CreatePack({ getters }, { name }) { async CreatePack({ getters }, { name }) {
await createPack(getters.authHost, getters.token, name) await createPack(getters.authHost, getters.token, name)
}, },
@ -52,7 +128,7 @@ const packs = {
await deletePack(getters.authHost, getters.token, name) await deletePack(getters.authHost, getters.token, name)
}, },
async DownloadFrom({ getters }, { instanceAddress, packName, as }) { async DownloadFrom({ getters }, { instanceAddress, packName, as }) {
const result = await downloadFrom(getters.authHost, instanceAddress, packName, as, getters.token) const result = await downloadFrom(instanceAddress, packName, as, getters.authHost, getters.token)
if (result.data === 'ok') { if (result.data === 'ok') {
Message({ Message({
@ -62,6 +138,32 @@ const packs = {
}) })
} }
}, },
async FetchLocalEmojiPacks({ commit, getters, state }, page) {
const { data } = await listPacks(page, state.pageSize, getters.authHost, getters.token)
const { packs, count } = data
const updatedPacks = Object.keys(packs).reduce((acc, packName) => {
const { files, ...pack } = packs[packName]
acc[packName] = pack
return acc
}, {})
commit('SET_LOCAL_PACKS', updatedPacks)
commit('SET_LOCAL_PACKS_COUNT', count)
commit('SET_LOCAL_PAGE', page)
},
async FetchLocalSinglePack({ getters, commit, state }, { name, page }) {
const { data } = await fetchPack(name, page, state.filesPageSize, getters.authHost, getters.token)
const { files, files_count } = data
commit('SET_LOCAL_PACK_FILES', { name, files })
commit('SET_LOCAL_FILES_COUNT', files_count)
commit('SET_LOCAL_FILES_PAGE', page)
},
async FetchRemoteSinglePack({ getters, commit, state }, { name, page }) {
const { data } = await fetchPack(name, page, state.filesPageSize, getters.authHost, getters.token)
const { files, files_count } = data
commit('SET_REMOTE_PACK_FILES', { name, files })
commit('SET_REMOTE_FILES_COUNT', files_count)
commit('SET_REMOTE_FILES_PAGE', page)
},
async ImportFromFS({ getters }) { async ImportFromFS({ getters }) {
const result = await importFromFS(getters.authHost, getters.token) const result = await importFromFS(getters.authHost, getters.token)
@ -99,30 +201,45 @@ const packs = {
commit('UPDATE_LOCAL_PACK_PACK', { name: packName, pack: result.data }) commit('UPDATE_LOCAL_PACK_PACK', { name: packName, pack: result.data })
} }
}, },
async SetLocalEmojiPacks({ commit, getters }) { async SetRemoteEmojiPacks({ commit, getters, state }, { page, remoteInstance }) {
const { data } = await listPacks(getters.authHost) const { data } = await listRemotePacks(remoteInstance, page, state.pageSize, getters.authHost, getters.token)
commit('SET_LOCAL_PACKS', data) const { packs, count } = data
}, const updatedPacks = Object.keys(packs).reduce((acc, packName) => {
async SetRemoteEmojiPacks({ commit, getters }, { remoteInstance }) { const { files, ...pack } = packs[packName]
const { data } = await listRemotePacks(getters.authHost, getters.token, remoteInstance) acc[packName] = pack
return acc
}, {})
commit('SET_REMOTE_INSTANCE', remoteInstance) commit('SET_REMOTE_INSTANCE', remoteInstance)
commit('SET_REMOTE_PACKS', data) commit('SET_REMOTE_PACKS', updatedPacks)
commit('SET_REMOTE_PACKS_COUNT', count)
}, },
async UpdateAndSavePackFile({ commit, getters }, args) { SetRemoteInstance({ commit }, instance) {
const result = await updatePackFile(getters.authHost, getters.token, args) commit('SET_REMOTE_INSTANCE', instance)
},
async UpdateEmojiFile({ commit, dispatch, getters, state }, { packName, shortcode, newShortcode, newFilename, force }) {
const updatedPackFiles = Object.keys(state.localPacks[packName].files).reduce((acc, el) => {
if (el === shortcode) {
acc[newShortcode] = newFilename
} else {
acc[el] = state.localPacks[packName].files[el]
}
return acc
}, {})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: updatedPackFiles })
if (result.status === 200) { try {
const { packName } = args await updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, getters.authHost, getters.token)
} catch (_e) {
Message({ return
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
} }
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage })
}, },
async UpdateLocalPackVal({ commit }, args) { async UpdateLocalPackVal({ commit }, args) {
commit('UPDATE_LOCAL_PACK_VAL', args) commit('UPDATE_LOCAL_PACK_VAL', args)
@ -130,4 +247,4 @@ const packs = {
} }
} }
export default packs export default emojiPacks

View file

@ -0,0 +1,108 @@
import { listBannedUrls, purgeUrls, removeBannedUrls, searchBannedUrls } from '@/api/mediaProxyCache'
import { fetchSettings, updateSettings } from '@/api/settings'
import { Message } from 'element-ui'
import i18n from '@/lang'
const mediaProxyCache = {
state: {
bannedUrls: [],
currentPage: 1,
loading: false,
mediaProxyEnabled: false,
pageSize: 50,
searchQuery: '',
totalUrlsCount: 0
},
mutations: {
MEDIA_PROXY_ENABLED: (state, enabled) => {
state.mediaProxyEnabled = enabled
},
SET_BANNED_URLS: (state, urls) => {
state.bannedUrls = urls.map(el => { return { url: el } })
},
SET_TOTAL_URLS_COUNT: (state, count) => {
state.totalUrlsCount = count
},
SET_LOADING: (state, status) => {
state.loading = status
},
SET_PAGE: (state, page) => {
state.currentPage = page
},
SET_SEARCH_QUERY: (state, query) => {
state.searchQuery = query
}
},
actions: {
async EnableMediaProxy({ dispatch, getters, state }) {
const configs = [{
group: ':pleroma',
key: ':media_proxy',
value: [
{ tuple: [':enabled', true] },
{ tuple: [':invalidation', [{ tuple: [':enabled', true] }]] }
]
}]
await updateSettings(configs, getters.authHost, getters.token)
dispatch('FetchMediaProxySetting')
},
async FetchMediaProxySetting({ commit, getters }) {
const { data } = await fetchSettings(getters.authHost, getters.token)
const mediaProxySettings = data.configs.find(el => el.key === ':media_proxy')
? data.configs.find(el => el.key === ':media_proxy').value
: []
const mediaProxyEnabled = mediaProxySettings.find(el => el.tuple[0] === ':enabled')
? mediaProxySettings.find(el => el.tuple[0] === ':enabled').tuple[1]
: false
commit('MEDIA_PROXY_ENABLED', mediaProxyEnabled)
},
async ListBannedUrls({ commit, getters, state }, { page }) {
commit('SET_LOADING', true)
const response = await listBannedUrls(page, state.pageSize, getters.authHost, getters.token)
commit('SET_BANNED_URLS', response.data.urls)
commit('SET_TOTAL_URLS_COUNT', response.data.count)
commit('SET_PAGE', page)
commit('SET_LOADING', false)
},
async PurgeUrls({ dispatch, getters, state }, { urls, ban }) {
await purgeUrls(urls, ban, getters.authHost, getters.token)
Message({
message: i18n.t('mediaProxyCache.evictedMessage'),
type: 'success',
duration: 5 * 1000
})
if (ban && state.searchQuery.length === 0) {
dispatch('ListBannedUrls', { page: state.currentPage })
} else if (ban) {
dispatch('SearchUrls', { query: state.searchQuery, page: state.currentPage })
}
},
async RemoveBannedUrls({ dispatch, getters, state }, urls) {
await removeBannedUrls(urls, getters.authHost, getters.token)
if (state.searchQuery.length === 0) {
dispatch('ListBannedUrls', { page: state.currentPage })
} else {
dispatch('SearchUrls', { query: state.searchQuery, page: state.currentPage })
}
},
async SearchUrls({ commit, dispatch, getters, state }, { query, page }) {
if (query.length === 0) {
commit('SET_SEARCH_QUERY', query)
dispatch('ListBannedUrls', { page })
} else {
commit('SET_LOADING', true)
commit('SET_SEARCH_QUERY', query)
const response = await searchBannedUrls(query, page, state.pageSize, getters.authHost, getters.token)
commit('SET_BANNED_URLS', response.data.urls)
commit('SET_TOTAL_URLS_COUNT', response.data.count)
commit('SET_PAGE', page)
commit('SET_LOADING', false)
}
}
}
}
export default mediaProxyCache

View file

@ -1,25 +1,12 @@
import _ from 'lodash' import _ from 'lodash'
export const checkPartialUpdate = (settings, updatedSettings, description) => { export const getBooleanValue = value => {
return Object.keys(updatedSettings).reduce((acc, group) => { if (value === 'true') {
acc[group] = Object.keys(updatedSettings[group]).reduce((acc, key) => { return true
if (!partialUpdate(group, key)) { } else if (value === 'false') {
const updated = Object.keys(settings[group][key]).reduce((acc, settingName) => { return false
const setting = description }
.find(element => element.group === group && element.key === key).children return value
.find(child => child.key === settingName)
const type = setting ? setting.type : ''
acc[settingName] = [type, settings[group][key][settingName]]
return acc
}, {})
acc[key] = updated
return acc
}
acc[key] = updatedSettings[group][key]
return acc
}, {})
return acc
}, {})
} }
const getCurrentValue = (type, value, path) => { const getCurrentValue = (type, value, path) => {
@ -41,7 +28,7 @@ const getCurrentValue = (type, value, path) => {
} }
const getValueWithoutKey = (key, [type, value]) => { const getValueWithoutKey = (key, [type, value]) => {
if (type === 'atom' && value.length > 1) { if (prependWithColon(type, value)) {
return `:${value}` return `:${value}`
} else if (key === ':backends') { } else if (key === ':backends') {
const index = value.findIndex(el => el === ':ex_syslogger') const index = value.findIndex(el => el === ':ex_syslogger')
@ -63,39 +50,56 @@ export const parseNonTuples = (key, value) => {
return updated return updated
} }
if (key === ':args') { if (key === ':args') {
if (typeof value === 'string') { return typeof value === 'string' ? [value] : value
return [value]
}
const index = value.findIndex(el => typeof el === 'object' && el.tuple.includes('implode'))
const updated = value.map((el, i) => i === index ? 'implode' : el)
return updated
} }
return value return value
} }
// REFACTOR // REFACTOR
export const parseTuples = (tuples, key) => { export const parseTuples = (tuples, key) => {
return tuples.reduce((accum, item) => { return tuples.reduce((accum, item) => {
if (key === ':rate_limit') { if (key === ':rate_limit' ||
accum[item.tuple[0]] = Array.isArray(item.tuple[1]) (key === 'Pleroma.Web.Endpoint.MetricsExporter' && item.tuple[0] === ':auth')) {
? item.tuple[1].map(el => el.tuple) const getValue = () => {
: item.tuple[1].tuple if (typeof item.tuple[1] === 'boolean') {
return item.tuple[1]
} else if (Array.isArray(item.tuple[1])) {
return item.tuple[1].map(el => el.tuple)
} else {
return item.tuple[1].tuple
}
}
accum[item.tuple[0]] = getValue()
} else if (item.tuple[0] === ':mascots') { } else if (item.tuple[0] === ':mascots') {
accum[item.tuple[0]] = item.tuple[1].reduce((acc, mascot) => { accum[item.tuple[0]] = item.tuple[1].reduce((acc, mascot) => {
return [...acc, { [mascot.tuple[0]]: { ...mascot.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}] return [...acc, { [mascot.tuple[0]]: { ...mascot.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}, []) }, [])
} else if (Array.isArray(item.tuple[1]) && } else if (Array.isArray(item.tuple[1]) &&
(item.tuple[0] === ':groups' || item.tuple[0] === ':replace' || item.tuple[0] === ':retries')) { (item.tuple[0] === ':groups' ||
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => { item.tuple[0] === ':replace' ||
return [...acc, { [group.tuple[0]]: { value: group.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}] item.tuple[0] === ':retries' ||
}, []) item.tuple[0] === ':timeout' ||
} else if (item.tuple[0] === ':crontab') { (item.tuple[0] === ':headers' && key === 'Pleroma.Web.MediaProxy.Invalidation.Http') ||
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => { item.tuple[0] === ':crontab' ||
return { ...acc, [group.tuple[1]]: group.tuple[0] } item.tuple[0] === ':transparency_exclusions' ||
}, {}) item.tuple[0] === ':quarantined_instances' ||
} else if (item.tuple[0] === ':match_actor') { key === ':mrf_simple')) {
accum[item.tuple[0]] = Object.keys(item.tuple[1]).reduce((acc, regex) => { if (item.tuple[0] === ':crontab') {
return [...acc, { [regex]: { value: item.tuple[1][regex], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}] accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => {
}, []) return [...acc, { [group.tuple[1]]: { value: group.tuple[0], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}, [])
} else {
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => {
/**
* The ':quarantined_instances' and ':mrf_simple' settings have changed to a list of tuples instead of a list of strings.
* This is to have backwards compatibility for instances that still use strings.
*/
if (typeof group === 'string') {
return [...acc, group]
} else {
return [...acc, { [group.tuple[0]]: { value: group.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}
}, [])
}
} else if (item.tuple[0] === ':icons') { } else if (item.tuple[0] === ':icons') {
accum[item.tuple[0]] = item.tuple[1].map(icon => { accum[item.tuple[0]] = item.tuple[1].map(icon => {
return Object.keys(icon).map(name => { return Object.keys(icon).map(name => {
@ -104,19 +108,27 @@ export const parseTuples = (tuples, key) => {
}, []) }, [])
} else if (item.tuple[0] === ':prune') { } else if (item.tuple[0] === ':prune') {
accum[item.tuple[0]] = item.tuple[1] === ':disabled' ? [item.tuple[1]] : item.tuple[1].tuple accum[item.tuple[0]] = item.tuple[1] === ':disabled' ? [item.tuple[1]] : item.tuple[1].tuple
} else if (item.tuple[0] === ':proxy_url') { } else if (item.tuple[0] === ':sender') {
accum[item.tuple[0]] = parseProxyUrl(item.tuple[1]) accum[item.tuple[0]] = parseStringOrTupleValue(item.tuple[0], item.tuple[1])
} else if (item.tuple[0] === ':args') { } else if (item.tuple[0] === ':args') {
accum[item.tuple[0]] = parseNonTuples(item.tuple[0], item.tuple[1]) accum[item.tuple[0]] = parseNonTuples(item.tuple[0], item.tuple[1])
} else if (Array.isArray(item.tuple[1]) && } else if (item.tuple[0] === ':ip_whitelist') {
(typeof item.tuple[1][0] === 'object' && !Array.isArray(item.tuple[1][0])) && item.tuple[1][0]['tuple']) { accum[item.tuple[0]] = item.tuple[1].map(ip => typeof ip === 'string' ? ip : ip.tuple.join('.'))
} else if (Array.isArray(item.tuple[1]) && (item.tuple[1][0] !== null &&
typeof item.tuple[1][0] === 'object' && !Array.isArray(item.tuple[1][0])) && item.tuple[1][0]['tuple']) {
accum[item.tuple[0]] = parseTuples(item.tuple[1], item.tuple[0]) accum[item.tuple[0]] = parseTuples(item.tuple[1], item.tuple[0])
} else if (Array.isArray(item.tuple[1])) { } else if (Array.isArray(item.tuple[1])) {
accum[item.tuple[0]] = item.tuple[1] accum[item.tuple[0]] = item.tuple[1]
} else if (item.tuple[0] === ':ip') { } else if (item.tuple[0] === ':ip') {
accum[item.tuple[0]] = item.tuple[1].tuple.join('.') accum[item.tuple[0]] = item.tuple[1].tuple.join('.')
} else if (item.tuple[1] && typeof item.tuple[1] === 'object') { } else if (item.tuple[1] && typeof item.tuple[1] === 'object') {
accum[item.tuple[0]] = parseObject(item.tuple[1]) if (item.tuple[0] === ':params' || item.tuple[0] === ':match_actor') {
accum[item.tuple[0]] = Object.keys(item.tuple[1]).reduce((acc, key) => {
return [...acc, { [key]: { value: item.tuple[1][key], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}, [])
} else {
accum[item.tuple[0]] = parseObject(item.tuple[1])
}
} else { } else {
accum[item.tuple[0]] = item.tuple[1] accum[item.tuple[0]] = item.tuple[1]
} }
@ -131,22 +143,34 @@ const parseObject = object => {
}, {}) }, {})
} }
const parseProxyUrl = value => { const parseStringOrTupleValue = (key, value) => {
if (value && !Array.isArray(value) && if (key === ':proxy_url') {
typeof value === 'object' && if (value && !Array.isArray(value) &&
value.tuple.length === 3 && typeof value === 'object' &&
value.tuple[0] === ':socks5') { value.tuple.length === 3 &&
const [, host, port] = value.tuple value.tuple[0] === ':socks5') {
return { socks5: true, host, port } const [, host, port] = value.tuple
} else if (typeof value === 'string') { return { socks5: true, host, port }
const [host, port] = value.split(':') } else if (typeof value === 'string') {
return { socks5: false, host, port } const [host, port] = value.split(':')
return { socks5: false, host, port }
}
return { socks5: false, host: null, port: null }
} else if (key === ':sender') {
if (typeof value === 'string') {
return { email: value }
} else if (value &&
typeof value === 'object' &&
value.tuple.length === 2) {
const [nickname, email] = value.tuple
return { nickname, email }
}
} }
return { socks5: false, host: null, port: null }
} }
const partialUpdate = (group, key) => { const prependWithColon = (type, value) => {
return !(group === ':auto_linker' && key === ':opts') return (type === 'atom' && value.length > 0) ||
(Array.isArray(type) && type.includes('boolean') && type.includes('atom') && typeof value === 'string')
} }
export const processNested = (valueForState, valueForUpdatedSettings, group, parentKey, parents, settings, updatedSettings) => { export const processNested = (valueForState, valueForUpdatedSettings, group, parentKey, parents, settings, updatedSettings) => {
@ -226,44 +250,76 @@ export const wrapUpdatedSettings = (group, settings, currentState) => {
const wrapValues = (settings, currentState) => { const wrapValues = (settings, currentState) => {
return Object.keys(settings).map(setting => { return Object.keys(settings).map(setting => {
const [type, value] = settings[setting] const [type, value] = settings[setting]
if ( if (type === 'keyword' ||
type === 'keyword' || (Array.isArray(type) && (
type.includes('keyword') || type.includes('keyword') ||
type.includes('tuple') && type.includes('list') || (type.includes('tuple') && type.includes('list'))
setting === ':replace' ))
) { ) {
return { 'tuple': [setting, wrapValues(value, currentState)] } return { 'tuple': [setting, wrapValues(value, currentState)] }
} else if (type === 'atom' && value.length > 0) { } else if (prependWithColon(type, value)) {
return { 'tuple': [setting, `:${value}`] } return { 'tuple': [setting, `:${value}`] }
} else if (type.includes('tuple') && (type.includes('string') || type.includes('atom'))) { } else if (type.includes('tuple') &&
return typeof value === 'string' (type.includes('string') || type.includes('atom') || type.includes('boolean'))) {
return typeof value === 'string' || typeof value === 'boolean'
? { 'tuple': [setting, value] } ? { 'tuple': [setting, value] }
: { 'tuple': [setting, { 'tuple': value }] } : { 'tuple': [setting, { 'tuple': value }] }
} else if (type === 'reversed_tuple') { } else if (type === 'reversed_tuple') {
return { 'tuple': [value, setting] } return { 'tuple': [value, setting] }
} else if (type === 'map') { } else if (type === 'map') {
const mapValue = Object.keys(value).reduce((acc, key) => { const mapValue = Object.keys(value).reduce((acc, key) => {
acc[key] = setting === ':match_actor' ? value[key] : value[key][1] acc[key] = value[key][1]
return acc return acc
}, {}) }, {})
const mapCurrentState = setting === ':match_actor' return { 'tuple': [setting, { ...currentState[setting], ...mapValue }] }
? currentState[setting].reduce((acc, element) => { } else if (type.includes('map') && !type.includes('list')) {
return { ...acc, ...{ [Object.keys(element)[0]]: Object.values(element)[0].value }} const mapValue = Object.keys(value).reduce((acc, key) => {
}, {}) acc[key] = value[key][1]
: currentState[setting] return acc
return { 'tuple': [setting, { ...mapCurrentState, ...mapValue }] } }, {})
return { 'tuple': [setting, mapValue] }
} else if (setting === ':ip') { } else if (setting === ':ip') {
const ip = value.split('.').map(s => parseInt(s, 10)) const ip = value.split('.').map(s => parseInt(s, 10))
return { 'tuple': [setting, { 'tuple': ip }] } return { 'tuple': [setting, { 'tuple': ip }] }
} else if (setting === ':args') {
const index = value.findIndex(el => el === 'implode')
const updatedArray = value.slice()
if (index !== -1) {
updatedArray[index] = { 'tuple': ['implode', '1'] }
}
return { 'tuple': [setting, updatedArray] }
} else { } else {
return { 'tuple': [setting, value] } return { 'tuple': [setting, value] }
} }
}) })
} }
export const formSearchObject = description => {
const parseNestedSettings = (description, label, key) => description.reduce((acc, setting) => {
const searchArray = _.compact([setting.key, setting.label, setting.description]).map(el => el.toLowerCase())
const resultObject = { label: setting.label, key: setting.key || setting.group, groupKey: key, groupLabel: label, search: searchArray }
if (setting.children) {
const updatedAcc = [...acc, resultObject]
return [...updatedAcc, ...parseNestedSettings(setting.children, label, key)]
}
return [...acc, resultObject]
}, [])
const processedDescription = description.reduce((acc, setting) => {
const searchArray = _.compact([setting.key, setting.label, setting.description]).map(el => el.toLowerCase())
const resultObject = { label: setting.label, key: setting.key || setting.group, groupKey: setting.key || setting.group, groupLabel: setting.label, search: searchArray }
if (setting.children) {
const updatedAcc = !setting.key && setting.group === ':pleroma' ? acc : [...acc, resultObject]
return [...updatedAcc, ...parseNestedSettings(setting.children, setting.label, setting.key || setting.group)]
}
return !setting.key && setting.group === ':pleroma' ? acc : [...acc, resultObject]
}, [])
const searchDataForEditableDocs = [{
groupKey: ':instance_panel',
groupLabel: 'Instance Panel',
key: ':instance_panel',
label: 'Instance Panel',
search: ['Instance Panel', ':instance_panel']
}, {
groupKey: ':terms_of_services',
groupLabel: 'Terms of Services',
key: ':terms_of_services',
label: 'Terms of Services',
search: ['Terms of Services', ':terms_of_services']
}]
return processedDescription.concat(searchDataForEditableDocs)
}

View file

@ -46,15 +46,10 @@ const permission = {
} }
}, },
actions: { actions: {
GenerateRoutes({ commit }, data) { GenerateRoutes({ commit }, { roles, _routesWithSettings }) {
return new Promise(resolve => { return new Promise(resolve => {
const { roles } = data const routes = _routesWithSettings || asyncRouterMap
let accessedRouters const accessedRouters = roles.includes('admin') ? routes : filterAsyncRouter(asyncRouterMap, roles)
if (roles.includes('admin')) {
accessedRouters = asyncRouterMap
} else {
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
}
commit('SET_ROUTERS', accessedRouters) commit('SET_ROUTERS', accessedRouters)
resolve() resolve()
}) })

View file

@ -13,19 +13,18 @@ const relays = {
state.fetchedRelays = relays state.fetchedRelays = relays
}, },
ADD_RELAY: (state, relay) => { ADD_RELAY: (state, relay) => {
state.fetchedRelays = [...state.fetchedRelays, relay] state.fetchedRelays = [...state.fetchedRelays, { actor: relay }]
}, },
DELETE_RELAY: (state, relay) => { DELETE_RELAY: (state, relay) => {
state.fetchedRelays = state.fetchedRelays.filter(fetchedRelay => fetchedRelay !== relay) state.fetchedRelays = state.fetchedRelays.filter(fetchedRelay => fetchedRelay.actor !== relay)
} }
}, },
actions: { actions: {
async FetchRelays({ commit, getters }) { async FetchRelays({ commit, getters }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
const response = await fetchRelays(getters.authHost, getters.token) const { data } = await fetchRelays(getters.authHost, getters.token)
commit('SET_RELAYS', data.relays)
commit('SET_RELAYS', response.data.relays)
commit('SET_LOADING', false) commit('SET_LOADING', false)
}, },
async AddRelay({ commit, dispatch, getters }, relay) { async AddRelay({ commit, dispatch, getters }, relay) {

View file

@ -1,13 +1,23 @@
import { changeState, fetchReports, createNote, deleteNote } from '@/api/reports' import { changeState, fetchReports, fetchSingleReport, createNote, deleteNote } from '@/api/reports'
import {
activateUsers,
deactivateUsers,
deleteUsers,
tagUser,
untagUser
} from '@/api/users'
const reports = { const reports = {
state: { state: {
fetchedReports: [],
totalReportsCount: 0,
currentPage: 1, currentPage: 1,
fetchedReports: [],
loading: true,
loadingSingleReport: true,
openReportsCount: 0,
pageSize: 50, pageSize: 50,
singleReport: {},
stateFilter: '', stateFilter: '',
loading: true totalReportsCount: 0
}, },
mutations: { mutations: {
SET_LAST_REPORT_ID: (state, id) => { SET_LAST_REPORT_ID: (state, id) => {
@ -16,6 +26,9 @@ const reports = {
SET_LOADING: (state, status) => { SET_LOADING: (state, status) => {
state.loading = status state.loading = status
}, },
SET_OPEN_REPORTS_COUNT: (state, total) => {
state.openReportsCount = total
},
SET_PAGE: (state, page) => { SET_PAGE: (state, page) => {
state.currentPage = page state.currentPage = page
}, },
@ -27,22 +40,122 @@ const reports = {
}, },
SET_REPORTS_FILTER: (state, filter) => { SET_REPORTS_FILTER: (state, filter) => {
state.stateFilter = filter state.stateFilter = filter
},
SET_SINGLE_REPORT: (state, report) => {
state.singleReport = report
},
SET_SINGLE_REPORT_LOADING: (state, status) => {
state.loadingSingleReport = status
} }
}, },
actions: { actions: {
async ChangeReportState({ commit, getters, state }, reportsData) { async ActivateUserFromReports({ commit, dispatch, getters, state }, { user, reportId }) {
changeState(reportsData, getters.authHost, getters.token) try {
await activateUsers([user.nickname], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedAccount = { ...user, is_active: true }
return report.id === reportId ? { ...report, account: updatedAccount } : report
})
commit('SET_REPORTS', updatedReports)
}
dispatch('SuccessMessage')
},
async ActivateUserFromReportShow({ commit, dispatch, getters, state }, user) {
try {
await activateUsers([user.nickname], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReport = { ...state.singleReport, account: { ...user, is_active: true }}
commit('SET_SINGLE_REPORT', updatedReport)
}
dispatch('SuccessMessage')
},
async AddTagFromReports({ commit, dispatch, getters, state }, { user, tag, reportId }) {
try {
await tagUser([user.nickname], [tag], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedAccount = { ...user, tags: [...user.tags, tag] }
return report.id === reportId ? { ...report, account: updatedAccount } : report
})
commit('SET_REPORTS', updatedReports)
}
dispatch('SuccessMessage')
},
async AddTagFromReportsFromReportShow({ commit, dispatch, getters, state }, { user, tag }) {
try {
await tagUser([user.nickname], [tag], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReport = { ...state.singleReport, account: { ...user, tags: [...user.tags, tag] }}
commit('SET_SINGLE_REPORT', updatedReport)
}
dispatch('SuccessMessage')
},
async ChangeReportState({ commit, dispatch, getters, state }, reportsData) {
try {
await changeState(reportsData, getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedReportsIds = reportsData.map(({ id }) => id)
return updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report
})
const updatedReports = state.fetchedReports.map(report => { commit('SET_REPORTS', updatedReports)
const updatedReportsIds = reportsData.map(({ id }) => id) dispatch('FetchOpenReportsCount')
return updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report }
})
commit('SET_REPORTS', updatedReports)
}, },
ClearFetchedReports({ commit }) { ClearFetchedReports({ commit }) {
commit('SET_REPORTS', []) commit('SET_REPORTS', [])
}, },
async DeactivateUserFromReports({ commit, dispatch, getters, state }, { user, reportId }) {
try {
await deactivateUsers([user.nickname], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedAccount = { ...user, is_active: false }
return report.id === reportId ? { ...report, account: updatedAccount } : report
})
commit('SET_REPORTS', updatedReports)
}
dispatch('SuccessMessage')
},
async DeactivateUserFromReportShow({ commit, dispatch, getters, state }, user) {
try {
await deactivateUsers([user.nickname], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReport = { ...state.singleReport, account: { ...user, is_active: false }}
commit('SET_SINGLE_REPORT', updatedReport)
}
dispatch('SuccessMessage')
},
async DeleteUserFromReports({ commit, dispatch, getters, state }, { user, reportId }) {
try {
await deleteUsers([user.nickname], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedAccount = { ...user, is_active: false }
return report.id === reportId ? { ...report, account: updatedAccount } : report
})
commit('SET_REPORTS', updatedReports)
}
dispatch('SuccessMessage')
},
async FetchReports({ commit, getters, state }, page) { async FetchReports({ commit, getters, state }, page) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token) const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token)
@ -52,7 +165,46 @@ const reports = {
commit('SET_PAGE', page) commit('SET_PAGE', page)
commit('SET_LOADING', false) commit('SET_LOADING', false)
}, },
SetFilter({ commit }, filter) { async FetchSingleReport({ commit, getters }, id) {
commit('SET_SINGLE_REPORT_LOADING', true)
const { data } = await fetchSingleReport(id, getters.authHost, getters.token)
commit('SET_SINGLE_REPORT', data)
commit('SET_SINGLE_REPORT_LOADING', false)
},
async FetchOpenReportsCount({ commit, getters, state }) {
commit('SET_LOADING', true)
const { data } = await fetchReports('open', state.currentPage, state.pageSize, getters.authHost, getters.token)
commit('SET_OPEN_REPORTS_COUNT', data.total)
commit('SET_LOADING', false)
},
async RemoveTagFromReports({ commit, dispatch, getters, state }, { user, tag, reportId }) {
try {
await untagUser([user.nickname], [tag], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReports = state.fetchedReports.map(report => {
const updatedAccount = { ...user, tags: user.tags.filter(userTag => userTag !== tag) }
return report.id === reportId ? { ...report, account: updatedAccount } : report
})
commit('SET_REPORTS', updatedReports)
}
dispatch('SuccessMessage')
},
async RemoveTagFromReportsFromReportShow({ commit, dispatch, getters, state }, { user, tag }) {
try {
await untagUser([user.nickname], [tag], getters.authHost, getters.token)
} catch (_e) {
return
} finally {
const updatedReport = { ...state.singleReport, account: { ...user, tags: user.tags.filter(userTag => userTag !== tag) }}
commit('SET_SINGLE_REPORT', updatedReport)
}
dispatch('SuccessMessage')
},
SetReportsFilter({ commit }, filter) {
commit('SET_REPORTS_FILTER', filter) commit('SET_REPORTS_FILTER', filter)
}, },
CreateReportNote({ commit, getters, state, rootState }, { content, reportID }) { CreateReportNote({ commit, getters, state, rootState }, { content, reportID }) {
@ -61,9 +213,8 @@ const reports = {
const optimisticNote = { const optimisticNote = {
user: { user: {
avatar: rootState.user.avatar, avatar: rootState.user.avatar,
display_name: rootState.user.name, nickname: rootState.user.name,
url: `${rootState.user.authHost}/${rootState.user.name}`, id: rootState.user.id
acct: rootState.user.name
}, },
content: content, content: content,
created_at: new Date().getTime() created_at: new Date().getTime()

View file

@ -1,37 +1,60 @@
import { fetchDescription, fetchSettings, removeSettings, restartApp, updateSettings } from '@/api/settings' import {
import { checkPartialUpdate, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers' deleteInstanceDocument,
fetchDescription,
fetchFrontends,
fetchSettings,
getInstanceDocument,
installFrontend,
removeSettings,
updateInstanceDocument,
updateSettings } from '@/api/settings'
import { formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers'
import { tabs } from '../../utils/tabs'
import _ from 'lodash' import _ from 'lodash'
const settings = { const settings = {
state: { state: {
activeTab: 'instance',
configDisabled: true, configDisabled: true,
frontends: [],
db: {}, db: {},
description: [], description: [],
instancePanel: '',
loading: true, loading: true,
needReboot: false, searchData: {},
searchQuery: '',
settings: {}, settings: {},
tabs: [],
termsOfServices: '',
updatedSettings: {} updatedSettings: {}
}, },
mutations: { mutations: {
CLEAR_UPDATED_SETTINGS: (state) => { CLEAR_UPDATED_SETTINGS: (state) => {
state.updatedSettings = {} state.updatedSettings = {}
}, },
SET_INSTANCE_PANEL: (state, data) => {
state.instancePanel = data
},
REMOVE_SETTING_FROM_UPDATED: (state, { group, key, subkeys }) => { REMOVE_SETTING_FROM_UPDATED: (state, { group, key, subkeys }) => {
if (_.get(state.updatedSettings, [group, key, subkeys[0]])) { if (_.get(state.updatedSettings, [group, key, subkeys[0]])) {
const { [subkeys[0]]: value, ...updatedSettings } = state.updatedSettings[group][key] const { [subkeys[0]]: value, ...updatedSettings } = state.updatedSettings[group][key]
state.updatedSettings = updatedSettings state.updatedSettings = updatedSettings
} }
}, },
SET_ACTIVE_TAB: (state, tab) => {
state.activeTab = tab
},
SET_DESCRIPTION: (state, data) => { SET_DESCRIPTION: (state, data) => {
state.description = data state.description = data
}, },
SET_FRONTENDS: (state, data) => {
state.frontends = data
},
SET_LOADING: (state, status) => { SET_LOADING: (state, status) => {
state.loading = status state.loading = status
}, },
SET_SEARCH: (state, searchObject) => {
state.searchData = searchObject
},
SET_SEARCH_QUERY: (state, query) => {
state.searchQuery = query
},
SET_SETTINGS: (state, data) => { SET_SETTINGS: (state, data) => {
const newSettings = data.reduce((acc, { group, key, value }) => { const newSettings = data.reduce((acc, { group, key, value }) => {
const parsedValue = valueHasTuples(key, value) const parsedValue = valueHasTuples(key, value)
@ -51,8 +74,11 @@ const settings = {
state.settings = newSettings state.settings = newSettings
state.db = newDbSettings state.db = newDbSettings
}, },
TOGGLE_REBOOT: (state, needReboot) => { SET_TABS: (state, tabs) => {
state.needReboot = needReboot || false state.tabs = tabs
},
SET_TERMS_OF_SERVICES: (state, data) => {
state.termsOfServices = data
}, },
TOGGLE_TABS: (state, status) => { TOGGLE_TABS: (state, status) => {
state.configDisabled = status state.configDisabled = status
@ -71,23 +97,45 @@ const settings = {
} }
}, },
actions: { actions: {
async FetchFrontends({ commit, getters }) {
const { data } = await fetchFrontends(getters.authHost, getters.token)
commit('SET_FRONTENDS', data)
},
async FetchInstanceDocument({ commit, getters }, name) {
const { data } = await getInstanceDocument(name, getters.authHost, getters.token)
if (name === 'instance-panel') {
commit('SET_INSTANCE_PANEL', data)
} else {
commit('SET_TERMS_OF_SERVICES', data)
}
},
async FetchSettings({ commit, getters }) { async FetchSettings({ commit, getters }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
try { try {
const response = await fetchSettings(getters.authHost, getters.token) const settings = await fetchSettings(getters.authHost, getters.token)
const description = await fetchDescription(getters.authHost, getters.token) commit('SET_SETTINGS', settings.data.configs)
commit('SET_DESCRIPTION', description.data)
commit('SET_SETTINGS', response.data.configs) const { data } = await fetchDescription(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', response.data.need_reboot) commit('SET_DESCRIPTION', data)
const searchObject = formSearchObject(data)
commit('SET_SEARCH', searchObject)
commit('SET_TABS', tabs)
} catch (_e) { } catch (_e) {
commit('TOGGLE_TABS', true) commit('TOGGLE_TABS', true)
commit('SET_ACTIVE_TAB', 'relays')
commit('SET_LOADING', false) commit('SET_LOADING', false)
return return
} }
commit('TOGGLE_TABS', false) commit('TOGGLE_TABS', false)
commit('SET_LOADING', false) commit('SET_LOADING', false)
}, },
async InstallFrontend({ commit, getters }, { name, ref, file, buildUrl, buildDir }) {
const { data } = await installFrontend({ name, ref, file, build_url: buildUrl, build_dir: buildDir }, getters.authHost, getters.token)
commit('SET_FRONTENDS', data)
},
async RemoveInstanceDocument({ dispatch, getters }, name) {
await deleteInstanceDocument(name, getters.authHost, getters.token)
await dispatch('FetchInstanceDocument', name)
},
async RemoveSetting({ commit, getters }, configs) { async RemoveSetting({ commit, getters }, configs) {
await removeSettings(configs, getters.authHost, getters.token) await removeSettings(configs, getters.authHost, getters.token)
const response = await fetchSettings(getters.authHost, getters.token) const response = await fetchSettings(getters.authHost, getters.token)
@ -96,17 +144,12 @@ const settings = {
commit('TOGGLE_REBOOT', response.data.need_reboot) commit('TOGGLE_REBOOT', response.data.need_reboot)
commit('REMOVE_SETTING_FROM_UPDATED', { group, key, subkeys: subkeys || [] }) commit('REMOVE_SETTING_FROM_UPDATED', { group, key, subkeys: subkeys || [] })
}, },
async RestartApplication({ commit, getters }) { SetSearchQuery({ commit }, query) {
await restartApp(getters.authHost, getters.token) commit('SET_SEARCH_QUERY', query)
commit('TOGGLE_REBOOT', false)
},
SetActiveTab({ commit }, tab) {
commit('SET_ACTIVE_TAB', tab)
}, },
async SubmitChanges({ getters, commit, state }) { async SubmitChanges({ getters, commit, state }) {
const updatedData = checkPartialUpdate(state.settings, state.updatedSettings, state.description) const configs = Object.keys(state.updatedSettings).reduce((acc, group) => {
const configs = Object.keys(updatedData).reduce((acc, group) => { return [...acc, ...wrapUpdatedSettings(group, state.updatedSettings[group], state.settings)]
return [...acc, ...wrapUpdatedSettings(group, updatedData[group], state.settings)]
}, []) }, [])
await updateSettings(configs, getters.authHost, getters.token) await updateSettings(configs, getters.authHost, getters.token)
@ -115,6 +158,13 @@ const settings = {
commit('TOGGLE_REBOOT', response.data.need_reboot) commit('TOGGLE_REBOOT', response.data.need_reboot)
commit('CLEAR_UPDATED_SETTINGS') commit('CLEAR_UPDATED_SETTINGS')
}, },
async UpdateInstanceDocs({ commit, getters }, { name, content }) {
commit('SET_INSTANCE_PANEL', content)
const formData = new FormData()
const blob = new Blob([content], { type: 'text/html' })
formData.append('file', blob)
await updateInstanceDocument(name, formData, getters.authHost, getters.token)
},
UpdateSettings({ commit }, { group, key, input, value, type }) { UpdateSettings({ commit }, { group, key, input, value, type }) {
key key
? commit('UPDATE_SETTINGS', { group, key, input, value, type }) ? commit('UPDATE_SETTINGS', { group, key, input, value, type })

View file

@ -1,9 +1,11 @@
import { changeStatusScope, deleteStatus, fetchStatuses, fetchStatusesCount, fetchStatusesByInstance } from '@/api/status' import { changeStatusScope, deleteStatus, fetchStatus, fetchStatuses, fetchStatusesCount, fetchStatusesByInstance } from '@/api/status'
const status = { const status = {
state: { state: {
fetchedStatus: {},
fetchedStatuses: [], fetchedStatuses: [],
loading: false, loading: false,
statusAuthor: {},
statusesByInstance: { statusesByInstance: {
selectedInstance: '', selectedInstance: '',
showLocal: false, showLocal: false,
@ -28,6 +30,9 @@ const status = {
CHANGE_SELECTED_INSTANCE: (state, instance) => { CHANGE_SELECTED_INSTANCE: (state, instance) => {
state.statusesByInstance.selectedInstance = instance state.statusesByInstance.selectedInstance = instance
}, },
SET_STATUS: (state, status) => {
state.fetchedStatus = status
},
SET_STATUSES_BY_INSTANCE: (state, statuses) => { SET_STATUSES_BY_INSTANCE: (state, statuses) => {
state.fetchedStatuses = statuses state.fetchedStatuses = statuses
}, },
@ -45,6 +50,9 @@ const status = {
}, },
SET_STATUS_VISIBILITY: (state, visibility) => { SET_STATUS_VISIBILITY: (state, visibility) => {
state.statusVisibility = visibility state.statusVisibility = visibility
},
SET_STATUS_AUTHOR: (state, user) => {
state.statusAuthor = user
} }
}, },
actions: { actions: {
@ -56,8 +64,18 @@ const status = {
dispatch('FetchUserStatuses', { userId, godmode }) dispatch('FetchUserStatuses', { userId, godmode })
} else if (fetchStatusesByInstance) { // called from Statuses by Instance } else if (fetchStatusesByInstance) { // called from Statuses by Instance
dispatch('FetchStatusesByInstance') dispatch('FetchStatusesByInstance')
} else { // called from Status show page
dispatch('FetchStatusAfterUserModeration', statusId)
} }
}, },
ClearState({ commit }) {
commit('CHANGE_SELECTED_INSTANCE', '')
commit('SET_STATUSES_BY_INSTANCE', [])
commit('CHANGE_LOCAL_CHECKBOX_VALUE', false)
commit('CHANGE_GODMODE_CHECKBOX_VALUE', false)
commit('SET_ALL_LOADED', false)
commit('CHANGE_PAGE', 1)
},
async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode, fetchStatusesByInstance }) { async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode, fetchStatusesByInstance }) {
await deleteStatus(statusId, getters.authHost, getters.token) await deleteStatus(statusId, getters.authHost, getters.token)
if (reportCurrentPage !== 0) { // called from Reports if (reportCurrentPage !== 0) { // called from Reports
@ -68,14 +86,30 @@ const status = {
dispatch('FetchStatusesByInstance') dispatch('FetchStatusesByInstance')
} }
}, },
async FetchStatusesCount({ commit, getters }) { async FetchStatus({ commit, dispatch, getters, state }, id) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
const { data } = await fetchStatusesCount(getters.authHost, getters.token) const status = await fetchStatus(id, getters.authHost, getters.token)
commit('SET_STATUS', status.data)
commit('SET_STATUS_AUTHOR', status.data.account)
commit('SET_LOADING', false)
dispatch('FetchUserStatuses', { userId: state.fetchedStatus.account.id, godmode: false })
},
FetchStatusAfterUserModeration({ commit, dispatch, getters, state }, id) {
commit('SET_LOADING', true)
fetchStatus(id, getters.authHost, getters.token)
.then(status => dispatch('SetStatus', status.data))
commit('SET_LOADING', false)
},
async FetchStatusesCount({ commit, getters }, instance) {
commit('SET_LOADING', true)
const { data } = await fetchStatusesCount(instance, getters.authHost, getters.token)
commit('SET_STATUS_VISIBILITY', data.status_visibility) commit('SET_STATUS_VISIBILITY', data.status_visibility)
commit('SET_LOADING', false) commit('SET_LOADING', false)
}, },
async FetchStatusesByInstance({ commit, getters, state, rootState }) { async FetchStatusesByInstance({ commit, dispatch, getters, state, rootState }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
dispatch('FetchStatusesCount', state.statusesByInstance.selectedInstance)
if (state.statusesByInstance.selectedInstance === '') { if (state.statusesByInstance.selectedInstance === '') {
commit('SET_STATUSES_BY_INSTANCE', []) commit('SET_STATUSES_BY_INSTANCE', [])
} else { } else {
@ -150,6 +184,10 @@ const status = {
}, },
HandlePageChange({ commit }, page) { HandlePageChange({ commit }, page) {
commit('CHANGE_PAGE', page) commit('CHANGE_PAGE', page)
},
SetStatus({ commit }, status) {
commit('SET_STATUS', status)
commit('SET_STATUS_AUTHOR', status.account)
} }
} }
} }

View file

@ -72,15 +72,19 @@ const user = {
}) })
}) })
}, },
async GetNodeInfo({ commit, state }) { async GetNodeInfo({ commit, dispatch, state }) {
const nodeInfo = await getNodeInfo(state.authHost) const nodeInfo = await getNodeInfo(state.authHost)
commit('SET_NODE_INFO', nodeInfo.data) commit('SET_NODE_INFO', nodeInfo.data)
dispatch('SetInvitesEnabled', nodeInfo.data.metadata.invitesEnabled)
}, },
GetUserInfo({ commit, state }) { GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getUserInfo(state.token, state.authHost).then(response => { getUserInfo(state.token, state.authHost).then(response => {
const data = response.data const data = response.data
const message = '<span>This user doesn\`t have admin rights. Try another credentials or see the </span>' +
'<u><a target="_blank" href="https://docs.pleroma.social/backend/administration/CLI_tasks/user/#set-the-value-of-the-given-users-settings">docs</a></u>' +
'<span> to find out how to make this user an admin</span>'
if (!data) { if (!data) {
reject('Verification failed, please login again.') reject('Verification failed, please login again.')
@ -89,7 +93,7 @@ const user = {
if (data.pleroma && data.pleroma.is_admin) { if (data.pleroma && data.pleroma.is_admin) {
commit('SET_ROLES', ['admin']) commit('SET_ROLES', ['admin'])
} else { } else {
reject('getInfo: roles must be a non-null array!') reject(message)
} }
commit('SET_NAME', data.username) commit('SET_NAME', data.username)

View file

@ -35,18 +35,21 @@ const userProfile = {
dispatch('FetchUserStatuses', { userId, godmode }) dispatch('FetchUserStatuses', { userId, godmode })
}, },
async FetchUserStatuses({ commit, getters }, { userId, godmode }) { FetchUserStatuses({ commit, dispatch, getters }, { userId, godmode }) {
commit('SET_STATUSES_LOADING', true) commit('SET_STATUSES_LOADING', true)
const statuses = await fetchUserStatuses(userId, getters.authHost, godmode, getters.token) fetchUserStatuses(userId, getters.authHost, godmode, getters.token)
.then(statuses => dispatch('SetStatuses', statuses.data.activities))
commit('SET_STATUSES', statuses.data)
commit('SET_STATUSES_LOADING', false) commit('SET_STATUSES_LOADING', false)
}, },
async FetchUserCredentials({ commit, getters }, { nickname }) { async FetchUserCredentials({ commit, getters }, { nickname }) {
const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token) const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token)
commit('SET_USER_CREDENTIALS', userResponse.data) commit('SET_USER_CREDENTIALS', userResponse.data)
}, },
SetStatuses({ commit }, statuses) {
commit('SET_STATUSES', statuses)
},
async UpdateUserCredentials({ dispatch, getters }, { nickname, credentials }) { async UpdateUserCredentials({ dispatch, getters }, { nickname, credentials }) {
await updateUserCredentials(nickname, credentials, getters.authHost, getters.token) await updateUserCredentials(nickname, credentials, getters.authHost, getters.token)
dispatch('FetchUserCredentials', { nickname }) dispatch('FetchUserCredentials', { nickname })

View file

@ -7,35 +7,40 @@ import {
deactivateUsers, deactivateUsers,
deleteRight, deleteRight,
deleteUsers, deleteUsers,
disableMfa,
fetchUsers, fetchUsers,
getPasswordResetToken, getPasswordResetToken,
searchUsers, searchUsers,
tagUser, tagUser,
untagUser, untagUser,
forcePasswordReset, forcePasswordReset,
approveUserAccount,
confirmUserEmail, confirmUserEmail,
resendConfirmationEmail resendConfirmationEmail,
updateUserCredentials
} from '@/api/users' } from '@/api/users'
import { fetchSettings, updateSettings } from '@/api/settings'
const users = { const users = {
state: { state: {
fetchedUsers: [], fetchedUsers: [],
loading: true, loading: true,
searchQuery: '', searchQuery: '',
mrfPolicies: [],
totalUsersCount: 0, totalUsersCount: 0,
currentPage: 1, currentPage: 1,
filters: { pageSize: 50,
local: false, actorTypeFilters: [],
external: false, filters: [],
active: false,
deactivated: false
},
passwordResetToken: { passwordResetToken: {
token: '', token: '',
link: '' link: ''
} }
}, },
mutations: { mutations: {
SET_ACTOR_TYPE_FILTERS: (state, actorTypeFilters) => {
state.actorTypeFilters = actorTypeFilters
},
SET_USERS: (state, users) => { SET_USERS: (state, users) => {
state.fetchedUsers = users state.fetchedUsers = users
}, },
@ -51,9 +56,11 @@ const users = {
return return
} }
state.fetchedUsers = [...usersWithoutSwapped, ...users].sort((a, b) => const updatedUsers = [...usersWithoutSwapped, ...users]
a.nickname.localeCompare(b.nickname) state.fetchedUsers = updatedUsers
) .filter(user => user.nickname && user.id)
.sort((a, b) => a.nickname.localeCompare(b.nickname))
.concat(updatedUsers.filter(user => !user.nickname || !user.id))
}, },
SET_COUNT: (state, count) => { SET_COUNT: (state, count) => {
state.totalUsersCount = count state.totalUsersCount = count
@ -71,24 +78,24 @@ const users = {
SET_SEARCH_QUERY: (state, query) => { SET_SEARCH_QUERY: (state, query) => {
state.searchQuery = query state.searchQuery = query
}, },
SET_TAG_POLICY: (state, mrfPolicies) => {
state.mrfPolicies = mrfPolicies
},
SET_USERS_FILTERS: (state, filters) => { SET_USERS_FILTERS: (state, filters) => {
state.filters = filters state.filters = filters
},
SET_USER_PROFILE: (state, user) => {
state.userProfile = user
} }
}, },
actions: { actions: {
async ActivateUsers({ dispatch, getters }, { users, _userId }) { async ActivateUsers({ dispatch, getters }, { users, _userId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return { ...user, deactivated: false } return { ...user, is_active: true }
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await activateUsers(nicknames, getters.authHost, getters.token) const callApiFn = async() => await activateUsers(nicknames, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
}, },
async ApplyChanges({ commit, dispatch, state }, { updatedUsers, callApiFn, userId }) { async ApplyChanges({ commit, dispatch, state }, { updatedUsers, callApiFn, userId, statusId }) {
commit('SWAP_USERS', updatedUsers) commit('SWAP_USERS', updatedUsers)
try { try {
@ -98,34 +105,57 @@ const users = {
} finally { } finally {
dispatch('SearchUsers', { query: state.searchQuery, page: state.currentPage }) dispatch('SearchUsers', { query: state.searchQuery, page: state.currentPage })
} }
if (statusId) {
if (userId) { dispatch('FetchStatusAfterUserModeration', statusId)
} else if (userId) {
dispatch('FetchUserProfile', { userId, godmode: false }) dispatch('FetchUserProfile', { userId, godmode: false })
} }
dispatch('SuccessMessage') dispatch('SuccessMessage')
}, },
async AddRight({ dispatch, getters }, { users, right, _userId }) { async AddRight({ dispatch, getters }, { users, right, _userId, _statusId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return user.local ? { ...user, roles: { ...user.roles, [right]: true }} : user return user.local ? { ...user, roles: { ...user.roles, [right]: true }} : user
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await addRight(nicknames, right, getters.authHost, getters.token) const callApiFn = async() => await addRight(nicknames, right, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
}, },
async AddTag({ dispatch, getters }, { users, tag, _userId }) { async AddTag({ dispatch, getters }, { users, tag, _userId, _statusId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return { ...user, tags: [...user.tags, tag] } return { ...user, tags: [...user.tags, tag] }
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await tagUser(nicknames, [tag], getters.authHost, getters.token) const callApiFn = async() => await tagUser(nicknames, [tag], getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
},
async ApproveUsersAccount({ dispatch, getters }, { users, _userId, _statusId }) {
const updatedUsers = users.map(user => {
return { ...user, is_approved: true }
})
const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await approveUserAccount(nicknames, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
},
ClearUsersState({ commit }) {
commit('SET_SEARCH_QUERY', '')
commit('SET_USERS_FILTERS', [])
}, },
async ClearFilters({ commit, dispatch, state }) { async ClearFilters({ commit, dispatch, state }) {
commit('CLEAR_USERS_FILTERS') commit('CLEAR_USERS_FILTERS')
dispatch('SearchUsers', { query: state.searchQuery, page: 1 }) dispatch('SearchUsers', { query: state.searchQuery, page: 1 })
}, },
async ConfirmUsersEmail({ dispatch, getters }, { users, _userId, _statusId }) {
const updatedUsers = users.map(user => {
return { ...user, is_confirmed: true }
})
const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await confirmUserEmail(nicknames, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
},
async CreateNewAccount({ dispatch, getters, state }, { nickname, email, password }) { async CreateNewAccount({ dispatch, getters, state }, { nickname, email, password }) {
try { try {
await createNewAccount(nickname, email, password, getters.authHost, getters.token) await createNewAccount(nickname, email, password, getters.authHost, getters.token)
@ -138,39 +168,29 @@ const users = {
}, },
async DeactivateUsers({ dispatch, getters }, { users, _userId }) { async DeactivateUsers({ dispatch, getters }, { users, _userId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return { ...user, deactivated: true } return { ...user, is_active: false }
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await deactivateUsers(nicknames, getters.authHost, getters.token) const callApiFn = async() => await deactivateUsers(nicknames, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
}, },
async ConfirmUsersEmail({ dispatch, getters }, { users, _userId }) { async DisableMfa({ dispatch, getters }, nickname) {
const updatedUsers = users.map(user => {
return { ...user, confirmation_pending: false }
})
const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await confirmUserEmail(nicknames, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
},
async ResendConfirmationEmail({ dispatch, getters }, users) {
const usersNicknames = users.map(user => user.nickname)
try { try {
await resendConfirmationEmail(usersNicknames, getters.authHost, getters.token) await disableMfa(nickname, getters.authHost, getters.token)
} catch (_e) { } catch (_e) {
return return
} }
dispatch('SuccessMessage') dispatch('SuccessMessage')
}, },
async DeleteRight({ dispatch, getters }, { users, right, _userId }) { async DeleteRight({ dispatch, getters }, { users, right, _userId, _statusId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return user.local ? { ...user, roles: { ...user.roles, [right]: false }} : user return user.local ? { ...user, roles: { ...user.roles, [right]: false }} : user
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await deleteRight(nicknames, right, getters.authHost, getters.token) const callApiFn = async() => await deleteRight(nicknames, right, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
}, },
async DeleteUsers({ commit, dispatch, getters, state }, { users, _userId }) { async DeleteUsers({ commit, dispatch, getters, state }, { users, _userId }) {
const usersNicknames = users.map(user => user.nickname) const usersNicknames = users.map(user => user.nickname)
@ -179,17 +199,41 @@ const users = {
} catch (_e) { } catch (_e) {
return return
} }
const deletedUsersIds = users.map(deletedUser => deletedUser.id) const updatedUsers = users.map(user => {
const updatedUsers = state.fetchedUsers.filter(user => !deletedUsersIds.includes(user.id)) return { ...user, is_active: false }
commit('SET_USERS', updatedUsers) })
commit('SWAP_USERS', updatedUsers)
dispatch('FetchUserProfile', { userId: _userId, godmode: false }) if (_userId) {
dispatch('FetchUserProfile', { userId: _userId, godmode: false })
}
dispatch('SuccessMessage') dispatch('SuccessMessage')
}, },
async EnableTagPolicy({ dispatch, getters, state }) {
const configs = [{
group: ':pleroma',
key: ':mrf',
value: [{ tuple: [':policies', [...state.mrfPolicies, 'Pleroma.Web.ActivityPub.MRF.TagPolicy']] }]
}]
await updateSettings(configs, getters.authHost, getters.token)
dispatch('FetchTagPolicySetting')
},
async FetchTagPolicySetting({ commit, getters }) {
const { data } = await fetchSettings(getters.authHost, getters.token)
const mrfSettings = data.configs.find(el => el.key === ':mrf')
? data.configs.find(el => el.key === ':mrf').value
: []
const mrfPolicies = mrfSettings.find(el => el.tuple[0] === ':policies')
? mrfSettings.find(el => el.tuple[0] === ':policies').tuple[1]
: []
commit('SET_TAG_POLICY', Array.isArray(mrfPolicies) ? mrfPolicies : [mrfPolicies])
},
async FetchUsers({ commit, dispatch, getters, state }, { page }) { async FetchUsers({ commit, dispatch, getters, state }, { page }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
const filters = Object.keys(state.filters).filter(filter => state.filters[filter]).join() const filters = state.filters.join()
const response = await fetchUsers(filters, getters.authHost, getters.token, page) const response = await fetchUsers(filters, state.actorTypeFilters, getters.authHost, getters.token, page)
await dispatch('GetNodeInfo') await dispatch('GetNodeInfo')
loadUsers(commit, page, response.data) loadUsers(commit, page, response.data)
}, },
@ -200,14 +244,14 @@ const users = {
RemovePasswordToken({ commit }) { RemovePasswordToken({ commit }) {
commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' }) commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' })
}, },
async RemoveTag({ dispatch, getters }, { users, tag, _userId }) { async RemoveTag({ dispatch, getters }, { users, tag, _userId, _statusId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return { ...user, tags: user.tags.filter(userTag => userTag !== tag) } return { ...user, tags: user.tags.filter(userTag => userTag !== tag) }
}) })
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
const callApiFn = async() => await untagUser(nicknames, [tag], getters.authHost, getters.token) const callApiFn = async() => await untagUser(nicknames, [tag], getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId }) dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
}, },
async RequirePasswordReset({ dispatch, getters }, users) { async RequirePasswordReset({ dispatch, getters }, users) {
const nicknames = users.map(user => user.nickname) const nicknames = users.map(user => user.nickname)
@ -218,6 +262,15 @@ const users = {
} }
dispatch('SuccessMessage') dispatch('SuccessMessage')
}, },
async ResendConfirmationEmail({ dispatch, getters }, users) {
const usersNicknames = users.map(user => user.nickname)
try {
await resendConfirmationEmail(usersNicknames, getters.authHost, getters.token)
} catch (_e) {
return
}
dispatch('SuccessMessage')
},
async SearchUsers({ commit, dispatch, state, getters }, { query, page }) { async SearchUsers({ commit, dispatch, state, getters }, { query, page }) {
if (query.length === 0) { if (query.length === 0) {
commit('SET_SEARCH_QUERY', query) commit('SET_SEARCH_QUERY', query)
@ -226,8 +279,8 @@ const users = {
commit('SET_LOADING', true) commit('SET_LOADING', true)
commit('SET_SEARCH_QUERY', query) commit('SET_SEARCH_QUERY', query)
const filters = Object.keys(state.filters).filter(filter => state.filters[filter]).join() const filters = state.filters.join()
const response = await searchUsers(query, filters, getters.authHost, getters.token, page) const response = await searchUsers(query, filters, state.actorTypeFilters, getters.authHost, getters.token, page)
loadUsers(commit, page, response.data) loadUsers(commit, page, response.data)
} }
@ -238,16 +291,21 @@ const users = {
duration: 5 * 1000 duration: 5 * 1000
}) })
}, },
async ToggleUsersFilter({ commit, dispatch, state }, filters) { async ToggleActorTypeFilter({ commit, dispatch, state }, actorTypeFilters) {
const defaultFilters = { commit('SET_ACTOR_TYPE_FILTERS', actorTypeFilters)
local: false,
external: false,
active: false,
deactivated: false
}
const currentFilters = { ...defaultFilters, ...filters }
commit('SET_USERS_FILTERS', currentFilters)
dispatch('SearchUsers', { query: state.searchQuery, page: 1 }) dispatch('SearchUsers', { query: state.searchQuery, page: 1 })
},
async ToggleUsersFilter({ commit, dispatch, state }, filters) {
commit('SET_USERS_FILTERS', filters)
dispatch('SearchUsers', { query: state.searchQuery, page: 1 })
},
async UpdateActorType({ dispatch, getters }, { user, type, _userId, _statusId }) {
const updatedUsers = [{ ...user, actor_type: type }]
const credentials = { actor_type: type }
const callApiFn = async() => await updateUserCredentials(user.nickname, credentials, getters.authHost, getters.token)
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
} }
} }
} }

View file

@ -101,7 +101,6 @@ div:focus {
code { code {
background: #eef1f6; background: #eef1f6;
padding: 15px 16px; padding: 15px 16px;
margin-bottom: 20px;
display: block; display: block;
line-height: 36px; line-height: 36px;
font-size: 15px; font-size: 15px;
@ -172,32 +171,3 @@ code {
background: #d0d0d0; background: #d0d0d0;
} }
} }
.link-type,
.link-type:focus {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
.filter-container {
padding-bottom: 10px;
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
}
//refine vue-multiselect plugin
.multiselect {
line-height: 16px;
}
.multiselect--active {
z-index: 1000 !important;
}

View file

@ -18,7 +18,7 @@
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 1001; z-index: 5000;
overflow: hidden; overflow: hidden;
//reset element-ui css //reset element-ui css
@ -91,7 +91,7 @@
} }
.submenu-title-noDropdown { .submenu-title-noDropdown {
padding-left: 10px !important; padding-left: 8px !important;
position: relative; position: relative;
.el-tooltip { .el-tooltip {

View file

@ -19,7 +19,7 @@ $menuHover:#263445;
$subMenuBg:#1f2d3d; $subMenuBg:#1f2d3d;
$subMenuHover:#001528; $subMenuHover:#001528;
$sideBarWidth: 180px; $sideBarWidth: 205px;
// the :export directive is the magic sauce for webpack // the :export directive is the magic sauce for webpack
:export { :export {

View file

@ -3,7 +3,7 @@ import Clipboard from 'clipboard'
function clipboardSuccess() { function clipboardSuccess() {
Vue.prototype.$message({ Vue.prototype.$message({
message: 'Copy successfully', message: 'Copied!',
type: 'success', type: 'success',
duration: 1500 duration: 1500
}) })

View file

@ -6,27 +6,32 @@ const service = axios.create({
timeout: 60000 // request timeout timeout: 60000 // request timeout
}) })
const isJson = ({ headers }) => headers['content-type'].includes('application/json')
// response interceptor // response interceptor
service.interceptors.response.use( service.interceptors.response.use(
response => response, response => response,
error => { error => {
let errorMessage
console.log(`Error ${error}`) console.log(`Error ${error}`)
if (error.response) { if (!error.response) {
const edata = error.response.data.error ? error.response.data.error : error.response.data Message({
errorMessage = !error.response.headers['content-type'].includes('application/json') message: error,
? `${error.message}` type: 'error',
: `${error.message} - ${edata}` duration: 5 * 1000
})
} else { } else {
errorMessage = error const errors = Array.isArray(error.response.data) ? error.response.data : [error.response.data]
errors.forEach(errorData => {
const edata = errorData.error || errorData
Message({
message: isJson(error.response) ? `${error.message} - ${edata}` : `${error.message}`,
type: 'error',
duration: 5 * 1000
})
})
} }
Message({
message: errorMessage,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error) return Promise.reject(error)
} }
) )

21
src/utils/tabs.js Normal file
View file

@ -0,0 +1,21 @@
export const tabs = [
{ label: 'ActivityPub', path: 'activity-pub', tab: ':activity_pub' },
{ label: 'Authentication', path: 'authentication', tab: ':authentication' },
{ label: 'Captcha', path: 'captcha', tab: ':captcha' },
{ label: 'Emoji', path: 'emoji', tab: ':emoji' },
{ label: 'Frontend', path: 'frontend', tab: ':frontend' },
{ label: 'HTTP', path: 'http', tab: ':http' },
{ label: 'Instance', path: 'instance', tab: ':instance' },
{ label: 'Job queue', path: 'job-queue', tab: ':job_queue' },
{ label: 'Link Formatter', path: 'link-formatter', tab: ':link_formatter' },
{ label: 'Logger', path: 'logger', tab: ':logger' },
{ label: 'Mailer', path: 'mailer', tab: ':mailer' },
{ label: 'Media Proxy', path: 'media-proxy', tab: ':media_proxy' },
{ label: 'Metadata', path: 'metadata', tab: ':metadata' },
{ label: 'MRF', path: 'mrf', tab: ':mrf' },
{ label: 'Rate limiters', path: 'rate-limiters', tab: ':rate_limiters' },
{ label: 'Web push encryption', path: 'web-push', tab: ':web_push' },
{ label: 'Upload', path: 'upload', tab: ':upload' },
{ label: 'Search', path: 'search', tab: ':search' },
{ label: 'Other', path: 'other', tab: ':other' }
]

View file

@ -1,23 +0,0 @@
<template>
<div class="chart-container">
<chart height="100%" width="100%"/>
</div>
</template>
<script>
import Chart from '@/components/element-ui/Charts/keyboard'
export default {
name: 'KeyboardChart',
components: { Chart }
}
</script>
<style scoped>
.chart-container{
position: relative;
width: 100%;
height: calc(100vh - 84px);
}
</style>

View file

@ -1,23 +0,0 @@
<template>
<div class="chart-container">
<chart height="100%" width="100%"/>
</div>
</template>
<script>
import Chart from '@/components/element-ui/Charts/lineMarker'
export default {
name: 'LineChart',
components: { Chart }
}
</script>
<style scoped>
.chart-container{
position: relative;
width: 100%;
height: calc(100vh - 84px);
}
</style>

View file

@ -1,23 +0,0 @@
<template>
<div class="chart-container">
<chart height="100%" width="100%"/>
</div>
</template>
<script>
import Chart from '@/components/element-ui/Charts/mixChart'
export default {
name: 'MixChart',
components: { Chart }
}
</script>
<style scoped>
.chart-container{
position: relative;
width: 100%;
height: calc(100vh - 84px);
}
</style>

View file

@ -1,45 +0,0 @@
<template>
<div class="app-container">
<el-tabs v-model="activeName">
<el-tab-pane label="use clipboard directly" name="directly">
<el-input v-model="inputData" placeholder="Please input" style="width:400px;max-width:100%;"/>
<el-button type="primary" icon="document" @click="handleCopy(inputData,$event)">copy</el-button>
</el-tab-pane>
<el-tab-pane label="use clipboard by v-directive" name="v-directive">
<el-input v-model="inputData" placeholder="Please input" style="width:400px;max-width:100%;"/>
<el-button v-clipboard:copy="inputData" v-clipboard:success="clipboardSuccess" type="primary" icon="document">copy</el-button>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import clip from '@/utils/clipboard' // use clipboard directly
import clipboard from '@/directive/clipboard/index.js' // use clipboard by v-directive
export default {
name: 'ClipboardDemo',
directives: {
clipboard
},
data: function() {
return {
activeName: 'directly',
inputData: 'https://github.com/PanJiaChen/vue-element-admin'
}
},
methods: {
handleCopy(text, event) {
clip(text, event)
},
clipboardSuccess() {
this.$message({
message: 'Copy successfully',
type: 'success',
duration: 1500
})
}
}
}
</script>

View file

@ -1,106 +0,0 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils'
const animationDuration = 6000
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data: function() {
return {
chart: null
}
},
mounted() {
this.initChart()
this.__resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
},
beforeDestroy() {
if (!this.chart) {
return
}
window.removeEventListener('resize', this.__resizeHandler)
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { //
type: 'shadow' // 线'line' | 'shadow'
}
},
grid: {
top: 10,
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}],
yAxis: [{
type: 'value',
axisTick: {
show: false
}
}],
series: [{
name: 'pageA',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [79, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageB',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [80, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageC',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [30, 52, 200, 334, 390, 330, 220],
animationDuration
}]
})
}
}
}
</script>

View file

@ -1,118 +0,0 @@
<template>
<el-card class="box-card-component" style="margin-left:8px;">
<div slot="header" class="box-card-header">
<img src="https://wpimg.wallstcn.com/e7d23d71-cf19-4b90-a1cc-f56af8c0903d.png">
</div>
<div style="position:relative;">
<pan-thumb :image="avatar" class="panThumb"/>
<mallki class-name="mallki-text" text="vue-element-admin"/>
<div style="padding-top:35px;" class="progress-item">
<span>Vue</span>
<el-progress :percentage="70"/>
</div>
<div class="progress-item">
<span>JavaScript</span>
<el-progress :percentage="18"/>
</div>
<div class="progress-item">
<span>Css</span>
<el-progress :percentage="12"/>
</div>
<div class="progress-item">
<span>ESLint</span>
<el-progress :percentage="100" status="success"/>
</div>
</div>
</el-card>
</template>
<script>
import { mapGetters } from 'vuex'
import PanThumb from '@/components/element-ui/PanThumb'
import Mallki from '@/components/element-ui/TextHoverEffect/Mallki'
export default {
components: { PanThumb, Mallki },
filters: {
statusFilter(status) {
const statusMap = {
success: 'success',
pending: 'danger'
}
return statusMap[status]
}
},
data: function() {
return {
statisticsData: {
article_count: 1024,
pageviews_count: 1024
}
}
},
computed: {
...mapGetters([
'name',
'avatar',
'roles'
])
}
}
</script>
<style rel="stylesheet/scss" lang="scss" >
.box-card-component{
.el-card__header {
padding: 0px!important;
}
}
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
.box-card-component {
.box-card-header {
position: relative;
height: 220px;
img {
width: 100%;
height: 100%;
transition: all 0.2s linear;
&:hover {
transform: scale(1.1, 1.1);
filter: contrast(130%);
}
}
}
.mallki-text {
position: absolute;
top: 0px;
right: 0px;
font-size: 20px;
font-weight: bold;
}
.panThumb {
z-index: 100;
height: 70px!important;
width: 70px!important;
position: absolute!important;
top: -45px;
left: 0px;
border: 5px solid #ffffff;
background-color: #fff;
margin: auto;
box-shadow: none!important;
/deep/ .pan-info {
box-shadow: none!important;
}
}
.progress-item {
margin-bottom: 10px;
font-size: 14px;
}
@media only screen and (max-width: 1510px){
.mallki-text{
display: none;
}
}
}
</style>

View file

@ -1,156 +0,0 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils'
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
autoResize: {
type: Boolean,
default: true
},
chartData: {
type: Object,
required: true
}
},
data: function() {
return {
chart: null,
sidebarElm: null
}
},
watch: {
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
},
mounted() {
this.initChart()
if (this.autoResize) {
this.__resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
}
//
this.sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler)
},
beforeDestroy() {
if (!this.chart) {
return
}
if (this.autoResize) {
window.removeEventListener('resize', this.__resizeHandler)
}
this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler)
this.chart.dispose()
this.chart = null
},
methods: {
sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.__resizeHandler()
}
},
setOptions({ expectedData, actualData } = {}) {
this.chart.setOption({
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
boundaryGap: false,
axisTick: {
show: false
}
},
grid: {
left: 10,
right: 10,
bottom: 20,
top: 30,
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
padding: [5, 10]
},
yAxis: {
axisTick: {
show: false
}
},
legend: {
data: ['expected', 'actual']
},
series: [{
name: 'expected', itemStyle: {
normal: {
color: '#FF005A',
lineStyle: {
color: '#FF005A',
width: 2
}
}
},
smooth: true,
type: 'line',
data: expectedData,
animationDuration: 2800,
animationEasing: 'cubicInOut'
},
{
name: 'actual',
smooth: true,
type: 'line',
itemStyle: {
normal: {
color: '#3888fa',
lineStyle: {
color: '#3888fa',
width: 2
},
areaStyle: {
color: '#f3f8ff'
}
}
},
data: actualData,
animationDuration: 2800,
animationEasing: 'quadraticOut'
}]
})
},
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.setOptions(this.chartData)
}
}
}
</script>

View file

@ -1,138 +0,0 @@
<template>
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('newVisitis')">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="peoples" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">New Visits</div>
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('messages')">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="message" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Messages</div>
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="money" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Purchases</div>
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="shopping" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Shoppings</div>
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num"/>
</div>
</div>
</el-col>
</el-row>
</template>
<script>
import CountTo from 'vue-count-to'
export default {
components: {
CountTo
},
methods: {
handleSetLineChartData(type) {
this.$emit('handleSetLineChartData', type)
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.panel-group {
margin-top: 18px;
.card-panel-col{
margin-bottom: 32px;
}
.card-panel {
height: 108px;
cursor: pointer;
font-size: 12px;
position: relative;
overflow: hidden;
color: #666;
background: #fff;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
border-color: rgba(0, 0, 0, .05);
&:hover {
.card-panel-icon-wrapper {
color: #fff;
}
.icon-people {
background: #40c9c6;
}
.icon-message {
background: #36a3f7;
}
.icon-money {
background: #f4516c;
}
.icon-shopping {
background: #34bfa3
}
}
.icon-people {
color: #40c9c6;
}
.icon-message {
color: #36a3f7;
}
.icon-money {
color: #f4516c;
}
.icon-shopping {
color: #34bfa3
}
.card-panel-icon-wrapper {
float: left;
margin: 14px 0 0 14px;
padding: 16px;
transition: all 0.38s ease-out;
border-radius: 6px;
}
.card-panel-icon {
float: left;
font-size: 48px;
}
.card-panel-description {
float: right;
font-weight: bold;
margin: 26px;
margin-left: 0px;
.card-panel-text {
line-height: 18px;
color: rgba(0, 0, 0, 0.45);
font-size: 16px;
margin-bottom: 12px;
}
.card-panel-num {
font-size: 20px;
}
}
}
}
</style>

View file

@ -1,84 +0,0 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils'
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data: function() {
return {
chart: null
}
},
mounted() {
this.initChart()
this.__resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
},
beforeDestroy() {
if (!this.chart) {
return
}
window.removeEventListener('resize', this.__resizeHandler)
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
left: 'center',
bottom: '10',
data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
},
calculable: true,
series: [
{
name: 'WEEKLY WRITE ARTICLES',
type: 'pie',
roseType: 'radius',
radius: [15, 95],
center: ['50%', '38%'],
data: [
{ value: 320, name: 'Industries' },
{ value: 240, name: 'Technology' },
{ value: 149, name: 'Forex' },
{ value: 100, name: 'Gold' },
{ value: 59, name: 'Forecasts' }
],
animationEasing: 'cubicInOut',
animationDuration: 2600
}
]
})
}
}
}
</script>

View file

@ -1,120 +0,0 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils'
const animationDuration = 3000
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data: function() {
return {
chart: null
}
},
mounted() {
this.initChart()
this.__resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
},
beforeDestroy() {
if (!this.chart) {
return
}
window.removeEventListener('resize', this.__resizeHandler)
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { //
type: 'shadow' // 线'line' | 'shadow'
}
},
radar: {
radius: '66%',
center: ['50%', '42%'],
splitNumber: 8,
splitArea: {
areaStyle: {
color: 'rgba(127,95,132,.3)',
opacity: 1,
shadowBlur: 45,
shadowColor: 'rgba(0,0,0,.5)',
shadowOffsetX: 0,
shadowOffsetY: 15
}
},
indicator: [
{ name: 'Sales', max: 10000 },
{ name: 'Administration', max: 20000 },
{ name: 'Information Techology', max: 20000 },
{ name: 'Customer Support', max: 20000 },
{ name: 'Development', max: 20000 },
{ name: 'Marketing', max: 20000 }
]
},
legend: {
left: 'center',
bottom: '10',
data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
},
series: [{
type: 'radar',
symbolSize: 0,
areaStyle: {
normal: {
shadowBlur: 13,
shadowColor: 'rgba(0,0,0,.2)',
shadowOffsetX: 0,
shadowOffsetY: 10,
opacity: 1
}
},
data: [
{
value: [5000, 7000, 12000, 11000, 15000, 14000],
name: 'Allocated Budget'
},
{
value: [4000, 9000, 15000, 15000, 13000, 11000],
name: 'Expected Spending'
},
{
value: [5500, 11000, 12000, 15000, 12000, 12000],
name: 'Actual Spending'
}
],
animationDuration: animationDuration
}]
})
}
}
}
</script>

View file

@ -1,79 +0,0 @@
<template>
<li :class="{ completed: todo.done, editing: editing }" class="todo">
<div class="view">
<input
:checked="todo.done"
class="toggle"
type="checkbox"
@change="toggleTodo( todo)">
<label @dblclick="editing = true" v-text="todo.text"/>
<button class="destroy" @click="deleteTodo( todo )"/>
</div>
<input
v-focus="editing"
v-show="editing"
:value="todo.text"
class="edit"
@keyup.enter="doneEdit"
@keyup.esc="cancelEdit"
@blur="doneEdit">
</li>
</template>
<script>
export default {
name: 'Todo',
directives: {
focus(el, { value }, { context }) {
if (value) {
context.$nextTick(() => {
el.focus()
})
}
}
},
props: {
todo: {
type: Object,
default: function() {
return {}
}
}
},
data: function() {
return {
editing: false
}
},
methods: {
deleteTodo(todo) {
this.$emit('deleteTodo', todo)
},
editTodo({ todo, value }) {
this.$emit('editTodo', { todo, value })
},
toggleTodo(todo) {
this.$emit('toggleTodo', todo)
},
doneEdit(e) {
const value = e.target.value.trim()
const { todo } = this
if (!value) {
this.deleteTodo({
todo
})
} else if (this.editing) {
this.editTodo({
todo,
value
})
this.editing = false
}
},
cancelEdit(e) {
e.target.value = this.todo.text
this.editing = false
}
}
}
</script>

View file

@ -1,320 +0,0 @@
.todoapp {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto ;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
background: #fff;
z-index: 1;
position: relative;
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
.todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 18px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 10px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
text-align: center;
border: none;
/* Mobile Safari */
opacity: 0;
position: absolute;
}
.toggle-all+label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all+label:before {
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked+label:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list li.editing {
border-bottom: none;
padding: 0;
}
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
.todo-list li.editing .view {
display: none;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none;
/* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle+label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat;
background-position: center left;
background-size: 36px;
}
.todo-list li .toggle:checked+label {
background-size: 36px;
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 50px;
display: block;
line-height: 1.0;
font-size: 14px;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
transition: color 0.2s ease-out;
cursor: pointer;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
position: relative;
padding: 10px 15px;
height: 40px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 40px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
position: relative;
z-index: 1;
list-style: none;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
font-size: 12px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
}

Some files were not shown because too many files have changed in this diff Show more