Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • develop
  • display-name-emoji-packs
  • feature/add-new-user-filters
  • feature/edit-tags-manually
  • feature/update-styles
  • master
  • release/2.0.3
  • release/2.1.0
  • remove-ssh-gopher
  • 1.2.0
  • v2.0.2
  • v2.1.0
12 results

Target

Select target project
No results found
Select Git revision
  • coverage-stable
  • develop
  • feature/ability-to-add-custom-tags
  • feature/add-metrics-exporter-settings
  • feature/dynamic-settings-rendering
  • feature/fetchs-list-of-tabs
  • feature/media-preview-proxy
  • feature/post-pagination
  • feature/render-settings-dynamically
  • feature/settings-rollback
  • feature/update-styles
  • release/2.5.0
  • release/2.6
  • remove-workers
  • renovate/autoprefixer-10.x
  • renovate/babel-eslint-replacement
  • renovate/babel-loader-8.x
  • renovate/babel-monorepo
  • renovate/element-ui-2.x
  • renovate/sass-1.x
  • renovate/vue-monorepo
  • renovate/vue-test-utils-1.x
  • renovate/vue-test-utils-2.x
  • renovate/vuex-3.x
  • revert-fd9f0542
  • stable
  • 1.2.0
  • 2.4.0
  • 2.5.0
  • v2.0.2
  • v2.1.0
  • v2.2.0
32 results
Show changes
93 files
+ 5090
4084
Compare changes
  • Side-by-side
  • Inline

Files

+22 −1
Original line number Diff line number Diff line
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased

### 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

### Changed

- 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

### 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`


## [2.1] - 2020-08-26

### Added
@@ -13,7 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- 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
- Support pagination of local and remote 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
@@ -38,6 +57,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- 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

@@ -46,6 +66,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- 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

+22 −2
Original line number Diff line number Diff line
@@ -31,11 +31,31 @@ AdminFE is bundled with Pleroma, i.e. you can just visit `https://your.instance/

### 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

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

+7 −2
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@
    "type": "git",
    "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
  },
  "resolutions": {
    "prosemirror-model": "1.9.1"
  },
  "bugs": {
    "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
  },
@@ -60,6 +63,8 @@
    "screenfull": "4.0.0",
    "showdown": "1.8.6",
    "sortablejs": "1.7.0",
    "tiptap": "^1.29.6",
    "tiptap-extensions": "^1.32.7",
    "tui-editor": "1.2.7",
    "vue": "^2.6.8",
    "vue-count-to": "1.0.13",
@@ -77,7 +82,7 @@
    "@babel/preset-env": "^7.3.4",
    "@vue/babel-helper-vue-jsx-merge-props": "^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",
    "babel-eslint": "8.2.6",
    "babel-helper-vue-jsx-merge-props": "2.0.3",
@@ -131,7 +136,7 @@
    "webpack": "^4.29.6",
    "webpack-bundle-analyzer": "2.13.1",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "3.1.14",
    "webpack-dev-server": "3.11.0",
    "webpack-merge": "4.1.4"
  },
  "engines": {
+51 −0
Original line number Diff line number Diff line
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()
}
+20 −0
Original line number Diff line number Diff line
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()
}
+3 −0
Original line number Diff line number Diff line
export function uploadMedia({ formData, authHost }) {
  return Promise.resolve()
}
+11 −0
Original line number Diff line number Diff line
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()
}
+11 −0
Original line number Diff line number Diff line
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()
}
Original line number Diff line number Diff line
@@ -21,11 +21,19 @@ export async function changeState(reportsData, authHost, token) {
  return Promise.resolve({ data: '' })
}

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 createNote(content, reportID, authHost, token) {
  return Promise.resolve()
}

export async function deleteStatus(statusId, authHost, token) {
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()
// }
+59 −0
Original line number Diff line number Diff line
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()
}
Original line number Diff line number Diff line
@@ -91,3 +91,7 @@ export async function fetchStatusesCount(instance, authHost, token) {
    }
  return Promise.resolve({ data })
}

export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
  return Promise.resolve()
}
Original line number Diff line number Diff line
@@ -123,3 +123,19 @@ export async function createNewAccount(nickname, email, password, authHost, toke
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()
}
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ export async function addNewEmojiFile(packName, file, shortcode, filename, host,

  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}/files`,
    url: `/api/pleroma/emoji/packs/files?name=${packName}`,
    method: 'post',
    headers: authHeaders(token),
    data
@@ -22,13 +22,13 @@ export async function addNewEmojiFile(packName, file, shortcode, filename, host,
}

export function addressOfEmojiInPack(host, packName, name) {
  return `${baseName(host)}/emoji/${packName}/${name}`
  return `${baseName(host)}/emoji/${encodeUri(packName)}/${name}`
}

export async function createPack(host, token, packName) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}`,
    url: `/api/pleroma/emoji/pack?name=${packName}`,
    method: 'post',
    headers: authHeaders(token)
  })
@@ -37,7 +37,7 @@ export async function createPack(host, token, packName) {
export async function deleteEmojiFile(packName, shortcode, host, token) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}/files?shortcode=${shortcode}`,
    url: `/api/pleroma/emoji/packs/files?name=${packName}&shortcode=${shortcode}`,
    method: 'delete',
    headers: authHeaders(token)
  })
@@ -46,7 +46,7 @@ export async function deleteEmojiFile(packName, shortcode, host, token) {
export async function deletePack(host, token, packName) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}`,
    url: `/api/pleroma/emoji/pack?name=${packName}`,
    method: 'delete',
    headers: authHeaders(token)
  })
@@ -68,7 +68,7 @@ export async function downloadFrom(instanceAddress, packName, as, host, token) {
export async function fetchPack(packName, page, pageSize, host, token) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}?page=${page}&page_size=${pageSize}`,
    url: `/api/pleroma/emoji/pack?name=${packName}&page=${page}&page_size=${pageSize}`,
    method: 'get',
    headers: authHeaders(token)
  })
@@ -92,10 +92,10 @@ export async function listPacks(page, pageSize, host, token) {
  })
}

export async function listRemotePacks(host, token, instance) {
export async function listRemotePacks(instance, page, pageSize, host, token) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/remote?url=${baseName(instance)}`,
    url: `/api/pleroma/emoji/packs/remote?url=${baseName(instance)}&page=${page}&page_size=${pageSize}`,
    method: 'get',
    headers: authHeaders(token)
  })
@@ -113,7 +113,7 @@ export async function reloadEmoji(host, token) {
export async function savePackMetadata(host, token, packName, metadata) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}`,
    url: `/api/pleroma/emoji/pack?name=${packName}`,
    method: 'patch',
    headers: authHeaders(token),
    data: { metadata },
@@ -124,7 +124,7 @@ export async function savePackMetadata(host, token, packName, metadata) {
export async function updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, host, token) {
  return await request({
    baseURL: baseName(host),
    url: `/api/pleroma/emoji/packs/${packName}/files`,
    url: `/api/pleroma/emoji/packs/files?name=${packName}`,
    method: 'patch',
    headers: authHeaders(token),
    data: { shortcode, new_shortcode: newShortcode, new_filename: newFilename, force }
@@ -132,3 +132,5 @@ export async function updateEmojiFile(packName, shortcode, newShortcode, newFile
}

const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

const encodeUri = (name) => encodeURIComponent(name)

src/api/reportsData.js

deleted100644 → 0
+0 −218
Original line number Diff line number Diff line
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' }]
  }
]
Original line number Diff line number Diff line
@@ -2,6 +2,15 @@ import request from '@/utils/request'
import { getToken } from '@/utils/auth'
import { baseName } from './utils'

export async function deleteInstanceDocument(name, authHost, token) {
  return await request({
    baseURL: baseName(authHost),
    url: `/api/pleroma/admin/instance_document/${name}`,
    method: 'delete',
    headers: authHeaders(token)
  })
}

export async function fetchDescription(authHost, token) {
  return await request({
    baseURL: baseName(authHost),
@@ -20,6 +29,25 @@ export async function fetchSettings(authHost, token) {
  })
}

export async function getInstanceDocument(name, authHost, token) {
  return await request({
    baseURL: baseName(authHost),
    url: `/api/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/pleroma/admin/instance_document/${name}`,
    method: 'patch',
    data: formData,
    headers: { ...authHeaders(token), 'Content-Type': 'multipart/form-data' }
  })
}

export async function updateSettings(configs, authHost, token) {
  return await request({
    baseURL: baseName(authHost),
Original line number Diff line number Diff line
<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>
Original line number Diff line number Diff line
<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>
Original line number Diff line number Diff line
<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>
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+3 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+1 −0
Original line number Diff line number Diff line
<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>
+17 −4
Original line number Diff line number Diff line
@@ -103,7 +103,11 @@ export default {
    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'
    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',
@@ -273,7 +277,10 @@ export default {
    linkToResetPassword: 'You can also use this link to reset password:',
    registrationReason: 'Registration Reason',
    service: 'Service',
    person: 'Person'
    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',
@@ -429,7 +436,9 @@ export default {
    removeSettingConfirmation: 'Are you sure you want to remove this setting\'s value from the database?',
    changeImage: 'Change image',
    uploadImage: 'Upload image',
    remove: 'Remove'
    remove: 'Remove',
    instancePanel: 'Instance Panel Document',
    termsOfServices: 'Terms of Service'
  },
  invites: {
    inviteTokens: 'Invite tokens',
@@ -476,6 +485,7 @@ export default {
    homepage: 'Homepage',
    description: 'Description',
    packs: 'Packs',
    displayName: 'Display name',
    license: 'License',
    shortcode: 'Shortcode',
    fallbackSrc: 'Fallback source',
@@ -511,6 +521,9 @@ export default {
    specifyFilename: 'Specify a custom filename',
    copy: 'Copy',
    copyToLocalPack: 'Copy to local pack',
    emptyPack: 'This emoji pack is empty'
    emptyPack: 'This emoji pack is empty',
    emojiWarning: 'Pack names cannot include any of the following characters: # / < > & +',
    image: 'Image'

  }
}
Original line number Diff line number Diff line
@@ -20,25 +20,29 @@ import Vue from 'vue'
const emojiPacks = {
  state: {
    activeTab: '',
    currentFilesPage: 1,
    currentPage: 1,
    currentLocalFilesPage: 1,
    currentLocalPacksPage: 1,
    currentRemoteFilesPage: 1,
    currentRemotePacksPage: 1,
    filesPageSize: 30,
    localPackFilesCount: 0,
    localPacks: {},
    localPacksCount: 0,
    pageSize: 50,
    remoteInstance: '',
    remotePacks: {}
    remotePackFilesCount: 0,
    remotePacks: {},
    remotePacksCount: 0
  },
  mutations: {
    SET_ACTIVE_TAB: (state, tab) => {
      state.activeTab = tab
    },
    SET_FILES_COUNT: (state, count) => {
    SET_LOCAL_FILES_COUNT: (state, count) => {
      state.localPackFilesCount = count
    },
    SET_FILES_PAGE: (state, page) => {
      state.currentFilesPage = page
    SET_LOCAL_FILES_PAGE: (state, page) => {
      state.currentLocalFilesPage = page
    },
    SET_LOCAL_PACKS: (state, packs) => {
      state.localPacks = packs
@@ -46,15 +50,27 @@ const emojiPacks = {
    SET_LOCAL_PACKS_COUNT: (state, count) => {
      state.localPacksCount = count
    },
    SET_PACK_FILES: (state, { name, files }) => {
    SET_LOCAL_PACK_FILES: (state, { name, files }) => {
      state.localPacks = { ...state.localPacks, [name]: { ...state.localPacks[name], files }}
    },
    SET_PAGE: (state, page) => {
      state.currentPage = page
    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) => {
      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) => {
      state.remotePacks = packs
    },
@@ -103,10 +119,10 @@ const emojiPacks = {
        type: 'success',
        duration: 5 * 1000
      })
      if (Object.keys(updatedPackFiles).length === 0 && state.currentFilesPage > 1) {
        dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage - 1 })
      if (Object.keys(updatedPackFiles).length === 0 && state.currentLocalFilesPage > 1) {
        dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage - 1 })
      } else {
        dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage })
        dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage })
      }
    },
    async CreatePack({ getters }, { name }) {
@@ -136,14 +152,21 @@ const emojiPacks = {
      }, {})
      commit('SET_LOCAL_PACKS', updatedPacks)
      commit('SET_LOCAL_PACKS_COUNT', count)
      commit('SET_PAGE', page)
      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 FetchSinglePack({ getters, commit, state }, { name, 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_PACK_FILES', { name, files })
      commit('SET_FILES_COUNT', files_count)
      commit('SET_FILES_PAGE', page)
      commit('SET_REMOTE_PACK_FILES', { name, files })
      commit('SET_REMOTE_FILES_COUNT', files_count)
      commit('SET_REMOTE_FILES_PAGE', page)
    },
    async ImportFromFS({ getters }) {
      const result = await importFromFS(getters.authHost, getters.token)
@@ -185,11 +208,18 @@ const emojiPacks = {
    SetActiveTab({ commit }, activeTab) {
      commit('SET_ACTIVE_TAB', activeTab)
    },
    async SetRemoteEmojiPacks({ commit, getters }, { remoteInstance }) {
      const { data } = await listRemotePacks(getters.authHost, getters.token, remoteInstance)
    async SetRemoteEmojiPacks({ commit, getters, state }, { page, remoteInstance }) {
      const { data } = await listRemotePacks(remoteInstance, 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_REMOTE_INSTANCE', remoteInstance)
      commit('SET_REMOTE_PACKS', data.packs)
      commit('SET_REMOTE_PACKS', updatedPacks)
      commit('SET_REMOTE_PACKS_COUNT', count)
    },
    SetRemoteInstance({ commit }, instance) {
      commit('SET_REMOTE_INSTANCE', instance)
@@ -216,7 +246,7 @@ const emojiPacks = {
        duration: 5 * 1000
      })

      dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage })
      dispatch('FetchLocalSinglePack', { name: packName, page: state.currentLocalFilesPage })
    },
    async UpdateLocalPackVal({ commit }, args) {
      commit('UPDATE_LOCAL_PACK_VAL', args)
Original line number Diff line number Diff line
import { listBannedUrls, purgeUrls, removeBannedUrls, searchBannedUrls } from '@/api/mediaProxyCache'
import { fetchSettings, updateSettings } from '@/api/settings'
import { Message } from 'element-ui'
import i18n from '@/lang'

@@ -7,10 +8,15 @@ const mediaProxyCache = {
    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 } })
    },
@@ -22,9 +28,36 @@ const mediaProxyCache = {
    },
    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)
@@ -40,13 +73,19 @@ const mediaProxyCache = {
        type: 'success',
        duration: 5 * 1000
      })
      if (ban) {
      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) {
Original line number Diff line number Diff line
@@ -66,7 +66,11 @@ export const parseTuples = (tuples, key) => {
        return [...acc, { [mascot.tuple[0]]: { ...mascot.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
      }, [])
    } else if (Array.isArray(item.tuple[1]) &&
      (item.tuple[0] === ':groups' || item.tuple[0] === ':replace' || item.tuple[0] === ':retries' || item.tuple[0] === ':headers' || item.tuple[0] === ':crontab')) {
      (item.tuple[0] === ':groups' ||
      item.tuple[0] === ':replace' ||
      item.tuple[0] === ':retries' ||
      (item.tuple[0] === ':headers' && key === 'Pleroma.Web.MediaProxy.Invalidation.Http') ||
      item.tuple[0] === ':crontab')) {
      if (item.tuple[0] === ':crontab') {
        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)}` }}]
@@ -245,7 +249,7 @@ const wrapValues = (settings, currentState) => {
        return acc
      }, {})
      return { 'tuple': [setting, { ...currentState[setting], ...mapValue }] }
    } else if (type.includes('map')) {
    } else if (type.includes('map') && !type.includes('list')) {
      const mapValue = Object.keys(value).reduce((acc, key) => {
        acc[key] = value[key][1]
        return acc
@@ -271,7 +275,7 @@ export const formSearchObject = description => {
    return [...acc, resultObject]
  }, [])

  return description.reduce((acc, setting) => {
  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) {
@@ -280,4 +284,19 @@ export const formSearchObject = description => {
    }
    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)
}
Original line number Diff line number Diff line
import { changeState, fetchReports, createNote, deleteNote } from '@/api/reports'
import {
  activateUsers,
  deactivateUsers,
  deleteUsers,
  tagUser,
  untagUser
} from '@/api/users'

const reports = {
  state: {
@@ -34,6 +41,34 @@ const reports = {
    }
  },
  actions: {
    async ActivateUserFromReports({ commit, dispatch, getters, state }, { user, reportId }) {
      try {
        await activateUsers([user.nickname], getters.authHost, getters.token)
      } catch (_e) {
        return
      } finally {
        const updatedReports = state.fetchedReports.map(report => {
          const updatedAccount = { ...user, deactivated: false }
          return report.id === reportId ? { ...report, account: updatedAccount } : report
        })
        commit('SET_REPORTS', updatedReports)
      }
      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 ChangeReportState({ commit, dispatch, getters, state }, reportsData) {
      changeState(reportsData, getters.authHost, getters.token)

@@ -48,6 +83,34 @@ const reports = {
    ClearFetchedReports({ commit }) {
      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, deactivated: true }
          return report.id === reportId ? { ...report, account: updatedAccount } : report
        })
        commit('SET_REPORTS', updatedReports)
      }
      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, deactivated: true }
          return report.id === reportId ? { ...report, account: updatedAccount } : report
        })
        commit('SET_REPORTS', updatedReports)
      }
      dispatch('SuccessMessage')
    },
    async FetchReports({ commit, getters, state }, page) {
      commit('SET_LOADING', true)
      const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token)
@@ -64,6 +127,20 @@ const reports = {
      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')
    },
    SetReportsFilter({ commit }, filter) {
      commit('SET_REPORTS_FILTER', filter)
    },
Original line number Diff line number Diff line
import { fetchDescription, fetchSettings, removeSettings, updateSettings } from '@/api/settings'
import {
  deleteInstanceDocument,
  fetchDescription,
  fetchSettings,
  getInstanceDocument,
  removeSettings,
  updateInstanceDocument,
  updateSettings } from '@/api/settings'
import { formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers'
import _ from 'lodash'

@@ -8,15 +15,20 @@ const settings = {
    configDisabled: true,
    db: {},
    description: [],
    instancePanel: '',
    loading: true,
    searchData: {},
    settings: {},
    termsOfServices: '',
    updatedSettings: {}
  },
  mutations: {
    CLEAR_UPDATED_SETTINGS: (state) => {
      state.updatedSettings = {}
    },
    SET_INSTANCE_PANEL: (state, data) => {
      state.instancePanel = data
    },
    REMOVE_SETTING_FROM_UPDATED: (state, { group, key, subkeys }) => {
      if (_.get(state.updatedSettings, [group, key, subkeys[0]])) {
        const { [subkeys[0]]: value, ...updatedSettings } = state.updatedSettings[group][key]
@@ -54,6 +66,9 @@ const settings = {
      state.settings = newSettings
      state.db = newDbSettings
    },
    SET_TERMS_OF_SERVICES: (state, data) => {
      state.termsOfServices = data
    },
    TOGGLE_TABS: (state, status) => {
      state.configDisabled = status
    },
@@ -71,6 +86,14 @@ const settings = {
    }
  },
  actions: {
    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 }) {
      commit('SET_LOADING', true)
      try {
@@ -89,6 +112,10 @@ const settings = {
      commit('TOGGLE_TABS', false)
      commit('SET_LOADING', false)
    },
    async RemoveInstanceDocument({ dispatch, getters }, name) {
      await deleteInstanceDocument(name, getters.authHost, getters.token)
      await dispatch('FetchInstanceDocument', name)
    },
    async RemoveSetting({ commit, getters }, configs) {
      await removeSettings(configs, getters.authHost, getters.token)
      const response = await fetchSettings(getters.authHost, getters.token)
@@ -111,6 +138,13 @@ const settings = {
      commit('TOGGLE_REBOOT', response.data.need_reboot)
      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 }) {
      key
        ? commit('UPDATE_SETTINGS', { group, key, input, value, type })
Original line number Diff line number Diff line
@@ -19,12 +19,14 @@ import {
  resendConfirmationEmail,
  updateUserCredentials
} from '@/api/users'
import { fetchSettings, updateSettings } from '@/api/settings'

const users = {
  state: {
    fetchedUsers: [],
    loading: true,
    searchQuery: '',
    mrfPolicies: [],
    totalUsersCount: 0,
    currentPage: 1,
    pageSize: 50,
@@ -78,6 +80,9 @@ const users = {
    SET_SEARCH_QUERY: (state, query) => {
      state.searchQuery = query
    },
    SET_TAG_POLICY: (state, mrfPolicies) => {
      state.mrfPolicies = mrfPolicies
    },
    SET_USERS_FILTERS: (state, filters) => {
      state.filters = filters
    }
@@ -206,6 +211,27 @@ const users = {
      }
      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 }) {
      commit('SET_LOADING', true)
      const filters = Object.keys(state.filters).filter(filter => state.filters[filter]).join()
Original line number Diff line number Diff line
@@ -101,7 +101,6 @@ div:focus {
code {
  background: #eef1f6;
  padding: 15px 16px;
  margin-bottom: 20px;
  display: block;
  line-height: 36px;
  font-size: 15px;
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@
      <el-form-item :label=" $t('emoji.sharePack')">
        <el-switch v-model="share" />
      </el-form-item>
      <el-form-item :label=" $t('emoji.displayName')">
        <el-input v-model="displayName" />
      </el-form-item>
      <el-form-item :label=" $t('emoji.homepage')">
        <el-input v-model="homepage" />
      </el-form-item>
@@ -30,7 +33,7 @@
      <div class="download-pack-button-container">
        <el-link
          v-if="pack.pack['can-download']"
          :href="`//${host}/api/pleroma/emoji/packs/${name}/download_shared`"
          :href="`//${host}//api/pleroma/emoji/packs/archive?name=${name}`"
          :underline="false"
          type="primary"
          target="_blank">
@@ -44,6 +47,11 @@
      </el-collapse-item>
      <el-collapse-item :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
        <div v-if="pack.files && Object.keys(pack.files).length > 0">
          <div :class="isMobile ? 'emoji-container-flex' : 'emoji-container-grid'">
            <span class="emoji-preview-img emoji-table-head">{{ $t('emoji.image') }}</span>
            <span class="emoji-table-head">{{ $t('emoji.shortcode') }}</span>
            <span class="emoji-table-head">{{ $t('emoji.file') }}</span>
          </div>
          <single-emoji-editor
            v-for="(file, shortcode) in pack.files"
            :key="shortcode"
@@ -100,10 +108,10 @@ export default {
  },
  computed: {
    currentFilesPage() {
      return this.$store.state.emojiPacks.currentFilesPage
      return this.$store.state.emojiPacks.currentLocalFilesPage
    },
    currentPage() {
      return this.$store.state.emojiPacks.currentPage
    currentLocalPacksPage() {
      return this.$store.state.emojiPacks.currentLocalPacksPage
    },
    isMobile() {
      return this.$store.state.app.device === 'mobile'
@@ -144,6 +152,15 @@ export default {
        )
      }
    },
    displayName: {
      get() { return this.pack.pack['display-name'] },
      set(value) {
        this.$store.dispatch(
          'UpdateLocalPackVal',
          { name: this.name, key: 'display-name', value }
        )
      }
    },
    description: {
      get() { return this.pack.pack['description'] },
      set(value) {
@@ -197,21 +214,21 @@ export default {
          .then(() => this.$store.dispatch('ReloadEmoji'))
          .then(() => {
            const { [this.name]: value, ...updatedPacks } = this.$store.state.emojiPacks.localPacks
            if (Object.keys(updatedPacks).length === 0 && this.currentPage > 1) {
              this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage - 1)
            if (Object.keys(updatedPacks).length === 0 && this.currentLocalPacksPage > 1) {
              this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage - 1)
            } else {
              this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
              this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage)
            }
          })
      }).catch(() => {})
    },
    handleChange(openTabs, name) {
      if (openTabs.includes('manageEmoji')) {
        this.$store.dispatch('FetchSinglePack', { name, page: 1 })
        this.$store.dispatch('FetchLocalSinglePack', { name, page: 1 })
      }
    },
    handleFilesPageChange(page) {
      this.$store.dispatch('FetchSinglePack', { name: this.name, page })
      this.$store.dispatch('FetchLocalSinglePack', { name: this.name, page })
    },
    savePackMetadata() {
      this.$store.dispatch('SavePackMetadata', { packName: this.name })
@@ -252,6 +269,11 @@ export default {
  font-weight: 700;
  color: #606266;
}
.emoji-table-head {
  color: #909399;
  font-size: 14px;
  font-weight: 700;
}
.emoji-pack-card {
  margin-top: 5px;
}
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
          </el-link>
        </el-form-item>
      </el-form>
      <el-collapse v-model="showPackContent" class="contents-collapse">
      <el-collapse v-model="showPackContent" class="contents-collapse" @change="handleChange($event, name)">
        <el-collapse-item :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
          <div v-if="pack.files && Object.keys(pack.files).length > 0">
            <single-emoji-editor
@@ -46,6 +46,16 @@
              :is-local="isLocal" />
          </div>
          <span v-else class="expl">{{ $t('emoji.emptyPack') }}</span>
          <div class="files-pagination">
            <el-pagination
              :total="remotePackFilesCount"
              :current-page="currentFilesPage"
              :page-size="pageSize"
              hide-on-single-page
              layout="prev, pager, next"
              @current-change="handleFilesPageChange"
            />
          </div>
        </el-collapse-item>
        <el-collapse-item :title=" $t('emoji.downloadPack')" name="downloadPack" class="no-background">
          <p>
@@ -95,8 +105,11 @@ export default {
    }
  },
  computed: {
    currentPage() {
      return this.$store.state.emojiPacks.currentPage
    currentFilesPage() {
      return this.$store.state.emojiPacks.currentRemoteFilesPage
    },
    currentRemotePacksPage() {
      return this.$store.state.emojiPacks.currentRemotePacksPage
    },
    isDesktop() {
      return this.$store.state.app.device === 'desktop'
@@ -119,9 +132,15 @@ export default {
    loadRemotePack() {
      return this.$store.state.emojiPacks.activeTab === this.name
    },
    pageSize() {
      return this.$store.state.emojiPacks.filesPageSize
    },
    remoteInstanceAddress() {
      return this.$store.state.emojiPacks.remoteInstance
    },
    remotePackFilesCount() {
      return this.$store.state.emojiPacks.remotePackFilesCount
    },
    share: {
      get() { return this.pack.pack['share-files'] },
      set(value) {
@@ -186,6 +205,14 @@ export default {
        { instanceAddress: this.remoteInstanceAddress, packName: this.name, as: this.downloadSharedAs }
      ).then(() => this.$store.dispatch('ReloadEmoji'))
        .then(() => this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage))
    },
    handleChange(openTabs, name) {
      if (openTabs.includes('manageEmoji')) {
        this.$store.dispatch('FetchRemoteSinglePack', { name, page: 1 })
      }
    },
    handleFilesPageChange(page) {
      this.$store.dispatch('FetchRemoteSinglePack', { name: this.name, page })
    }
  }
}
@@ -231,6 +258,10 @@ export default {
    margin-bottom: 10px;
  }
}
.files-pagination {
  margin: 25px 0;
  text-align: center;
}
.has-background .el-collapse-item__header {
  background: #f6f6f6;
}
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ export default {
}
.emoji-container-grid {
  display: grid;
  grid-template-columns: 75px auto auto 200px;
  grid-template-columns: 75px 1fr 1fr 200px;
  grid-column-gap: 15px;
  margin-bottom: 10px;
}
@@ -197,7 +197,7 @@ export default {
}
.remote-emoji-container-grid {
  display: grid;
  grid-template-columns: 75px auto auto 160px;
  grid-template-columns: 75px 1fr 1fr 160px;
  grid-column-gap: 15px;
  margin-bottom: 10px;
}
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
                {{ $t('users.create') }}
              </el-button>
            </div>
            <span class="emoji-name-warning">{{ $t('emoji.emojiWarning') }}</span>
          </el-form-item>
          <el-form-item v-if="Object.keys(localPacks).length > 0" :label="$t('emoji.packs')">
            <el-collapse v-for="(pack, name) in localPacks" :key="name" v-model="activeLocalPack" accordion @change="setActiveTab">
@@ -40,11 +41,11 @@
        <div class="pagination">
          <el-pagination
            :total="localPacksCount"
            :current-page="currentPage"
            :current-page="currentLocalPacksPage"
            :page-size="pageSize"
            hide-on-single-page
            layout="prev, pager, next"
            @current-change="handlePageChange"
            @current-change="handleLocalPageChange"
          />
        </div>
      </el-tab-pane>
@@ -70,6 +71,16 @@
            </el-collapse>
          </el-form-item>
        </el-form>
        <div class="pagination">
          <el-pagination
            :total="remotePacksCount"
            :current-page="currentRemotePacksPage"
            :page-size="pageSize"
            hide-on-single-page
            layout="prev, pager, next"
            @current-change="handleRemotePageChange"
          />
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
@@ -93,8 +104,11 @@ export default {
    }
  },
  computed: {
    currentPage() {
      return this.$store.state.emojiPacks.currentPage
    currentLocalPacksPage() {
      return this.$store.state.emojiPacks.currentLocalPacksPage
    },
    currentRemotePacksPage() {
      return this.$store.state.emojiPacks.currentRemotePacksPage
    },
    isMobile() {
      return this.$store.state.app.device === 'mobile'
@@ -130,6 +144,9 @@ export default {
    },
    remotePacks() {
      return this.$store.state.emojiPacks.remotePacks
    },
    remotePacksCount() {
      return this.$store.state.emojiPacks.remotePacksCount
    }
  },
  mounted() {
@@ -143,23 +160,26 @@ export default {
        .then(() => {
          this.newPackName = ''

          this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
          this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage)
          this.$store.dispatch('ReloadEmoji')
        })
    },
    handlePageChange(page) {
    handleLocalPageChange(page) {
      this.$store.dispatch('FetchLocalEmojiPacks', page)
    },
    handleRemotePageChange(page) {
      this.$store.dispatch('SetRemoteEmojiPacks', { page, remoteInstance: this.remoteInstanceAddress })
    },
    importFromFS() {
      this.$store.dispatch('ImportFromFS')
        .then(() => {
          this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
          this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage)
          this.$store.dispatch('ReloadEmoji')
        })
    },
    refreshLocalPacks() {
      try {
        this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
        this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage)
      } catch (e) {
        return
      }
@@ -170,7 +190,7 @@ export default {
    },
    async refreshRemotePacks() {
      this.fullscreenLoading = true
      await this.$store.dispatch('SetRemoteEmojiPacks', { remoteInstance: this.remoteInstanceAddress })
      await this.$store.dispatch('SetRemoteEmojiPacks', { page: 1, remoteInstance: this.remoteInstanceAddress })
      this.fullscreenLoading = false
    },
    async reloadEmoji() {
@@ -206,6 +226,15 @@ export default {
  justify-content: space-between;
  margin: 0 15px 22px 15px;
}
.emoji-name-warning {
  color: #666666;
  font-size: 13px;
  line-height: 22px;
  margin: 5px 0 0 0;
  overflow-wrap: break-word;
  overflow: hidden;
  text-overflow: ellipsis;
}
.emoji-packs-header-button-container {
  display: flex;
}
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
      <h1>{{ $t('mediaProxyCache.mediaProxyCache') }}</h1>
      <reboot-button/>
    </div>
    <div v-if="mediaProxyEnabled">
      <p class="media-proxy-cache-header">{{ $t('mediaProxyCache.evictObjectsHeader') }}</p>
      <div class="url-input-container">
        <el-input
@@ -64,6 +65,11 @@
        />
      </div>
    </div>
    <div v-else class="enable-mediaproxy-container">
      <el-button type="text" @click="enableMediaProxy">{{ $t('mediaProxyCache.enable') }}</el-button>
      {{ $t('mediaProxyCache.invalidationAndMediaProxy') }}
    </div>
  </div>
</template>

<script>
@@ -94,6 +100,9 @@ export default {
    loading() {
      return this.$store.state.mediaProxyCache.loading
    },
    mediaProxyEnabled() {
      return this.$store.state.mediaProxyCache.mediaProxyEnabled
    },
    pageSize() {
      return this.$store.state.mediaProxyCache.pageSize
    },
@@ -112,11 +121,32 @@ export default {
  mounted() {
    this.$store.dispatch('GetNodeInfo')
    this.$store.dispatch('NeedReboot')
    this.$store.dispatch('FetchMediaProxySetting')
    this.$store.dispatch('ListBannedUrls', { page: 1 })
  },
  methods: {
    enableMediaProxy() {
      this.$confirm(
        this.$t('mediaProxyCache.confirmEnablingMediaProxy'),
        {
          confirmButtonText: 'Yes',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
        this.$message({
          type: 'success',
          message: this.$t('mediaProxyCache.enableMediaProxySuccessMessage')
        })
        this.$store.dispatch('EnableMediaProxy')
      }).catch(() => {
        this.$message({
          type: 'info',
          message: 'Canceled'
        })
      })
    },
    evictURL() {
      const urls = this.urls.split(',').map(url => url.trim()).filter(el => el.length > 0)
      const urls = this.splitUrls(this.urls)
      this.$store.dispatch('PurgeUrls', { urls, ban: this.ban })
      this.urls = ''
    },
@@ -133,6 +163,9 @@ export default {
    },
    removeUrl(url) {
      this.$store.dispatch('RemoveBannedUrls', [url])
    },
    splitUrls(urls) {
      return urls.split(',').map(url => url.trim()).filter(el => el.length > 0)
    }
  }
}
@@ -142,6 +175,12 @@ export default {
h1 {
  margin: 0;
}
.enable-mediaproxy-container {
  margin: 10px 15px;
  button {
    font-size: 16px;
  }
}
.expl {
  color: #666666;
  font-size: 13px;
Original line number Diff line number Diff line
<template>
  <el-dropdown trigger="click">
  <el-dropdown :hide-on-click="false" trigger="click">
    <el-button :disabled="!account.id" plain size="small" icon="el-icon-files">{{ $t('reports.moderateUser') }}
      <i class="el-icon-arrow-down el-icon--right"/>
    </el-button>
@@ -11,10 +11,11 @@
      </el-dropdown-item>
      <el-dropdown-item
        v-if="showDeactivatedButton(account.id)"
        @click.native="handleDeletion(account.id)">
        @click.native="handleDeletion(account)">
        {{ $t('users.deleteAccount') }}
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :divided="true"
        :class="{ 'active-tag': tags.includes('mrf_tag:media-force-nsfw') }"
        @click.native="toggleTag(account, 'mrf_tag:media-force-nsfw')">
@@ -22,37 +23,47 @@
        <i v-if="tags.includes('mrf_tag:media-force-nsfw')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': tags.includes('mrf_tag:media-strip') }"
        @click.native="toggleTag(account, 'mrf_tag:media-strip')">
        {{ $t('users.stripMedia') }}
        <i v-if="tags.includes('mrf_tag:media-strip')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': tags.includes('mrf_tag:force-unlisted') }"
        @click.native="toggleTag(account, 'mrf_tag:force-unlisted')">
        {{ $t('users.forceUnlisted') }}
        <i v-if="tags.includes('mrf_tag:force-unlisted')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': tags.includes('mrf_tag:sandbox') }"
        @click.native="toggleTag(account, 'mrf_tag:sandbox')">
        {{ $t('users.sandbox') }}
        <i v-if="tags.includes('mrf_tag:sandbox')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="account.local"
        v-if="tagPolicyEnabled && account.local"
        :class="{ 'active-tag': tags.includes('mrf_tag:disable-remote-subscription') }"
        @click.native="toggleTag(account, 'mrf_tag:disable-remote-subscription')">
        {{ $t('users.disableRemoteSubscription') }}
        <i v-if="tags.includes('mrf_tag:disable-remote-subscription')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="account.local"
        v-if="tagPolicyEnabled && account.local"
        :class="{ 'active-tag': tags.includes('mrf_tag:disable-any-subscription') }"
        @click.native="toggleTag(account, 'mrf_tag:disable-any-subscription')">
        {{ $t('users.disableAnySubscription') }}
        <i v-if="tags.includes('mrf_tag:disable-any-subscription')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="!tagPolicyEnabled"
        divided
        class="no-hover"
        @click.native="enableTagPolicy">
        {{ $t('users.enableTagPolicy') }}
      </el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</template>
@@ -64,27 +75,69 @@ export default {
    account: {
      type: Object,
      required: true
    },
    reportId: {
      type: String,
      required: true
    }
  },
  computed: {
    tagPolicyEnabled() {
      return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
    },
    tags() {
      return this.account.tags || []
    }
  },
  methods: {
    handleDeactivation({ nickname }) {
      this.$store.dispatch('ToggleUserActivation', nickname)
    enableTagPolicy() {
      this.$confirm(
        this.$t('users.confirmEnablingTagPolicy'),
        {
          confirmButtonText: 'Yes',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
        this.$message({
          type: 'success',
          message: this.$t('users.enableTagPolicySuccessMessage')
        })
        this.$store.dispatch('EnableTagPolicy')
      }).catch(() => {
        this.$message({
          type: 'info',
          message: 'Canceled'
        })
      })
    },
    handleDeactivation(user) {
      user.deactivated
        ? this.$store.dispatch('ActivateUserFromReports', { user, reportId: this.reportId })
        : this.$store.dispatch('DeactivateUserFromReports', { user, reportId: this.reportId })
    },
    handleDeletion(user) {
      this.$store.dispatch('DeleteUser', user)
      this.$confirm(
        this.$t('users.deleteUserConfirmation'),
        {
          confirmButtonText: 'Delete',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
        this.$store.dispatch('DeleteUserFromReports', { user, reportId: this.reportId })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: 'Delete canceled'
        })
      })
    },
    showDeactivatedButton(id) {
      return this.$store.state.user.id !== id
    },
    toggleTag(user, tag) {
      user.tags.includes(tag)
        ? this.$store.dispatch('RemoveTag', { users: [user], tag })
        : this.$store.dispatch('AddTag', { users: [user], tag })
        ? this.$store.dispatch('RemoveTagFromReports', { user, tag, reportId: this.reportId })
        : this.$store.dispatch('AddTagFromReports', { user, tag, reportId: this.reportId })
    }
  }
}
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@
                  <el-dropdown-item v-if="report.state !== 'closed'" @click.native="changeReportState('closed', report.id)">{{ $t('reports.close') }}</el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
              <moderate-user-dropdown v-if="propertyExists(report.account, 'nickname')" :account="report.account"/>
              <moderate-user-dropdown v-if="propertyExists(report.account, 'nickname')" :account="report.account" :report-id="report.id" />
            </div>
          </div>
          <el-divider class="divider"/>
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ export default {
  mounted() {
    this.$store.dispatch('GetNodeInfo')
    this.$store.dispatch('NeedReboot')
    this.$store.dispatch('FetchTagPolicySetting')
    this.$store.dispatch('FetchReports', 1)
  }
}
Original line number Diff line number Diff line
@@ -15,10 +15,6 @@
    <el-form :model="oauth2Data" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="oauth2" :data="oauth2Data"/>
    </el-form>
    <el-divider v-if="oauth2" class="divider thick-line"/>
    <el-form :model="restrictUnauthenticatedData" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="restrictUnauthenticated" :data="restrictUnauthenticatedData"/>
    </el-form>
    <div class="submit-button-container">
      <el-button class="submit-button" type="primary" @click="onSubmit">Submit</el-button>
    </div>
@@ -85,12 +81,6 @@ export default {
    },
    pleromaAuthenticatorData() {
      return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Auth.Authenticator']) || {}
    },
    restrictUnauthenticated() {
      return this.settings.description.find(setting => setting.key === ':restrict_unauthenticated')
    },
    restrictUnauthenticatedData() {
      return _.get(this.settings.settings, [':pleroma', ':restrict_unauthenticated']) || {}
    }
  },
  methods: {
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@
          @change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"
        />
        <el-input
          v-else-if="setting.type === 'string' || (setting.type.includes('string') && setting.type.includes('atom'))"
          v-else-if="setting.type === 'string' ||
          (Array.isArray(setting.type) && setting.type.includes('string') && setting.type.includes('atom'))"
          :value="inputValue"
          :placeholder="setting.suggestions ? setting.suggestions[0] : null"
          :data-search="setting.key || setting.group"
@@ -358,7 +359,10 @@ export default {
      )
    },
    renderSingleSelect(type) {
      return !this.reducedSelects && (type === 'module' || (type.includes('atom') && type.includes('dropdown')))
      return !this.reducedSelects && (
        type === 'module' ||
        (Array.isArray(type) && type.includes('atom') && type.includes('dropdown'))
      )
    },
    senderInput({ key, type }) {
      return Array.isArray(type) && type.includes('string') && type.includes('tuple') && key === ':sender'
Original line number Diff line number Diff line
@@ -3,7 +3,12 @@
    <el-form :model="instanceData" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="instance" :data="instanceData"/>
    </el-form>
    <editor-input v-model="instancePanelContent" :name="'instance-panel'" @input="handleEditorUpdate"/>
    <el-divider v-if="instance" class="divider thick-line"/>
    <el-form :model="restrictUnauthenticatedData" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="restrictUnauthenticated" :data="restrictUnauthenticatedData"/>
    </el-form>
    <el-divider v-if="restrictUnauthenticated" class="divider thick-line"/>
    <el-form :model="adminTokenData" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="adminToken" :data="adminTokenData"/>
    </el-form>
@@ -49,13 +54,20 @@
import { mapGetters } from 'vuex'
import i18n from '@/lang'
import Setting from './Setting'
import { EditorInput } from './inputComponents'
import _ from 'lodash'

export default {
  name: 'Instance',
  components: {
    EditorInput,
    Setting
  },
  data() {
    return {
      editorContent: ''
    }
  },
  computed: {
    ...mapGetters([
      'settings'
@@ -66,6 +78,14 @@ export default {
    adminTokenData() {
      return _.get(this.settings.settings, [':pleroma', ':admin_token']) || {}
    },
    instancePanelContent: {
      get() {
        return this.$store.state.settings.instancePanel
      },
      set(content) {
        this.editorContent = content
      }
    },
    favicons() {
      return this.settings.description.find(setting => setting.key === ':instances_favicons')
    },
@@ -120,6 +140,12 @@ export default {
    pleromaUserData() {
      return _.get(this.settings.settings, [':pleroma', 'Pleroma.User']) || {}
    },
    restrictUnauthenticated() {
      return this.settings.description.find(setting => setting.key === ':restrict_unauthenticated')
    },
    restrictUnauthenticatedData() {
      return _.get(this.settings.settings, [':pleroma', ':restrict_unauthenticated']) || {}
    },
    scheduledActivity() {
      return this.$store.state.settings.description.find(setting => setting.key === 'Pleroma.ScheduledActivity')
    },
@@ -145,10 +171,17 @@ export default {
      return _.get(this.settings.settings, [':pleroma', ':welcome']) || {}
    }
  },
  async mounted() {
    await this.$store.dispatch('FetchInstanceDocument', 'instance-panel')
  },
  methods: {
    handleEditorUpdate(content) {
      this.editorContent = content
    },
    async onSubmit() {
      try {
        await this.$store.dispatch('SubmitChanges')
        await this.$store.dispatch('UpdateInstanceDocs', { name: 'instance-panel', content: this.editorContent })
      } catch (e) {
        return
      }
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ export default {
      })
    },
    showMrfPolicy(key) {
      const selectedMrfPolicies = _.get(this.settings.settings, [':pleroma', ':mrf', ':policies'])
      const selectedMrfPolicies = _.get(this.settings.settings, [':pleroma', ':mrf', ':policies']) || []
      const mappedPolicies = this.mrfSettings.reduce((acc, { key, related_policy }) => {
        if (key !== ':mrf') {
          acc[key] = related_policy
Original line number Diff line number Diff line
<template>
  <div v-if="!loading" :class="isSidebarOpen" class="form-container">
    <editor-input v-model="termsOfServicesContent" :name="'terms-of-service'" @input="handleEditorUpdate"/>
    <el-divider class="divider thick-line"/>
    <el-form :model="mimeTypesData" :label-position="labelPosition" :label-width="labelWidth">
      <setting :setting-group="mimeTypes" :data="mimeTypesData"/>
    </el-form>
@@ -25,11 +27,17 @@
import { mapGetters } from 'vuex'
import i18n from '@/lang'
import Setting from './Setting'
import { EditorInput } from './inputComponents'
import _ from 'lodash'

export default {
  name: 'Other',
  components: { Setting },
  components: { EditorInput, Setting },
  data() {
    return {
      termsOfServices: ''
    }
  },
  computed: {
    ...mapGetters([
      'settings'
@@ -81,12 +89,27 @@ export default {
    },
    remoteIpData() {
      return _.get(this.settings.settings, [':pleroma', 'Pleroma.Plugs.RemoteIp']) || {}
    },
    termsOfServicesContent: {
      get() {
        return this.$store.state.settings.termsOfServices
      },
      set(content) {
        this.termsOfServices = content
      }
    }
  },
  async mounted() {
    await this.$store.dispatch('FetchInstanceDocument', 'terms-of-service')
  },
  methods: {
    handleEditorUpdate(content) {
      this.editorContent = content
    },
    async onSubmit() {
      try {
        await this.$store.dispatch('SubmitChanges')
        await this.$store.dispatch('UpdateInstanceDocs', { name: 'terms-of-service', content: this.editorContent })
      } catch (e) {
        return
      }
Original line number Diff line number Diff line
<template>
  <el-form :label-position="labelPosition" :label-width="labelWidth">
    <el-form-item :data-search="name === 'instance-panel' ? ':instance_panel' : ':terms_of_services'" class="editor-form-item">
      <span slot="label">
        {{ name === 'instance-panel' ? $t('settings.instancePanel') : $t('settings.termsOfServices') }}
        <el-tooltip :content="$t('settings.removeFromDB')" placement="bottom-end">
          <el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeInstanceDoc"/>
        </el-tooltip>
      </span>
      <div class="editor">
        <editor-menu-bar v-slot="{ commands, isActive }" :editor="editor">
          <div class="menubar">
            <button
              :class="{ 'is-active': isActive.bold() }"
              class="menubar__button"
              @click="commands.bold">
              <svg-icon icon-class="tiptap-bold" />
            </button>
            <button
              :class="{ 'is-active': isActive.italic() }"
              class="menubar__button"
              @click="commands.italic">
              <svg-icon icon-class="tiptap-italic" />
            </button>
            <button
              :class="{ 'is-active': isActive.underline() }"
              class="menubar__button"
              @click="commands.underline">
              <svg-icon icon-class="tiptap-underline" />
            </button>
            <button
              :class="{ 'is-active': isActive.heading({ level: 1 }) }"
              class="menubar__button"
              @click="commands.heading({ level: 1 })">
              H1
            </button>
            <button
              :class="{ 'is-active': isActive.heading({ level: 2 }) }"
              class="menubar__button"
              @click="commands.heading({ level: 2 })">
              H2
            </button>
            <button
              :class="{ 'is-active': isActive.heading({ level: 3 }) }"
              class="menubar__button"
              @click="commands.heading({ level: 3 })">
              H3
            </button>
            <button
              :class="{ 'is-active': isActive.bullet_list() }"
              class="menubar__button"
              @click="commands.bullet_list">
              <svg-icon icon-class="tiptap-ul" />
            </button>
            <button
              :class="{ 'is-active': isActive.ordered_list() }"
              class="menubar__button"
              @click="commands.ordered_list">
              <svg-icon icon-class="tiptap-ol" />
            </button>
            <button
              :class="{ 'is-active': isActive.blockquote() }"
              class="menubar__button"
              @click="commands.blockquote">
              <svg-icon icon-class="tiptap-quote" />
            </button>
            <button
              :class="{ 'is-active': isActive.link() }"
              class="menubar__button"
              @click="commands.link">
              <svg-icon icon-class="tiptap-link" />
            </button>
            <button
              :class="{ 'is-active': isActive.code_block() }"
              class="menubar__button"
              @click="commands.code_block">
              <svg-icon icon-class="tiptap-code" />
            </button>
            <button
              class="menubar__button"
              @click="commands.horizontal_rule">
              <svg-icon icon-class="tiptap-hr" />
            </button>
            <button
              class="menubar__button"
              @click="commands.undo">
              <svg-icon icon-class="tiptap-undo" />
            </button>
            <button
              class="menubar__button"
              @click="commands.redo">
              <svg-icon icon-class="tiptap-redo" />
            </button>
          </div>
        </editor-menu-bar>
        <editor-content :editor="editor" class="editor__content" />
      </div>
    </el-form-item>
  </el-form>
</template>

<script>
import { Editor, EditorContent, EditorMenuBar } from 'tiptap'
import {
  Blockquote,
  CodeBlock,
  Heading,
  HorizontalRule,
  OrderedList,
  BulletList,
  ListItem,
  Bold,
  Italic,
  Link,
  Underline,
  History
} from 'tiptap-extensions'

export default {
  name: 'EditorInput',
  components: {
    EditorContent,
    EditorMenuBar
  },
  props: {
    value: {
      type: String,
      default: ''
    },
    name: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      editor: null,
      emitAfterOnUpdate: false
    }
  },
  computed: {
    isMobile() {
      return this.$store.state.app.device === 'mobile'
    },
    labelPosition() {
      return this.isMobile ? 'top' : 'right'
    },
    labelWidth() {
      if (this.isMobile) {
        return '120px'
      } else if (this.isTablet) {
        return '200px'
      } else {
        return '280px'
      }
    }
  },
  watch: {
    value(val) {
      if (this.emitAfterOnUpdate) {
        this.emitAfterOnUpdate = false
        return
      }
      if (this.editor) this.editor.setContent(val)
    }
  },
  beforeDestroy() {
    if (this.editor) {
      this.editor.destroy()
    }
  },
  mounted() {
    this.editor = new Editor({
      extensions: [
        new Blockquote(),
        new Bold(),
        new BulletList(),
        new CodeBlock(),
        new Heading({ levels: [1, 2, 3] }),
        new History(),
        new HorizontalRule(),
        new Italic(),
        new Link(),
        new ListItem(),
        new OrderedList(),
        new Underline()
      ],
      content: this.value,
      onUpdate: ({ getHTML }) => {
        this.$emit('input', getHTML())
      }
    })
    this.editor.setContent(this.value)
  },
  methods: {
    async removeInstanceDoc() {
      await this.$store.dispatch('RemoveInstanceDocument', this.name)
      this.editor.setContent(this.value)
    }
  }
}
</script>

<style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main';
@include tiptap
</style>
Original line number Diff line number Diff line
export { default as EditableKeywordInput } from './EditableKeywordInput'
export { default as EditorInput } from './EditorInput'
export { default as IconsInput } from './IconsInput'
export { default as ImageUploadInput } from './ImageUploadInput'
export { default as LinkFormatterInput } from './LinkFormatterInput'
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ export const tabs = description => {
    },
    'authentication': {
      label: 'settings.auth',
      settings: [':auth', ':ldap', ':oauth2', 'Pleroma.Web.Auth.Authenticator', ':restrict_unauthenticated']
      settings: [':auth', ':ldap', ':oauth2', 'Pleroma.Web.Auth.Authenticator']
    },
    'esshd': {
      label: 'settings.esshd',
@@ -30,7 +30,7 @@ export const tabs = description => {
    },
    'instance': {
      label: 'settings.instance',
      settings: [':admin_token', ':instance', ':instances_favicons', ':welcome', ':manifest', 'Pleroma.User', 'Pleroma.ScheduledActivity', ':uri_schemes', ':feed', ':streamer']
      settings: [':admin_token', ':instance', ':instance_panel', ':instances_favicons', ':welcome', ':manifest', 'Pleroma.User', 'Pleroma.ScheduledActivity', ':uri_schemes', ':feed', ':streamer', ':restrict_unauthenticated']
    },
    'job-queue': {
      label: 'settings.jobQueue',
@@ -78,7 +78,7 @@ export const tabs = description => {
    },
    'other': {
      label: 'settings.other',
      settings: [':mime', 'Pleroma.Plugs.RemoteIp', ':modules', 'Pleroma.Web.ApiSpec.CastAndValidate']
      settings: [':mime', 'Pleroma.Plugs.RemoteIp', ':modules', 'Pleroma.Web.ApiSpec.CastAndValidate', ':terms_of_services']
    }
  }
}
Original line number Diff line number Diff line
@@ -697,3 +697,168 @@
    }
  }
}

@mixin tiptap {
  .editor {
    position: relative;
    border-radius: 4px;
    border: 1px solid #DCDFE6;
    padding: 10px;
  
    &__content {
  
      overflow-wrap: break-word;
      word-wrap: break-word;
      word-break: break-word;
      padding-left: 10px;
  
      * {
        caret-color: currentColor;
      }
  
      pre {
        border-radius: 5px;
        font-size: 0.8rem;
        overflow-x: auto;
  
        code {
          display: block;
        }
      }
      
      p code {
        border-radius: 5px;
        font-size: 0.8rem;
        font-weight: bold;
      }
  
      ul,
      ol {
        padding-left: 1rem;
      }
  
      li > p,
      li > ol,
      li > ul {
        margin: 0;
      }
  
      a {
        color: inherit;
      }
  
      blockquote {
        border-left: 3px solid rgba(#000000, 0.1);
        color: rgba(#000000, 0.8);
        padding-left: 0.8rem;
        font-style: italic;
  
        p {
          margin: 0;
        }
      }
  
      img {
        max-width: 100%;
        border-radius: 3px;
      }
  
      table {
        border-collapse: collapse;
        table-layout: fixed;
        width: 100%;
        margin: 0;
        overflow: hidden;
  
        td, th {
          min-width: 1em;
          border: 2px solid #dddddd;
          padding: 3px 5px;
          vertical-align: top;
          box-sizing: border-box;
          position: relative;
          > * {
            margin-bottom: 0;
          }
        }
  
        th {
          font-weight: bold;
          text-align: left;
        }
  
        .selectedCell:after {
          z-index: 2;
          position: absolute;
          content: "";
          left: 0; right: 0; top: 0; bottom: 0;
          background: rgba(200, 200, 255, 0.4);
          pointer-events: none;
        }
  
        .column-resize-handle {
          position: absolute;
          right: -2px; top: 0; bottom: 0;
          width: 4px;
          z-index: 20;
          background-color: #adf;
          pointer-events: none;
        }
      }
  
      .tableWrapper {
        margin: 1em 0;
        overflow-x: auto;
      }
  
      .resize-cursor {
        cursor: ew-resize;
        cursor: col-resize;
      }
  
    }
  }
  .editor-form-item {
    margin-right: 30px;
  }
  .menubar {

    margin-bottom: 1rem;
    transition: visibility 0.2s 0.4s, opacity 0.2s 0.4s;
  
    &.is-hidden {
      visibility: hidden;
      opacity: 0;
    }
  
    &.is-focused {
      visibility: visible;
      opacity: 1;
      transition: visibility 0.2s, opacity 0.2s;
    }
  
    &__button {
      font-weight: bold;
      display: inline-flex;
      background: transparent;
      border: 0;
      color: #000000;
      padding: 0.2rem 0.5rem;
      margin-right: 0.2rem;
      border-radius: 3px;
      cursor: pointer;
  
      &:hover {
        background-color: rgba(#000000, 0.05);
      }
  
      &.is-active {
        background-color: rgba(#000000, 0.1);
      }
    }
  
    span#{&}__button {
      font-size: 13.3333px;
    }
  }
}
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
        </span>
      </el-button>
    </div>
    <el-dropdown-menu slot="dropdown">
    <el-dropdown-menu slot="dropdown" class="moderation-dropdown-menu">
      <el-dropdown-item
        class="actor-type-dropdown">
        <el-select v-model="actorType" :placeholder="$t('userProfile.actorType')" class="actor-type-select">
@@ -68,6 +68,7 @@
        {{ $t('users.resendConfirmation') }}
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :divided="showAdminAction(user)"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:media-force-nsfw') }"
        @click.native="toggleTag(user, 'mrf_tag:media-force-nsfw')">
@@ -75,37 +76,47 @@
        <i v-if="user.tags.includes('mrf_tag:media-force-nsfw')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:media-strip') }"
        @click.native="toggleTag(user, 'mrf_tag:media-strip')">
        {{ $t('users.stripMedia') }}
        <i v-if="user.tags.includes('mrf_tag:media-strip')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:force-unlisted') }"
        @click.native="toggleTag(user, 'mrf_tag:force-unlisted')">
        {{ $t('users.forceUnlisted') }}
        <i v-if="user.tags.includes('mrf_tag:force-unlisted')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="tagPolicyEnabled"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:sandbox') }"
        @click.native="toggleTag(user, 'mrf_tag:sandbox')">
        {{ $t('users.sandbox') }}
        <i v-if="user.tags.includes('mrf_tag:sandbox')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="user.local"
        v-if="user.local && tagPolicyEnabled"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:disable-remote-subscription') }"
        @click.native="toggleTag(user, 'mrf_tag:disable-remote-subscription')">
        {{ $t('users.disableRemoteSubscription') }}
        <i v-if="user.tags.includes('mrf_tag:disable-remote-subscription')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="user.local"
        v-if="user.local && tagPolicyEnabled"
        :class="{ 'active-tag': user.tags.includes('mrf_tag:disable-any-subscription') }"
        @click.native="toggleTag(user, 'mrf_tag:disable-any-subscription')">
        {{ $t('users.disableAnySubscription') }}
        <i v-if="user.tags.includes('mrf_tag:disable-any-subscription')" class="el-icon-check"/>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="!tagPolicyEnabled"
        divided
        class="no-hover"
        @click.native="enableTagPolicy">
        {{ $t('users.enableTagPolicy') }}
      </el-dropdown-item>
      <el-dropdown-item
        v-if="user.local"
        divided
@@ -161,12 +172,35 @@ export default {
    },
    isDesktop() {
      return this.$store.state.app.device === 'desktop'
    },
    tagPolicyEnabled() {
      return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
    }
  },
  methods: {
    disableMfa(nickname) {
      this.$store.dispatch('DisableMfa', nickname)
    },
    enableTagPolicy() {
      this.$confirm(
        this.$t('users.confirmEnablingTagPolicy'),
        {
          confirmButtonText: 'Yes',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
        this.$message({
          type: 'success',
          message: this.$t('users.enableTagPolicySuccessMessage')
        })
        this.$store.dispatch('EnableTagPolicy')
      }).catch(() => {
        this.$message({
          type: 'info',
          message: 'Canceled'
        })
      })
    },
    getPasswordResetToken(nickname) {
      this.$emit('open-reset-token-dialog')
      this.$store.dispatch('GetPasswordResetToken', nickname)
@@ -288,9 +322,15 @@ export default {
    display: flex;
    justify-content: space-between;
  }
  .moderation-dropdown-menu {
    width: 350px;
  }
  @media only screen and (max-width:480px) {
    .moderate-user-button {
      width: 100%
    }
    .moderation-dropdown-menu {
      width: auto;
    }
  }
</style>
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@
        @click.native="requirePasswordReset">
        {{ $t('users.requirePasswordReset') }}
      </el-dropdown-item>
      <el-dropdown-item divided class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" divided class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.forceNsfw') }}</span>
          <el-button-group class="tag-button-group">
@@ -74,7 +74,7 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.stripMedia') }}</span>
          <el-button-group class="tag-button-group">
@@ -87,7 +87,7 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.forceUnlisted') }}</span>
          <el-button-group class="tag-button-group">
@@ -100,7 +100,7 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.sandbox') }}</span>
          <el-button-group class="tag-button-group">
@@ -113,7 +113,7 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.disableRemoteSubscriptionForMultiple') }}</span>
          <el-button-group class="tag-button-group">
@@ -126,7 +126,7 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item class="no-hover">
      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
        <div class="tag-container">
          <span class="tag-text">{{ $t('users.disableAnySubscriptionForMultiple') }}</span>
          <el-button-group class="tag-button-group">
@@ -139,6 +139,12 @@
          </el-button-group>
        </div>
      </el-dropdown-item>
      <el-dropdown-item
        v-if="!tagPolicyEnabled"
        divided
        @click.native="enableTagPolicy">
        {{ $t('users.enableTagPolicy') }}
      </el-dropdown-item>
    </el-dropdown-menu>
    <el-dropdown-menu v-else slot="dropdown">
      <el-dropdown-item>
@@ -159,11 +165,14 @@ export default {
    }
  },
  computed: {
    isDesktop() {
      return this.$store.state.app.device === 'desktop'
    },
    showDropdownForMultipleUsers() {
      return this.$props.selectedUsers.length > 0
    },
    isDesktop() {
      return this.$store.state.app.device === 'desktop'
    tagPolicyEnabled() {
      return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
    }
  },
  methods: {
@@ -248,6 +257,26 @@ export default {
        }
      }
    },
    enableTagPolicy() {
      this.$confirm(
        this.$t('users.confirmEnablingTagPolicy'),
        {
          confirmButtonText: 'Yes',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
        this.$message({
          type: 'success',
          message: this.$t('users.enableTagPolicySuccessMessage')
        })
        this.$store.dispatch('EnableTagPolicy')
      }).catch(() => {
        this.$message({
          type: 'info',
          message: 'Canceled'
        })
      })
    },
    isLocalUser(user) {
      return user.nickname && user.local
    },
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ export default {
      return re.test(email)
    },
    validNickname(nickname) {
      var re = /^[a-zA-Z\d]+$/
      var re = /^[a-zA-Z\d_-]+$/
      return re.test(nickname)
    }
  }
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ export default {
  },
  mounted: function() {
    this.$store.dispatch('NeedReboot')
    this.$store.dispatch('FetchTagPolicySetting')
    this.$store.dispatch('FetchUsers', { page: 1 })
  },
  destroyed() {
@@ -275,6 +276,11 @@ export default {
    margin: 7px 0 0 15px;
  }
}
.active-tag.is-disabled {
  .el-icon-check {
    color: #bbb;
  }
}
.el-dropdown-link:hover {
    cursor: pointer;
    color: #409EFF;
Original line number Diff line number Diff line
@@ -341,6 +341,40 @@ describe('Wrap settings', () => {
    expect(_.isEqual(result2, expectedResult2)).toBeTruthy()
  })

  it('wraps settings with type [`list`, `map`]', () => {
    const settings = { ':manifest': { ':icons': [['map', 'list'], [
      { ':src': '/static/logo.png', ':type': 'image/png' },
      { ':src': '/static/icon.png', ':type': 'image/png' }
    ]]}}
    
    const state = { ':pleroma': { ':manifest': { 
      ':background_color': '#191b22',
      ':theme_color': '#282c37',
      ':icons': [
        [
          { 'id': 'f21318c4', 'key': ':src', 'value': '/static/logo.png' },
          { 'id': 'f4b87549', 'key': ':type', 'value': 'image/png' }
        ], [
          { 'id': 'f31d351e', 'key': ':src', 'value': '/static/icon.png' },
          { 'id': 'f1455852', 'key': ':type', 'value': 'image/png' }
        ]
      ]
    }}}

    const result = wrapUpdatedSettings(':pleroma', settings, state)
    const expectedResult = [{
      group: ':pleroma',
      key: ':manifest',
      value: [{ tuple: [':icons', [
        { ':src': '/static/logo.png', ':type': 'image/png' },
        { ':src': '/static/icon.png', ':type': 'image/png' }
      ]]}]
    }]

    expect(_.isEqual(result, expectedResult)).toBeTruthy()
  })


  it('wraps IP setting', () => {
    const settings = { ':gopher': { ':ip': ['tuple', '127.0.0.1']}}
    const state = { ':pleroma': { ':gopher': {}}}
Original line number Diff line number Diff line
import Vuex from 'vuex'
import { mount, createLocalVue, config } from '@vue/test-utils'
import { mount, createLocalVue, config, RouterLinkStub } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import Element from 'element-ui'
import Invites from '@/views/invites/index'
@@ -15,6 +15,7 @@ localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/invites')
jest.mock('@/api/nodeInfo')
jest.mock('@/api/settings')

describe('Invite tokens', () => {
  let store
@@ -28,7 +29,9 @@ describe('Invite tokens', () => {
      store,
      localVue,
      sync: false,
      stubs: ['router-link']
      stubs: {
        RouterLink: RouterLinkStub
      }
    })

    await flushPromises()
@@ -42,7 +45,9 @@ describe('Invite tokens', () => {
      store,
      localVue,
      sync: false,
      stubs: ['router-link']
      stubs: {
        RouterLink: RouterLinkStub
      }
    })
    await flushPromises()

@@ -66,7 +71,9 @@ describe('Invite tokens', () => {
      store,
      localVue,
      sync: false,
      stubs: ['router-link']
      stubs: {
        RouterLink: RouterLinkStub
      }
    })
    await flushPromises()
    expect(store.state.invites.inviteTokens.length).toEqual(3)
@@ -101,7 +108,9 @@ describe('Invite tokens', () => {
      store,
      localVue,
      sync: false,
      stubs: ['router-link']
      stubs: {
        RouterLink: RouterLinkStub
      }
    })

    await flushPromises()
@@ -114,39 +123,4 @@ describe('Invite tokens', () => {
    expect(store.state.invites.inviteTokens[0].used).toBe(true)
    done()
  })

  it('invites user via email', async (done) => {
    const wrapper = mount(Invites, {
      store,
      localVue,
      sync: false,
      stubs: ['router-link']
    })

    const dialog = wrapper.find('div.el-dialog__wrapper .invite-via-email-dialog')
    expect(dialog.isVisible()).toBe(false)

    const inviteUserViaEmailStub = jest.fn()
    wrapper.setMethods({ inviteUserViaEmail: inviteUserViaEmailStub })

    const openDialogButton = wrapper.find('button.invite-via-email')
    openDialogButton.trigger('click')
    await flushPromises()
    expect(dialog.isVisible()).toBe(true)

    const email = wrapper.find('input[name="email"]')
    email.element.value = 'bob@gmail.com'
    email.trigger('input')

    const name = wrapper.find('input[name="name"]')
    name.element.value = 'Bob'
    name.trigger('input')

    const createButton = wrapper.find('.invite-via-email-dialog button.el-button--primary')
    createButton.trigger('click')
    await flushPromises()

    expect(wrapper.vm.inviteUserViaEmail).toHaveBeenCalled()
    done()
  })
})

test/views/layout/index.test.js

deleted100644 → 0
+0 −49
Original line number Diff line number Diff line
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import { mount, createLocalVue, config } from '@vue/test-utils'
import Element from 'element-ui'
import Layout from '@/views/layout/Layout'
import storeConfig from './store.conf'
import routerConfig from './router.conf'
import { cloneDeep } from 'lodash'
import { beforeEachRoute } from '@/permission'

config.mocks["$t"] = () => {}

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
localVue.use(Element)

describe('Log out', () => {
  let store
  let router

  beforeEach(() => {
    store = new Vuex.Store(cloneDeep(storeConfig))
    router = new VueRouter(cloneDeep(routerConfig))
    router.beforeEach(beforeEachRoute)

    delete window.location
    window.location = { href: '' }
  })

  it('logs out user', async (done) => {
    const wrapper = mount(Layout, {
      store,
      router,
      localVue
    })

    const logoutButton = wrapper.find('span')
    expect(store.state.user.roles.length).toBe(1)
    expect(store.state.user.token).toBe('foo123')

    logoutButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(store.state.user.roles.length).toBe(0)
    expect(store.state.user.token).toBe('')
    done()
  })
})
Original line number Diff line number Diff line
import app from '@/store/modules/app'
import errorLog from '@/store/modules/errorLog'
import permission from '@/store/modules/permission'
import reports from '@/store/modules/reports'
import tagsView from '@/store/modules/tagsView'
import user from '@/store/modules/user'
import getters from '@/store/getters'
@@ -10,6 +11,7 @@ export default {
    app,
    errorLog,
    permission,
    reports,
    tagsView,
    user: {
      ...user,
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@ localVue.use(Vuex)
localVue.use(VueRouter)
localVue.use(Element)

jest.mock('@/api/app')
jest.mock('@/api/nodeInfo')
jest.mock('@/api/login')
jest.mock('@/api/settings')

describe('Login', () => {
  let store
+100 −0
Original line number Diff line number Diff line
import Vuex from 'vuex'
import { mount, createLocalVue, config } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import Element from 'element-ui'
import MediaProxyCache from '@/views/mediaProxyCache/index'
import app from '@/store/modules/app'
import mediaProxyCache from '@/store/modules/mediaProxyCache'
import settings from '@/store/modules/settings'
import user from '@/store/modules/user'
import getters from '@/store/getters'

config.mocks["$t"] = () => {}

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)

jest.mock('@/api/app')
jest.mock('@/api/nodeInfo')
jest.mock('@/api/mediaProxyCache')
jest.mock('@/api/settings')

describe('MediaProxy Cache Invalidation', () => {
  let store
  let actions

  beforeEach(() => {
    actions = { ...mediaProxyCache.actions, PurgeUrls: jest.fn() }
    store = new Vuex.Store({ 
      modules: {
        app,
        mediaProxyCache: { ...mediaProxyCache, actions },
        user,
        settings,
      },
      getters
    })
  })

  it('fetches initial list of urls', async (done) => {
    const wrapper = mount(MediaProxyCache, {
      store,
      localVue,
      sync: false
    })

    await flushPromises()
    expect(wrapper.vm.urlsCount).toEqual(2)