mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-25 17:51:36 +01:00
Merge pull request #2846 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to e0648a916a
This commit is contained in:
commit
c8ef702ba9
95 changed files with 2093 additions and 1161 deletions
|
@ -7,8 +7,13 @@ RSpec/Focus: # Require full spec run on CI
|
||||||
Exclude: []
|
Exclude: []
|
||||||
|
|
||||||
Rails/Output: # Remove any `puts` debugging
|
Rails/Output: # Remove any `puts` debugging
|
||||||
|
inherit_mode:
|
||||||
|
merge:
|
||||||
|
- Include
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Exclude: []
|
Exclude: []
|
||||||
|
Include:
|
||||||
|
- spec/**/*.rb
|
||||||
|
|
||||||
Rails/FindEach: # Using `each` could impact performance, use `find_each`
|
Rails/FindEach: # Using `each` could impact performance, use `find_each`
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -331,7 +331,7 @@ GEM
|
||||||
httplog (1.7.0)
|
httplog (1.7.0)
|
||||||
rack (>= 2.0)
|
rack (>= 2.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.14.5)
|
i18n (1.14.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (1.0.14)
|
i18n-tasks (1.0.14)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
|
@ -472,9 +472,9 @@ GEM
|
||||||
omniauth-rails_csrf_protection (1.0.2)
|
omniauth-rails_csrf_protection (1.0.2)
|
||||||
actionpack (>= 4.2)
|
actionpack (>= 4.2)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.0)
|
||||||
omniauth-saml (2.1.0)
|
omniauth-saml (2.2.1)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.1)
|
||||||
ruby-saml (~> 1.12)
|
ruby-saml (~> 1.17)
|
||||||
omniauth_openid_connect (0.6.1)
|
omniauth_openid_connect (0.6.1)
|
||||||
omniauth (>= 1.9, < 3)
|
omniauth (>= 1.9, < 3)
|
||||||
openid_connect (~> 1.1)
|
openid_connect (~> 1.1)
|
||||||
|
@ -764,7 +764,7 @@ GEM
|
||||||
rubocop-rspec (~> 3, >= 3.0.1)
|
rubocop-rspec (~> 3, >= 3.0.1)
|
||||||
ruby-prof (1.7.0)
|
ruby-prof (1.7.0)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-saml (1.16.0)
|
ruby-saml (1.17.0)
|
||||||
nokogiri (>= 1.13.10)
|
nokogiri (>= 1.13.10)
|
||||||
rexml
|
rexml
|
||||||
ruby-vips (2.2.2)
|
ruby-vips (2.2.2)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V2Alpha::Notifications::AccountsController < Api::BaseController
|
class Api::V2::Notifications::AccountsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }
|
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_notifications!
|
before_action :set_notifications!
|
||||||
|
@ -33,11 +33,11 @@ class Api::V2Alpha::Notifications::AccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v2_alpha_notification_accounts_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v2_notification_accounts_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
||||||
def prev_path
|
def prev_path
|
||||||
api_v2_alpha_notification_accounts_url pagination_params(min_id: pagination_since_id) unless @paginated_notifications.empty?
|
api_v2_notification_accounts_url pagination_params(min_id: pagination_since_id) unless @paginated_notifications.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_collection
|
def pagination_collection
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V2Alpha::NotificationsController < Api::BaseController
|
class Api::V2::NotificationsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss]
|
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss]
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss]
|
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss]
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
@ -21,7 +21,7 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
|
||||||
ActiveRecord::Associations::Preloader.new(records: @presenter.accounts, associations: [:account_stat, { user: :role }]).call
|
ActiveRecord::Associations::Preloader.new(records: @presenter.accounts, associations: [:account_stat, { user: :role }]).call
|
||||||
end
|
end
|
||||||
|
|
||||||
MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#index rendering') do |span|
|
MastodonOTELTracer.in_span('Api::V2::NotificationsController#index rendering') do |span|
|
||||||
statuses = @grouped_notifications.filter_map { |group| group.target_status&.id }
|
statuses = @grouped_notifications.filter_map { |group| group.target_status&.id }
|
||||||
|
|
||||||
span.add_attributes(
|
span.add_attributes(
|
||||||
|
@ -64,7 +64,7 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_notifications
|
def load_notifications
|
||||||
MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#load_notifications') do
|
MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_notifications') do
|
||||||
notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_grouped_paginated_by_id(
|
notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_grouped_paginated_by_id(
|
||||||
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
||||||
params.slice(:max_id, :since_id, :min_id, :grouped_types).permit(:max_id, :since_id, :min_id, grouped_types: [])
|
params.slice(:max_id, :since_id, :min_id, :grouped_types).permit(:max_id, :since_id, :min_id, grouped_types: [])
|
||||||
|
@ -79,7 +79,7 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
|
||||||
def load_grouped_notifications
|
def load_grouped_notifications
|
||||||
return [] if @notifications.empty?
|
return [] if @notifications.empty?
|
||||||
|
|
||||||
MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#load_grouped_notifications') do
|
MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_grouped_notifications') do
|
||||||
NotificationGroup.from_notifications(@notifications, pagination_range: (@notifications.last.id)..(@notifications.first.id), grouped_types: params[:grouped_types])
|
NotificationGroup.from_notifications(@notifications, pagination_range: (@notifications.last.id)..(@notifications.first.id), grouped_types: params[:grouped_types])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -101,11 +101,11 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v2_alpha_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty?
|
api_v2_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def prev_path
|
def prev_path
|
||||||
api_v2_alpha_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty?
|
api_v2_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_collection
|
def pagination_collection
|
|
@ -2,7 +2,7 @@ import { createAction } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
apiClearNotifications,
|
apiClearNotifications,
|
||||||
apiFetchNotifications,
|
apiFetchNotificationGroups,
|
||||||
} from 'flavours/glitch/api/notifications';
|
} from 'flavours/glitch/api/notifications';
|
||||||
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
|
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
|
||||||
import type {
|
import type {
|
||||||
|
@ -71,7 +71,7 @@ function dispatchAssociatedRecords(
|
||||||
export const fetchNotifications = createDataLoadingThunk(
|
export const fetchNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/fetch',
|
'notificationGroups/fetch',
|
||||||
async (_params, { getState }) =>
|
async (_params, { getState }) =>
|
||||||
apiFetchNotifications({ exclude_types: getExcludedTypes(getState()) }),
|
apiFetchNotificationGroups({ exclude_types: getExcludedTypes(getState()) }),
|
||||||
({ notifications, accounts, statuses }, { dispatch }) => {
|
({ notifications, accounts, statuses }, { dispatch }) => {
|
||||||
dispatch(importFetchedAccounts(accounts));
|
dispatch(importFetchedAccounts(accounts));
|
||||||
dispatch(importFetchedStatuses(statuses));
|
dispatch(importFetchedStatuses(statuses));
|
||||||
|
@ -92,7 +92,7 @@ export const fetchNotifications = createDataLoadingThunk(
|
||||||
export const fetchNotificationsGap = createDataLoadingThunk(
|
export const fetchNotificationsGap = createDataLoadingThunk(
|
||||||
'notificationGroups/fetchGap',
|
'notificationGroups/fetchGap',
|
||||||
async (params: { gap: NotificationGap }, { getState }) =>
|
async (params: { gap: NotificationGap }, { getState }) =>
|
||||||
apiFetchNotifications({
|
apiFetchNotificationGroups({
|
||||||
max_id: params.gap.maxId,
|
max_id: params.gap.maxId,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
}),
|
}),
|
||||||
|
@ -108,7 +108,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
||||||
export const pollRecentNotifications = createDataLoadingThunk(
|
export const pollRecentNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/pollRecentNotifications',
|
'notificationGroups/pollRecentNotifications',
|
||||||
async (_params, { getState }) => {
|
async (_params, { getState }) => {
|
||||||
return apiFetchNotifications({
|
return apiFetchNotificationGroups({
|
||||||
max_id: undefined,
|
max_id: undefined,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
||||||
|
|
234
app/javascript/flavours/glitch/actions/notification_requests.ts
Normal file
234
app/javascript/flavours/glitch/actions/notification_requests.ts
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
import {
|
||||||
|
apiFetchNotificationRequest,
|
||||||
|
apiFetchNotificationRequests,
|
||||||
|
apiFetchNotifications,
|
||||||
|
apiAcceptNotificationRequest,
|
||||||
|
apiDismissNotificationRequest,
|
||||||
|
apiAcceptNotificationRequests,
|
||||||
|
apiDismissNotificationRequests,
|
||||||
|
} from 'flavours/glitch/api/notifications';
|
||||||
|
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
|
||||||
|
import type {
|
||||||
|
ApiNotificationGroupJSON,
|
||||||
|
ApiNotificationJSON,
|
||||||
|
} from 'flavours/glitch/api_types/notifications';
|
||||||
|
import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses';
|
||||||
|
import type { AppDispatch, RootState } from 'flavours/glitch/store';
|
||||||
|
import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions';
|
||||||
|
|
||||||
|
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||||
|
import { decreasePendingNotificationsCount } from './notification_policies';
|
||||||
|
|
||||||
|
// TODO: refactor with notification_groups
|
||||||
|
function dispatchAssociatedRecords(
|
||||||
|
dispatch: AppDispatch,
|
||||||
|
notifications: ApiNotificationGroupJSON[] | ApiNotificationJSON[],
|
||||||
|
) {
|
||||||
|
const fetchedAccounts: ApiAccountJSON[] = [];
|
||||||
|
const fetchedStatuses: ApiStatusJSON[] = [];
|
||||||
|
|
||||||
|
notifications.forEach((notification) => {
|
||||||
|
if (notification.type === 'admin.report') {
|
||||||
|
fetchedAccounts.push(notification.report.target_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.type === 'moderation_warning') {
|
||||||
|
fetchedAccounts.push(notification.moderation_warning.target_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('status' in notification && notification.status) {
|
||||||
|
fetchedStatuses.push(notification.status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchedAccounts.length > 0)
|
||||||
|
dispatch(importFetchedAccounts(fetchedAccounts));
|
||||||
|
|
||||||
|
if (fetchedStatuses.length > 0)
|
||||||
|
dispatch(importFetchedStatuses(fetchedStatuses));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/fetch',
|
||||||
|
async (_params, { getState }) => {
|
||||||
|
let sinceId = undefined;
|
||||||
|
|
||||||
|
if (getState().notificationRequests.items.length > 0) {
|
||||||
|
sinceId = getState().notificationRequests.items[0]?.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiFetchNotificationRequests({
|
||||||
|
since_id: sinceId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
({ requests, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(requests.map((request) => request.account)));
|
||||||
|
|
||||||
|
return { requests, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: (_params, { getState }) =>
|
||||||
|
!getState().notificationRequests.isLoading,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fetchNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/fetch',
|
||||||
|
async ({ id }: { id: string }) => apiFetchNotificationRequest(id),
|
||||||
|
{
|
||||||
|
condition: ({ id }, { getState }) =>
|
||||||
|
!(
|
||||||
|
getState().notificationRequests.current.item?.id === id ||
|
||||||
|
getState().notificationRequests.current.isLoading
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const expandNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/expand',
|
||||||
|
async (_, { getState }) => {
|
||||||
|
const nextUrl = getState().notificationRequests.next;
|
||||||
|
if (!nextUrl) throw new Error('missing URL');
|
||||||
|
|
||||||
|
return apiFetchNotificationRequests(undefined, nextUrl);
|
||||||
|
},
|
||||||
|
({ requests, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(requests.map((request) => request.account)));
|
||||||
|
|
||||||
|
return { requests, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: (_, { getState }) =>
|
||||||
|
!!getState().notificationRequests.next &&
|
||||||
|
!getState().notificationRequests.isLoading,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fetchNotificationsForRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/fetchNotifications',
|
||||||
|
async ({ accountId }: { accountId: string }, { getState }) => {
|
||||||
|
const sinceId =
|
||||||
|
// @ts-expect-error current.notifications.items is not yet typed
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
|
getState().notificationRequests.current.notifications.items[0]?.get(
|
||||||
|
'id',
|
||||||
|
) as string | undefined;
|
||||||
|
|
||||||
|
return apiFetchNotifications({
|
||||||
|
since_id: sinceId,
|
||||||
|
account_id: accountId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
({ notifications, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatchAssociatedRecords(dispatch, notifications);
|
||||||
|
|
||||||
|
return { notifications, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ({ accountId }, { getState }) => {
|
||||||
|
const current = getState().notificationRequests.current;
|
||||||
|
return !(
|
||||||
|
current.item?.account_id === accountId &&
|
||||||
|
current.notifications.isLoading
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const expandNotificationsForRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/expandNotifications',
|
||||||
|
async (_, { getState }) => {
|
||||||
|
const nextUrl = getState().notificationRequests.current.notifications.next;
|
||||||
|
if (!nextUrl) throw new Error('missing URL');
|
||||||
|
|
||||||
|
return apiFetchNotifications(undefined, nextUrl);
|
||||||
|
},
|
||||||
|
({ notifications, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatchAssociatedRecords(dispatch, notifications);
|
||||||
|
|
||||||
|
return { notifications, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ({ accountId }: { accountId: string }, { getState }) => {
|
||||||
|
const url = getState().notificationRequests.current.notifications.next;
|
||||||
|
|
||||||
|
return (
|
||||||
|
!!url &&
|
||||||
|
!getState().notificationRequests.current.notifications.isLoading &&
|
||||||
|
getState().notificationRequests.current.item?.account_id === accountId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectNotificationCountForRequest = (state: RootState, id: string) => {
|
||||||
|
const requests = state.notificationRequests.items;
|
||||||
|
const thisRequest = requests.find((request) => request.id === id);
|
||||||
|
return thisRequest ? thisRequest.notifications_count : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const acceptNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/accept',
|
||||||
|
({ id }: { id: string }) => apiAcceptNotificationRequest(id),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { id } }) => {
|
||||||
|
const count = selectNotificationCountForRequest(getState(), id);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const dismissNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/dismiss',
|
||||||
|
({ id }: { id: string }) => apiDismissNotificationRequest(id),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { id } }) => {
|
||||||
|
const count = selectNotificationCountForRequest(getState(), id);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const acceptNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/acceptBulk',
|
||||||
|
({ ids }: { ids: string[] }) => apiAcceptNotificationRequests(ids),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { ids } }) => {
|
||||||
|
const count = ids.reduce(
|
||||||
|
(count, id) => count + selectNotificationCountForRequest(getState(), id),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const dismissNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/dismissBulk',
|
||||||
|
({ ids }: { ids: string[] }) => apiDismissNotificationRequests(ids),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { ids } }) => {
|
||||||
|
const count = ids.reduce(
|
||||||
|
(count, id) => count + selectNotificationCountForRequest(getState(), id),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
|
@ -18,7 +18,6 @@ import {
|
||||||
importFetchedStatuses,
|
importFetchedStatuses,
|
||||||
} from './importer';
|
} from './importer';
|
||||||
import { submitMarkers } from './markers';
|
import { submitMarkers } from './markers';
|
||||||
import { decreasePendingNotificationsCount } from './notification_policies';
|
|
||||||
import { notificationsUpdate } from "./notifications_typed";
|
import { notificationsUpdate } from "./notifications_typed";
|
||||||
import { register as registerPushNotifications } from './push_notifications';
|
import { register as registerPushNotifications } from './push_notifications';
|
||||||
import { saveSettings } from './settings';
|
import { saveSettings } from './settings';
|
||||||
|
@ -57,26 +56,6 @@ export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
||||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_REQUEST = 'NOTIFICATION_REQUESTS_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_SUCCESS = 'NOTIFICATION_REQUESTS_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_FAIL = 'NOTIFICATION_REQUESTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_REQUEST = 'NOTIFICATION_REQUESTS_EXPAND_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_SUCCESS = 'NOTIFICATION_REQUESTS_EXPAND_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_FAIL = 'NOTIFICATION_REQUESTS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_REQUEST = 'NOTIFICATION_REQUEST_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_SUCCESS = 'NOTIFICATION_REQUEST_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_FAIL = 'NOTIFICATION_REQUEST_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_REQUEST = 'NOTIFICATION_REQUEST_ACCEPT_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_SUCCESS = 'NOTIFICATION_REQUEST_ACCEPT_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_FAIL = 'NOTIFICATION_REQUEST_ACCEPT_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_REQUEST = 'NOTIFICATION_REQUEST_DISMISS_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_SUCCESS = 'NOTIFICATION_REQUEST_DISMISS_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_FAIL = 'NOTIFICATION_REQUEST_DISMISS_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_REQUEST = 'NOTIFICATION_REQUESTS_ACCEPT_REQUEST';
|
export const NOTIFICATION_REQUESTS_ACCEPT_REQUEST = 'NOTIFICATION_REQUESTS_ACCEPT_REQUEST';
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_SUCCESS = 'NOTIFICATION_REQUESTS_ACCEPT_SUCCESS';
|
export const NOTIFICATION_REQUESTS_ACCEPT_SUCCESS = 'NOTIFICATION_REQUESTS_ACCEPT_SUCCESS';
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_FAIL = 'NOTIFICATION_REQUESTS_ACCEPT_FAIL';
|
export const NOTIFICATION_REQUESTS_ACCEPT_FAIL = 'NOTIFICATION_REQUESTS_ACCEPT_FAIL';
|
||||||
|
@ -85,14 +64,6 @@ export const NOTIFICATION_REQUESTS_DISMISS_REQUEST = 'NOTIFICATION_REQUESTS_DISM
|
||||||
export const NOTIFICATION_REQUESTS_DISMISS_SUCCESS = 'NOTIFICATION_REQUESTS_DISMISS_SUCCESS';
|
export const NOTIFICATION_REQUESTS_DISMISS_SUCCESS = 'NOTIFICATION_REQUESTS_DISMISS_SUCCESS';
|
||||||
export const NOTIFICATION_REQUESTS_DISMISS_FAIL = 'NOTIFICATION_REQUESTS_DISMISS_FAIL';
|
export const NOTIFICATION_REQUESTS_DISMISS_FAIL = 'NOTIFICATION_REQUESTS_DISMISS_FAIL';
|
||||||
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST = 'NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS = 'NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL = 'NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL';
|
|
||||||
|
|
||||||
defineMessages({
|
defineMessages({
|
||||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||||
});
|
});
|
||||||
|
@ -105,12 +76,6 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectNotificationCountForRequest = (state, id) => {
|
|
||||||
const requests = state.getIn(['notificationRequests', 'items']);
|
|
||||||
const thisRequest = requests.find(request => request.get('id') === id);
|
|
||||||
return thisRequest ? thisRequest.get('notifications_count') : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const loadPending = () => ({
|
export const loadPending = () => ({
|
||||||
type: NOTIFICATIONS_LOAD_PENDING,
|
type: NOTIFICATIONS_LOAD_PENDING,
|
||||||
});
|
});
|
||||||
|
@ -431,296 +396,3 @@ export function setBrowserPermission (value) {
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchNotificationRequests = () => (dispatch, getState) => {
|
|
||||||
const params = {};
|
|
||||||
|
|
||||||
if (getState().getIn(['notificationRequests', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getState().getIn(['notificationRequests', 'items'])?.size > 0) {
|
|
||||||
params.since_id = getState().getIn(['notificationRequests', 'items', 0, 'id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationRequestsRequest());
|
|
||||||
|
|
||||||
api().get('/api/v1/notifications/requests', { params }).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
|
||||||
dispatch(fetchNotificationRequestsSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationRequestsFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsRequest = () => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsSuccess = (requests, next) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_SUCCESS,
|
|
||||||
requests,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsFail = error => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequests = () => (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['notificationRequests', 'next']);
|
|
||||||
|
|
||||||
if (!url || getState().getIn(['notificationRequests', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandNotificationRequestsRequest());
|
|
||||||
|
|
||||||
api().get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
|
||||||
dispatch(expandNotificationRequestsSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandNotificationRequestsFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandNotificationRequestsRequest = () => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequestsSuccess = (requests, next) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_SUCCESS,
|
|
||||||
requests,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequestsFail = error => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequest = id => (dispatch, getState) => {
|
|
||||||
const current = getState().getIn(['notificationRequests', 'current']);
|
|
||||||
|
|
||||||
if (current.getIn(['item', 'id']) === id || current.get('isLoading')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().get(`/api/v1/notifications/requests/${id}`).then(({ data }) => {
|
|
||||||
dispatch(fetchNotificationRequestSuccess(data));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestSuccess = request => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_SUCCESS,
|
|
||||||
request,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequest = (id) => (dispatch, getState) => {
|
|
||||||
const count = selectNotificationCountForRequest(getState(), id);
|
|
||||||
dispatch(acceptNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/${id}/accept`).then(() => {
|
|
||||||
dispatch(acceptNotificationRequestSuccess(id));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(acceptNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const acceptNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestSuccess = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_SUCCESS,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequest = (id) => (dispatch, getState) => {
|
|
||||||
const count = selectNotificationCountForRequest(getState(), id);
|
|
||||||
dispatch(dismissNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{
|
|
||||||
dispatch(dismissNotificationRequestSuccess(id));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(dismissNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dismissNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestSuccess = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_SUCCESS,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequests = (ids) => (dispatch, getState) => {
|
|
||||||
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
|
|
||||||
dispatch(acceptNotificationRequestsRequest(ids));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/accept`, { id: ids }).then(() => {
|
|
||||||
dispatch(acceptNotificationRequestsSuccess(ids));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(acceptNotificationRequestFail(ids, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsRequest = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_REQUEST,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsSuccess = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_SUCCESS,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsFail = (ids, error) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_FAIL,
|
|
||||||
ids,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequests = (ids) => (dispatch, getState) => {
|
|
||||||
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
|
|
||||||
dispatch(acceptNotificationRequestsRequest(ids));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/dismiss`, { id: ids }).then(() => {
|
|
||||||
dispatch(dismissNotificationRequestsSuccess(ids));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(dismissNotificationRequestFail(ids, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsRequest = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_REQUEST,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsSuccess = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_SUCCESS,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsFail = (ids, error) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_FAIL,
|
|
||||||
ids,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequest = accountId => (dispatch, getState) => {
|
|
||||||
const current = getState().getIn(['notificationRequests', 'current']);
|
|
||||||
const params = { account_id: accountId };
|
|
||||||
|
|
||||||
if (current.getIn(['item', 'account']) === accountId) {
|
|
||||||
if (current.getIn(['notifications', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.getIn(['notifications', 'items'])?.size > 0) {
|
|
||||||
params.since_id = current.getIn(['notifications', 'items', 0, 'id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationsForRequestRequest());
|
|
||||||
|
|
||||||
api().get('/api/v1/notifications', { params }).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
|
||||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
|
||||||
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));
|
|
||||||
|
|
||||||
dispatch(fetchNotificationsForRequestSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationsForRequestFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestRequest = () => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestSuccess = (notifications, next) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS,
|
|
||||||
notifications,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestFail = (error) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequest = () => (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['notificationRequests', 'current', 'notifications', 'next']);
|
|
||||||
|
|
||||||
if (!url || getState().getIn(['notificationRequests', 'current', 'notifications', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandNotificationsForRequestRequest());
|
|
||||||
|
|
||||||
api().get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
|
||||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
|
||||||
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));
|
|
||||||
|
|
||||||
dispatch(expandNotificationsForRequestSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandNotificationsForRequestFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestRequest = () => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestSuccess = (notifications, next) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS,
|
|
||||||
notifications,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestFail = (error) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,14 +1,43 @@
|
||||||
import api, { apiRequest, getLinks } from 'flavours/glitch/api';
|
import api, {
|
||||||
import type { ApiNotificationGroupsResultJSON } from 'flavours/glitch/api_types/notifications';
|
apiRequest,
|
||||||
|
getLinks,
|
||||||
|
apiRequestGet,
|
||||||
|
apiRequestPost,
|
||||||
|
} from 'flavours/glitch/api';
|
||||||
|
import type {
|
||||||
|
ApiNotificationGroupsResultJSON,
|
||||||
|
ApiNotificationRequestJSON,
|
||||||
|
ApiNotificationJSON,
|
||||||
|
} from 'flavours/glitch/api_types/notifications';
|
||||||
|
|
||||||
export const apiFetchNotifications = async (params?: {
|
export const apiFetchNotifications = async (
|
||||||
|
params?: {
|
||||||
|
account_id?: string;
|
||||||
|
since_id?: string;
|
||||||
|
},
|
||||||
|
url?: string,
|
||||||
|
) => {
|
||||||
|
const response = await api().request<ApiNotificationJSON[]>({
|
||||||
|
method: 'GET',
|
||||||
|
url: url ?? '/api/v1/notifications',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
notifications: response.data,
|
||||||
|
links: getLinks(response),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiFetchNotificationGroups = async (params?: {
|
||||||
|
url?: string;
|
||||||
exclude_types?: string[];
|
exclude_types?: string[];
|
||||||
max_id?: string;
|
max_id?: string;
|
||||||
since_id?: string;
|
since_id?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const response = await api().request<ApiNotificationGroupsResultJSON>({
|
const response = await api().request<ApiNotificationGroupsResultJSON>({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/v2_alpha/notifications',
|
url: '/api/v2/notifications',
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,3 +53,43 @@ export const apiFetchNotifications = async (params?: {
|
||||||
|
|
||||||
export const apiClearNotifications = () =>
|
export const apiClearNotifications = () =>
|
||||||
apiRequest<undefined>('POST', 'v1/notifications/clear');
|
apiRequest<undefined>('POST', 'v1/notifications/clear');
|
||||||
|
|
||||||
|
export const apiFetchNotificationRequests = async (
|
||||||
|
params?: {
|
||||||
|
since_id?: string;
|
||||||
|
},
|
||||||
|
url?: string,
|
||||||
|
) => {
|
||||||
|
const response = await api().request<ApiNotificationRequestJSON[]>({
|
||||||
|
method: 'GET',
|
||||||
|
url: url ?? '/api/v1/notifications/requests',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
requests: response.data,
|
||||||
|
links: getLinks(response),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiFetchNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestGet<ApiNotificationRequestJSON>(
|
||||||
|
`v1/notifications/requests/${id}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiAcceptNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestPost(`v1/notifications/requests/${id}/accept`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiDismissNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestPost(`v1/notifications/requests/${id}/dismiss`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiAcceptNotificationRequests = async (id: string[]) => {
|
||||||
|
return apiRequestPost('v1/notifications/requests/accept', { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiDismissNotificationRequests = async (id: string[]) => {
|
||||||
|
return apiRequestPost('v1/notifications/dismiss/dismiss', { id });
|
||||||
|
};
|
||||||
|
|
|
@ -149,3 +149,12 @@ export interface ApiNotificationGroupsResultJSON {
|
||||||
statuses: ApiStatusJSON[];
|
statuses: ApiStatusJSON[];
|
||||||
notification_groups: ApiNotificationGroupJSON[];
|
notification_groups: ApiNotificationGroupJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiNotificationRequestJSON {
|
||||||
|
id: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
notifications_count: string;
|
||||||
|
account: ApiAccountJSON;
|
||||||
|
last_status?: ApiStatusJSON;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { initBlockModal } from 'flavours/glitch/actions/blocks';
|
import { initBlockModal } from 'flavours/glitch/actions/blocks';
|
||||||
import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
||||||
import { acceptNotificationRequest, dismissNotificationRequest } from 'flavours/glitch/actions/notifications';
|
import { acceptNotificationRequest, dismissNotificationRequest } from 'flavours/glitch/actions/notification_requests';
|
||||||
import { initReport } from 'flavours/glitch/actions/reports';
|
import { initReport } from 'flavours/glitch/actions/reports';
|
||||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import { CheckBox } from 'flavours/glitch/components/check_box';
|
import { CheckBox } from 'flavours/glitch/components/check_box';
|
||||||
|
@ -40,11 +40,11 @@ export const NotificationRequest = ({ id, accountId, notificationsCount, checked
|
||||||
const { push: historyPush } = useHistory();
|
const { push: historyPush } = useHistory();
|
||||||
|
|
||||||
const handleDismiss = useCallback(() => {
|
const handleDismiss = useCallback(() => {
|
||||||
dispatch(dismissNotificationRequest(id));
|
dispatch(dismissNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleAccept = useCallback(() => {
|
const handleAccept = useCallback(() => {
|
||||||
dispatch(acceptNotificationRequest(id));
|
dispatch(acceptNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleMute = useCallback(() => {
|
const handleMute = useCallback(() => {
|
||||||
|
|
|
@ -10,7 +10,13 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||||
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||||
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
|
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
|
||||||
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
||||||
import { fetchNotificationRequest, fetchNotificationsForRequest, expandNotificationsForRequest, acceptNotificationRequest, dismissNotificationRequest } from 'flavours/glitch/actions/notifications';
|
import {
|
||||||
|
fetchNotificationRequest,
|
||||||
|
fetchNotificationsForRequest,
|
||||||
|
expandNotificationsForRequest,
|
||||||
|
acceptNotificationRequest,
|
||||||
|
dismissNotificationRequest,
|
||||||
|
} from 'flavours/glitch/actions/notification_requests';
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
|
@ -44,28 +50,28 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||||
const columnRef = useRef();
|
const columnRef = useRef();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const notificationRequest = useSelector(state => state.getIn(['notificationRequests', 'current', 'item', 'id']) === id ? state.getIn(['notificationRequests', 'current', 'item']) : null);
|
const notificationRequest = useSelector(state => state.notificationRequests.current.item?.id === id ? state.notificationRequests.current.item : null);
|
||||||
const accountId = notificationRequest?.get('account');
|
const accountId = notificationRequest?.account_id;
|
||||||
const account = useSelector(state => state.getIn(['accounts', accountId]));
|
const account = useSelector(state => state.getIn(['accounts', accountId]));
|
||||||
const notifications = useSelector(state => state.getIn(['notificationRequests', 'current', 'notifications', 'items']));
|
const notifications = useSelector(state => state.notificationRequests.current.notifications.items);
|
||||||
const isLoading = useSelector(state => state.getIn(['notificationRequests', 'current', 'notifications', 'isLoading']));
|
const isLoading = useSelector(state => state.notificationRequests.current.notifications.isLoading);
|
||||||
const hasMore = useSelector(state => !!state.getIn(['notificationRequests', 'current', 'notifications', 'next']));
|
const hasMore = useSelector(state => !!state.notificationRequests.current.notifications.next);
|
||||||
const removed = useSelector(state => state.getIn(['notificationRequests', 'current', 'removed']));
|
const removed = useSelector(state => state.notificationRequests.current.removed);
|
||||||
|
|
||||||
const handleHeaderClick = useCallback(() => {
|
const handleHeaderClick = useCallback(() => {
|
||||||
columnRef.current?.scrollTop();
|
columnRef.current?.scrollTop();
|
||||||
}, [columnRef]);
|
}, [columnRef]);
|
||||||
|
|
||||||
const handleLoadMore = useCallback(() => {
|
const handleLoadMore = useCallback(() => {
|
||||||
dispatch(expandNotificationsForRequest());
|
dispatch(expandNotificationsForRequest({ accountId }));
|
||||||
}, [dispatch]);
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
const handleDismiss = useCallback(() => {
|
const handleDismiss = useCallback(() => {
|
||||||
dispatch(dismissNotificationRequest(id));
|
dispatch(dismissNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleAccept = useCallback(() => {
|
const handleAccept = useCallback(() => {
|
||||||
dispatch(acceptNotificationRequest(id));
|
dispatch(acceptNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleMoveUp = useCallback(id => {
|
const handleMoveUp = useCallback(id => {
|
||||||
|
@ -79,12 +85,12 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||||
}, [columnRef, notifications]);
|
}, [columnRef, notifications]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchNotificationRequest(id));
|
dispatch(fetchNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (accountId) {
|
if (accountId) {
|
||||||
dispatch(fetchNotificationsForRequest(accountId));
|
dispatch(fetchNotificationsForRequest({ accountId }));
|
||||||
}
|
}
|
||||||
}, [dispatch, accountId]);
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,12 @@ import ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?rea
|
||||||
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { openModal } from 'flavours/glitch/actions/modal';
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
import { fetchNotificationRequests, expandNotificationRequests, acceptNotificationRequests, dismissNotificationRequests } from 'flavours/glitch/actions/notifications';
|
import {
|
||||||
|
fetchNotificationRequests,
|
||||||
|
expandNotificationRequests,
|
||||||
|
acceptNotificationRequests,
|
||||||
|
dismissNotificationRequests,
|
||||||
|
} from 'flavours/glitch/actions/notification_requests';
|
||||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||||
import { CheckBox } from 'flavours/glitch/components/check_box';
|
import { CheckBox } from 'flavours/glitch/components/check_box';
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
|
@ -84,7 +89,7 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
|
||||||
message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }),
|
message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }),
|
||||||
confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}),
|
confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}),
|
||||||
onConfirm: () =>
|
onConfirm: () =>
|
||||||
dispatch(acceptNotificationRequests(selectedItems)),
|
dispatch(acceptNotificationRequests({ ids: selectedItems })),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [dispatch, intl, selectedItems]);
|
}, [dispatch, intl, selectedItems]);
|
||||||
|
@ -97,7 +102,7 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
|
||||||
message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }),
|
message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }),
|
||||||
confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}),
|
confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}),
|
||||||
onConfirm: () =>
|
onConfirm: () =>
|
||||||
dispatch(dismissNotificationRequests(selectedItems)),
|
dispatch(dismissNotificationRequests({ ids: selectedItems })),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [dispatch, intl, selectedItems]);
|
}, [dispatch, intl, selectedItems]);
|
||||||
|
@ -161,9 +166,9 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
const columnRef = useRef();
|
const columnRef = useRef();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isLoading = useSelector(state => state.getIn(['notificationRequests', 'isLoading']));
|
const isLoading = useSelector(state => state.notificationRequests.isLoading);
|
||||||
const notificationRequests = useSelector(state => state.getIn(['notificationRequests', 'items']));
|
const notificationRequests = useSelector(state => state.notificationRequests.items);
|
||||||
const hasMore = useSelector(state => !!state.getIn(['notificationRequests', 'next']));
|
const hasMore = useSelector(state => !!state.notificationRequests.next);
|
||||||
|
|
||||||
const [selectionMode, setSelectionMode] = useState(false);
|
const [selectionMode, setSelectionMode] = useState(false);
|
||||||
const [checkedRequestIds, setCheckedRequestIds] = useState([]);
|
const [checkedRequestIds, setCheckedRequestIds] = useState([]);
|
||||||
|
@ -182,7 +187,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
else
|
else
|
||||||
ids.push(id);
|
ids.push(id);
|
||||||
|
|
||||||
setSelectAllChecked(ids.length === notificationRequests.size);
|
setSelectAllChecked(ids.length === notificationRequests.length);
|
||||||
|
|
||||||
return [...ids];
|
return [...ids];
|
||||||
});
|
});
|
||||||
|
@ -193,7 +198,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
if(checked)
|
if(checked)
|
||||||
setCheckedRequestIds([]);
|
setCheckedRequestIds([]);
|
||||||
else
|
else
|
||||||
setCheckedRequestIds(notificationRequests.map(request => request.get('id')).toArray());
|
setCheckedRequestIds(notificationRequests.map(request => request.id));
|
||||||
|
|
||||||
return !checked;
|
return !checked;
|
||||||
});
|
});
|
||||||
|
@ -217,7 +222,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
multiColumn={multiColumn}
|
multiColumn={multiColumn}
|
||||||
showBackButton
|
showBackButton
|
||||||
appendContent={
|
appendContent={
|
||||||
notificationRequests.size > 0 && (
|
notificationRequests.length > 0 && (
|
||||||
<SelectRow selectionMode={selectionMode} setSelectionMode={setSelectionMode} selectAllChecked={selectAllChecked} toggleSelectAll={toggleSelectAll} selectedItems={checkedRequestIds} />
|
<SelectRow selectionMode={selectionMode} setSelectionMode={setSelectionMode} selectAllChecked={selectAllChecked} toggleSelectAll={toggleSelectAll} selectedItems={checkedRequestIds} />
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -236,12 +241,12 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
>
|
>
|
||||||
{notificationRequests.map(request => (
|
{notificationRequests.map(request => (
|
||||||
<NotificationRequest
|
<NotificationRequest
|
||||||
key={request.get('id')}
|
key={request.id}
|
||||||
id={request.get('id')}
|
id={request.id}
|
||||||
accountId={request.get('account')}
|
accountId={request.account_id}
|
||||||
notificationsCount={request.get('notifications_count')}
|
notificationsCount={request.notifications_count}
|
||||||
showCheckbox={selectionMode}
|
showCheckbox={selectionMode}
|
||||||
checked={checkedRequestIds.includes(request.get('id'))}
|
checked={checkedRequestIds.includes(request.id)}
|
||||||
toggleCheck={handleCheck}
|
toggleCheck={handleCheck}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import type { ApiNotificationRequestJSON } from 'flavours/glitch/api_types/notifications';
|
||||||
|
|
||||||
|
export interface NotificationRequest
|
||||||
|
extends Omit<ApiNotificationRequestJSON, 'account' | 'notifications_count'> {
|
||||||
|
account_id: string;
|
||||||
|
notifications_count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createNotificationRequestFromJSON(
|
||||||
|
requestJSON: ApiNotificationRequestJSON,
|
||||||
|
): NotificationRequest {
|
||||||
|
const { account, notifications_count, ...request } = requestJSON;
|
||||||
|
|
||||||
|
return {
|
||||||
|
account_id: account.id,
|
||||||
|
notifications_count: +notifications_count,
|
||||||
|
...request,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,114 +0,0 @@
|
||||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
|
||||||
|
|
||||||
import { blockAccountSuccess, muteAccountSuccess } from 'flavours/glitch/actions/accounts';
|
|
||||||
import {
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_SUCCESS,
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_FAIL,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_SUCCESS,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_FAIL,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_REQUEST,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_SUCCESS,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_FAIL,
|
|
||||||
NOTIFICATION_REQUEST_ACCEPT_REQUEST,
|
|
||||||
NOTIFICATION_REQUEST_DISMISS_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_ACCEPT_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_DISMISS_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL,
|
|
||||||
} from 'flavours/glitch/actions/notifications';
|
|
||||||
|
|
||||||
import { notificationToMap } from './notifications';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
|
||||||
items: ImmutableList(),
|
|
||||||
isLoading: false,
|
|
||||||
next: null,
|
|
||||||
current: ImmutableMap({
|
|
||||||
isLoading: false,
|
|
||||||
item: null,
|
|
||||||
removed: false,
|
|
||||||
notifications: ImmutableMap({
|
|
||||||
items: ImmutableList(),
|
|
||||||
isLoading: false,
|
|
||||||
next: null,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const normalizeRequest = request => fromJS({
|
|
||||||
...request,
|
|
||||||
account: request.account.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeRequest = (state, id) => {
|
|
||||||
if (state.getIn(['current', 'item', 'id']) === id) {
|
|
||||||
state = state.setIn(['current', 'removed'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.update('items', list => list.filterNot(item => item.get('id') === id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeRequestByAccount = (state, account_id) => {
|
|
||||||
if (state.getIn(['current', 'item', 'account']) === account_id) {
|
|
||||||
state = state.setIn(['current', 'removed'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.update('items', list => list.filterNot(item => item.get('account') === account_id));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const notificationRequestsReducer = (state = initialState, action) => {
|
|
||||||
switch(action.type) {
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_SUCCESS:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.update('items', list => ImmutableList(action.requests.map(normalizeRequest)).concat(list));
|
|
||||||
map.set('isLoading', false);
|
|
||||||
map.update('next', next => next ?? action.next);
|
|
||||||
});
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_SUCCESS:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.update('items', list => list.concat(ImmutableList(action.requests.map(normalizeRequest))));
|
|
||||||
map.set('isLoading', false);
|
|
||||||
map.set('next', action.next);
|
|
||||||
});
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_REQUEST:
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_REQUEST:
|
|
||||||
return state.set('isLoading', true);
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_FAIL:
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_FAIL:
|
|
||||||
return state.set('isLoading', false);
|
|
||||||
case NOTIFICATION_REQUEST_ACCEPT_REQUEST:
|
|
||||||
case NOTIFICATION_REQUEST_DISMISS_REQUEST:
|
|
||||||
return removeRequest(state, action.id);
|
|
||||||
case NOTIFICATION_REQUESTS_ACCEPT_REQUEST:
|
|
||||||
case NOTIFICATION_REQUESTS_DISMISS_REQUEST:
|
|
||||||
return action.ids.reduce((state, id) => removeRequest(state, id), state);
|
|
||||||
case blockAccountSuccess.type:
|
|
||||||
return removeRequestByAccount(state, action.payload.relationship.id);
|
|
||||||
case muteAccountSuccess.type:
|
|
||||||
return action.payload.relationship.muting_notifications ? removeRequestByAccount(state, action.payload.relationship.id) : state;
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_REQUEST:
|
|
||||||
return state.set('current', initialState.get('current').set('isLoading', true));
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_SUCCESS:
|
|
||||||
return state.update('current', map => map.set('isLoading', false).set('item', normalizeRequest(action.request)));
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_FAIL:
|
|
||||||
return state.update('current', map => map.set('isLoading', false));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST:
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST:
|
|
||||||
return state.setIn(['current', 'notifications', 'isLoading'], true);
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS:
|
|
||||||
return state.updateIn(['current', 'notifications'], map => map.set('isLoading', false).update('items', list => ImmutableList(action.notifications.map(notificationToMap)).concat(list)).update('next', next => next ?? action.next));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS:
|
|
||||||
return state.updateIn(['current', 'notifications'], map => map.set('isLoading', false).update('items', list => list.concat(ImmutableList(action.notifications.map(notificationToMap)))).set('next', action.next));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL:
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL:
|
|
||||||
return state.setIn(['current', 'notifications', 'isLoading'], false);
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
182
app/javascript/flavours/glitch/reducers/notification_requests.ts
Normal file
182
app/javascript/flavours/glitch/reducers/notification_requests.ts
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
import { createReducer, isAnyOf } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
import {
|
||||||
|
blockAccountSuccess,
|
||||||
|
muteAccountSuccess,
|
||||||
|
} from 'flavours/glitch/actions/accounts';
|
||||||
|
import {
|
||||||
|
fetchNotificationRequests,
|
||||||
|
expandNotificationRequests,
|
||||||
|
fetchNotificationRequest,
|
||||||
|
fetchNotificationsForRequest,
|
||||||
|
expandNotificationsForRequest,
|
||||||
|
acceptNotificationRequest,
|
||||||
|
dismissNotificationRequest,
|
||||||
|
acceptNotificationRequests,
|
||||||
|
dismissNotificationRequests,
|
||||||
|
} from 'flavours/glitch/actions/notification_requests';
|
||||||
|
import type { NotificationRequest } from 'flavours/glitch/models/notification_request';
|
||||||
|
import { createNotificationRequestFromJSON } from 'flavours/glitch/models/notification_request';
|
||||||
|
|
||||||
|
import { notificationToMap } from './notifications';
|
||||||
|
|
||||||
|
interface NotificationsListState {
|
||||||
|
items: unknown[]; // TODO
|
||||||
|
isLoading: boolean;
|
||||||
|
next: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CurrentNotificationRequestState {
|
||||||
|
item: NotificationRequest | null;
|
||||||
|
isLoading: boolean;
|
||||||
|
removed: boolean;
|
||||||
|
notifications: NotificationsListState;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NotificationRequestsState {
|
||||||
|
items: NotificationRequest[];
|
||||||
|
isLoading: boolean;
|
||||||
|
next: string | null;
|
||||||
|
current: CurrentNotificationRequestState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: NotificationRequestsState = {
|
||||||
|
items: [],
|
||||||
|
isLoading: false,
|
||||||
|
next: null,
|
||||||
|
current: {
|
||||||
|
item: null,
|
||||||
|
isLoading: false,
|
||||||
|
removed: false,
|
||||||
|
notifications: {
|
||||||
|
isLoading: false,
|
||||||
|
items: [],
|
||||||
|
next: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRequest = (state: NotificationRequestsState, id: string) => {
|
||||||
|
if (state.current.item?.id === id) {
|
||||||
|
state.current.removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.items = state.items.filter((item) => item.id !== id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRequestByAccount = (
|
||||||
|
state: NotificationRequestsState,
|
||||||
|
account_id: string,
|
||||||
|
) => {
|
||||||
|
if (state.current.item?.account_id === account_id) {
|
||||||
|
state.current.removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.items = state.items.filter((item) => item.account_id !== account_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const notificationRequestsReducer =
|
||||||
|
createReducer<NotificationRequestsState>(initialState, (builder) => {
|
||||||
|
builder
|
||||||
|
.addCase(fetchNotificationRequests.fulfilled, (state, action) => {
|
||||||
|
state.items = action.payload.requests
|
||||||
|
.map(createNotificationRequestFromJSON)
|
||||||
|
.concat(state.items);
|
||||||
|
state.isLoading = false;
|
||||||
|
state.next ??= action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(expandNotificationRequests.fulfilled, (state, action) => {
|
||||||
|
state.items = state.items.concat(
|
||||||
|
action.payload.requests.map(createNotificationRequestFromJSON),
|
||||||
|
);
|
||||||
|
state.isLoading = false;
|
||||||
|
state.next = action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(blockAccountSuccess, (state, action) => {
|
||||||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||||||
|
})
|
||||||
|
.addCase(muteAccountSuccess, (state, action) => {
|
||||||
|
if (action.payload.relationship.muting_notifications)
|
||||||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.pending, (state) => {
|
||||||
|
state.current = { ...initialState.current, isLoading: true };
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.rejected, (state) => {
|
||||||
|
state.current.isLoading = false;
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.isLoading = false;
|
||||||
|
state.current.item = createNotificationRequestFromJSON(action.payload);
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationsForRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
state.current.notifications.items.unshift(
|
||||||
|
...action.payload.notifications.map(notificationToMap),
|
||||||
|
);
|
||||||
|
state.current.notifications.next ??= action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(expandNotificationsForRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
state.current.notifications.items.push(
|
||||||
|
...action.payload.notifications.map(notificationToMap),
|
||||||
|
);
|
||||||
|
state.current.notifications.next = action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationRequests.pending,
|
||||||
|
expandNotificationRequests.pending,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.isLoading = true;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationRequests.rejected,
|
||||||
|
expandNotificationRequests.rejected,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.isLoading = false;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
acceptNotificationRequest.pending,
|
||||||
|
dismissNotificationRequest.pending,
|
||||||
|
),
|
||||||
|
(state, action) => {
|
||||||
|
removeRequest(state, action.meta.arg.id);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
acceptNotificationRequests.pending,
|
||||||
|
dismissNotificationRequests.pending,
|
||||||
|
),
|
||||||
|
(state, action) => {
|
||||||
|
action.meta.arg.ids.forEach((id) => {
|
||||||
|
removeRequest(state, id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationsForRequest.pending,
|
||||||
|
expandNotificationsForRequest.pending,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.current.notifications.isLoading = true;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationsForRequest.rejected,
|
||||||
|
expandNotificationsForRequest.rejected,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
|
@ -55,11 +55,11 @@ const initialState = ImmutableMap({
|
||||||
markNewForDelete: false,
|
markNewForDelete: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const notificationToMap = (notification, markForDelete = false) => ImmutableMap({
|
export const notificationToMap = (notification) => ImmutableMap({
|
||||||
id: notification.id,
|
id: notification.id,
|
||||||
type: notification.type,
|
type: notification.type,
|
||||||
account: notification.account.id,
|
account: notification.account.id,
|
||||||
markedForDelete: markForDelete,
|
markedForDelete: false,
|
||||||
status: notification.status ? notification.status.id : null,
|
status: notification.status ? notification.status.id : null,
|
||||||
report: notification.report ? fromJS(notification.report) : null,
|
report: notification.report ? fromJS(notification.report) : null,
|
||||||
event: notification.event ? fromJS(notification.event) : null,
|
event: notification.event ? fromJS(notification.event) : null,
|
||||||
|
@ -76,7 +76,7 @@ const normalizeNotification = (state, notification, usePendingItems) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usePendingItems || !state.get('pendingItems').isEmpty()) {
|
if (usePendingItems || !state.get('pendingItems').isEmpty()) {
|
||||||
return state.update('pendingItems', list => list.unshift(notificationToMap(notification, markNewForDelete))).update('unread', unread => unread + 1);
|
return state.update('pendingItems', list => list.unshift(notificationToMap(notification).set('markForDelete', markNewForDelete))).update('unread', unread => unread + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCountUnreadNotifications(state)) {
|
if (shouldCountUnreadNotifications(state)) {
|
||||||
|
@ -90,7 +90,7 @@ const normalizeNotification = (state, notification, usePendingItems) => {
|
||||||
list = list.take(20);
|
list = list.take(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.unshift(notificationToMap(notification, markNewForDelete));
|
return list.unshift(notificationToMap(notification).set('markForDelete', markNewForDelete));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingMore
|
||||||
|
|
||||||
const markNewForDelete = state.get('markNewForDelete');
|
const markNewForDelete = state.get('markNewForDelete');
|
||||||
const lastReadId = state.get('lastReadId');
|
const lastReadId = state.get('lastReadId');
|
||||||
const newItems = ImmutableList(notifications.map((notification) => notificationToMap(notification, markNewForDelete)));
|
const newItems = ImmutableList(notifications.map((notification) => notificationToMap(notification).set('markForDelete', markNewForDelete)));
|
||||||
|
|
||||||
return state.withMutations(mutable => {
|
return state.withMutations(mutable => {
|
||||||
if (!newItems.isEmpty()) {
|
if (!newItems.isEmpty()) {
|
||||||
|
|
|
@ -33,8 +33,12 @@ interface AppThunkConfig {
|
||||||
}
|
}
|
||||||
type AppThunkApi = Pick<GetThunkAPI<AppThunkConfig>, 'getState' | 'dispatch'>;
|
type AppThunkApi = Pick<GetThunkAPI<AppThunkConfig>, 'getState' | 'dispatch'>;
|
||||||
|
|
||||||
interface AppThunkOptions {
|
interface AppThunkOptions<Arg> {
|
||||||
useLoadingBar?: boolean;
|
useLoadingBar?: boolean;
|
||||||
|
condition?: (
|
||||||
|
arg: Arg,
|
||||||
|
{ getState }: { getState: AppThunkApi['getState'] },
|
||||||
|
) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
||||||
|
@ -42,7 +46,7 @@ const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
||||||
export function createThunk<Arg = void, Returned = void>(
|
export function createThunk<Arg = void, Returned = void>(
|
||||||
name: string,
|
name: string,
|
||||||
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
||||||
options: AppThunkOptions = {},
|
options: AppThunkOptions<Arg> = {},
|
||||||
) {
|
) {
|
||||||
return createBaseAsyncThunk(
|
return createBaseAsyncThunk(
|
||||||
name,
|
name,
|
||||||
|
@ -70,6 +74,7 @@ export function createThunk<Arg = void, Returned = void>(
|
||||||
if (options.useLoadingBar) return { useLoadingBar: true };
|
if (options.useLoadingBar) return { useLoadingBar: true };
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
condition: options.condition,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +101,7 @@ type ArgsType = Record<string, unknown> | undefined;
|
||||||
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||||
|
|
||||||
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
||||||
|
@ -104,17 +109,19 @@ export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, DiscardLoadData>,
|
| OnData<Args, LoadDataResult, DiscardLoadData>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, void>>;
|
): ReturnType<typeof createThunk<Args, void>>;
|
||||||
|
|
||||||
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
||||||
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?: AppThunkOptions | OnData<Args, LoadDataResult, void>,
|
onDataOrThunkOptions?:
|
||||||
thunkOptions?: AppThunkOptions,
|
| AppThunkOptions<Args>
|
||||||
|
| OnData<Args, LoadDataResult, void>,
|
||||||
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||||
|
|
||||||
// Overload when there is an `onData` method returning something
|
// Overload when there is an `onData` method returning something
|
||||||
|
@ -126,9 +133,9 @@ export function createDataLoadingThunk<
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, Returned>,
|
| OnData<Args, LoadDataResult, Returned>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, Returned>>;
|
): ReturnType<typeof createThunk<Args, Returned>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,6 +161,7 @@ export function createDataLoadingThunk<
|
||||||
* @param maybeThunkOptions
|
* @param maybeThunkOptions
|
||||||
* Additional Mastodon specific options for the thunk. Currently supports:
|
* Additional Mastodon specific options for the thunk. Currently supports:
|
||||||
* - `useLoadingBar` to display a loading bar while this action is pending. Defaults to true.
|
* - `useLoadingBar` to display a loading bar while this action is pending. Defaults to true.
|
||||||
|
* - `condition` is passed to `createAsyncThunk` (https://redux-toolkit.js.org/api/createAsyncThunk#canceling-before-execution)
|
||||||
* @returns The created thunk
|
* @returns The created thunk
|
||||||
*/
|
*/
|
||||||
export function createDataLoadingThunk<
|
export function createDataLoadingThunk<
|
||||||
|
@ -164,12 +172,12 @@ export function createDataLoadingThunk<
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, Returned>,
|
| OnData<Args, LoadDataResult, Returned>,
|
||||||
maybeThunkOptions?: AppThunkOptions,
|
maybeThunkOptions?: AppThunkOptions<Args>,
|
||||||
) {
|
) {
|
||||||
let onData: OnData<Args, LoadDataResult, Returned> | undefined;
|
let onData: OnData<Args, LoadDataResult, Returned> | undefined;
|
||||||
let thunkOptions: AppThunkOptions | undefined;
|
let thunkOptions: AppThunkOptions<Args> | undefined;
|
||||||
|
|
||||||
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
||||||
else if (typeof onDataOrThunkOptions === 'object')
|
else if (typeof onDataOrThunkOptions === 'object')
|
||||||
|
@ -203,6 +211,9 @@ export function createDataLoadingThunk<
|
||||||
return undefined as Returned;
|
return undefined as Returned;
|
||||||
else return result;
|
else return result;
|
||||||
},
|
},
|
||||||
{ useLoadingBar: thunkOptions?.useLoadingBar ?? true },
|
{
|
||||||
|
useLoadingBar: thunkOptions?.useLoadingBar ?? true,
|
||||||
|
condition: thunkOptions?.condition,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10761,6 +10761,7 @@ noscript {
|
||||||
scroll-padding: 16px;
|
scroll-padding: 16px;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
&__card {
|
&__card {
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { createAction } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
apiClearNotifications,
|
apiClearNotifications,
|
||||||
apiFetchNotifications,
|
apiFetchNotificationGroups,
|
||||||
} from 'mastodon/api/notifications';
|
} from 'mastodon/api/notifications';
|
||||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||||
import type {
|
import type {
|
||||||
|
@ -71,7 +71,7 @@ function dispatchAssociatedRecords(
|
||||||
export const fetchNotifications = createDataLoadingThunk(
|
export const fetchNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/fetch',
|
'notificationGroups/fetch',
|
||||||
async (_params, { getState }) =>
|
async (_params, { getState }) =>
|
||||||
apiFetchNotifications({ exclude_types: getExcludedTypes(getState()) }),
|
apiFetchNotificationGroups({ exclude_types: getExcludedTypes(getState()) }),
|
||||||
({ notifications, accounts, statuses }, { dispatch }) => {
|
({ notifications, accounts, statuses }, { dispatch }) => {
|
||||||
dispatch(importFetchedAccounts(accounts));
|
dispatch(importFetchedAccounts(accounts));
|
||||||
dispatch(importFetchedStatuses(statuses));
|
dispatch(importFetchedStatuses(statuses));
|
||||||
|
@ -92,7 +92,7 @@ export const fetchNotifications = createDataLoadingThunk(
|
||||||
export const fetchNotificationsGap = createDataLoadingThunk(
|
export const fetchNotificationsGap = createDataLoadingThunk(
|
||||||
'notificationGroups/fetchGap',
|
'notificationGroups/fetchGap',
|
||||||
async (params: { gap: NotificationGap }, { getState }) =>
|
async (params: { gap: NotificationGap }, { getState }) =>
|
||||||
apiFetchNotifications({
|
apiFetchNotificationGroups({
|
||||||
max_id: params.gap.maxId,
|
max_id: params.gap.maxId,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
}),
|
}),
|
||||||
|
@ -108,7 +108,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
||||||
export const pollRecentNotifications = createDataLoadingThunk(
|
export const pollRecentNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/pollRecentNotifications',
|
'notificationGroups/pollRecentNotifications',
|
||||||
async (_params, { getState }) => {
|
async (_params, { getState }) => {
|
||||||
return apiFetchNotifications({
|
return apiFetchNotificationGroups({
|
||||||
max_id: undefined,
|
max_id: undefined,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
||||||
|
|
234
app/javascript/mastodon/actions/notification_requests.ts
Normal file
234
app/javascript/mastodon/actions/notification_requests.ts
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
import {
|
||||||
|
apiFetchNotificationRequest,
|
||||||
|
apiFetchNotificationRequests,
|
||||||
|
apiFetchNotifications,
|
||||||
|
apiAcceptNotificationRequest,
|
||||||
|
apiDismissNotificationRequest,
|
||||||
|
apiAcceptNotificationRequests,
|
||||||
|
apiDismissNotificationRequests,
|
||||||
|
} from 'mastodon/api/notifications';
|
||||||
|
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||||
|
import type {
|
||||||
|
ApiNotificationGroupJSON,
|
||||||
|
ApiNotificationJSON,
|
||||||
|
} from 'mastodon/api_types/notifications';
|
||||||
|
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
|
||||||
|
import type { AppDispatch, RootState } from 'mastodon/store';
|
||||||
|
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
|
||||||
|
|
||||||
|
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||||
|
import { decreasePendingNotificationsCount } from './notification_policies';
|
||||||
|
|
||||||
|
// TODO: refactor with notification_groups
|
||||||
|
function dispatchAssociatedRecords(
|
||||||
|
dispatch: AppDispatch,
|
||||||
|
notifications: ApiNotificationGroupJSON[] | ApiNotificationJSON[],
|
||||||
|
) {
|
||||||
|
const fetchedAccounts: ApiAccountJSON[] = [];
|
||||||
|
const fetchedStatuses: ApiStatusJSON[] = [];
|
||||||
|
|
||||||
|
notifications.forEach((notification) => {
|
||||||
|
if (notification.type === 'admin.report') {
|
||||||
|
fetchedAccounts.push(notification.report.target_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.type === 'moderation_warning') {
|
||||||
|
fetchedAccounts.push(notification.moderation_warning.target_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('status' in notification && notification.status) {
|
||||||
|
fetchedStatuses.push(notification.status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchedAccounts.length > 0)
|
||||||
|
dispatch(importFetchedAccounts(fetchedAccounts));
|
||||||
|
|
||||||
|
if (fetchedStatuses.length > 0)
|
||||||
|
dispatch(importFetchedStatuses(fetchedStatuses));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/fetch',
|
||||||
|
async (_params, { getState }) => {
|
||||||
|
let sinceId = undefined;
|
||||||
|
|
||||||
|
if (getState().notificationRequests.items.length > 0) {
|
||||||
|
sinceId = getState().notificationRequests.items[0]?.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiFetchNotificationRequests({
|
||||||
|
since_id: sinceId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
({ requests, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(requests.map((request) => request.account)));
|
||||||
|
|
||||||
|
return { requests, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: (_params, { getState }) =>
|
||||||
|
!getState().notificationRequests.isLoading,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fetchNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/fetch',
|
||||||
|
async ({ id }: { id: string }) => apiFetchNotificationRequest(id),
|
||||||
|
{
|
||||||
|
condition: ({ id }, { getState }) =>
|
||||||
|
!(
|
||||||
|
getState().notificationRequests.current.item?.id === id ||
|
||||||
|
getState().notificationRequests.current.isLoading
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const expandNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/expand',
|
||||||
|
async (_, { getState }) => {
|
||||||
|
const nextUrl = getState().notificationRequests.next;
|
||||||
|
if (!nextUrl) throw new Error('missing URL');
|
||||||
|
|
||||||
|
return apiFetchNotificationRequests(undefined, nextUrl);
|
||||||
|
},
|
||||||
|
({ requests, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(requests.map((request) => request.account)));
|
||||||
|
|
||||||
|
return { requests, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: (_, { getState }) =>
|
||||||
|
!!getState().notificationRequests.next &&
|
||||||
|
!getState().notificationRequests.isLoading,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fetchNotificationsForRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/fetchNotifications',
|
||||||
|
async ({ accountId }: { accountId: string }, { getState }) => {
|
||||||
|
const sinceId =
|
||||||
|
// @ts-expect-error current.notifications.items is not yet typed
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
|
getState().notificationRequests.current.notifications.items[0]?.get(
|
||||||
|
'id',
|
||||||
|
) as string | undefined;
|
||||||
|
|
||||||
|
return apiFetchNotifications({
|
||||||
|
since_id: sinceId,
|
||||||
|
account_id: accountId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
({ notifications, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatchAssociatedRecords(dispatch, notifications);
|
||||||
|
|
||||||
|
return { notifications, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ({ accountId }, { getState }) => {
|
||||||
|
const current = getState().notificationRequests.current;
|
||||||
|
return !(
|
||||||
|
current.item?.account_id === accountId &&
|
||||||
|
current.notifications.isLoading
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const expandNotificationsForRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/expandNotifications',
|
||||||
|
async (_, { getState }) => {
|
||||||
|
const nextUrl = getState().notificationRequests.current.notifications.next;
|
||||||
|
if (!nextUrl) throw new Error('missing URL');
|
||||||
|
|
||||||
|
return apiFetchNotifications(undefined, nextUrl);
|
||||||
|
},
|
||||||
|
({ notifications, links }, { dispatch }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatchAssociatedRecords(dispatch, notifications);
|
||||||
|
|
||||||
|
return { notifications, next: next?.uri };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ({ accountId }: { accountId: string }, { getState }) => {
|
||||||
|
const url = getState().notificationRequests.current.notifications.next;
|
||||||
|
|
||||||
|
return (
|
||||||
|
!!url &&
|
||||||
|
!getState().notificationRequests.current.notifications.isLoading &&
|
||||||
|
getState().notificationRequests.current.item?.account_id === accountId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectNotificationCountForRequest = (state: RootState, id: string) => {
|
||||||
|
const requests = state.notificationRequests.items;
|
||||||
|
const thisRequest = requests.find((request) => request.id === id);
|
||||||
|
return thisRequest ? thisRequest.notifications_count : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const acceptNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/accept',
|
||||||
|
({ id }: { id: string }) => apiAcceptNotificationRequest(id),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { id } }) => {
|
||||||
|
const count = selectNotificationCountForRequest(getState(), id);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const dismissNotificationRequest = createDataLoadingThunk(
|
||||||
|
'notificationRequest/dismiss',
|
||||||
|
({ id }: { id: string }) => apiDismissNotificationRequest(id),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { id } }) => {
|
||||||
|
const count = selectNotificationCountForRequest(getState(), id);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const acceptNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/acceptBulk',
|
||||||
|
({ ids }: { ids: string[] }) => apiAcceptNotificationRequests(ids),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { ids } }) => {
|
||||||
|
const count = ids.reduce(
|
||||||
|
(count, id) => count + selectNotificationCountForRequest(getState(), id),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const dismissNotificationRequests = createDataLoadingThunk(
|
||||||
|
'notificationRequests/dismissBulk',
|
||||||
|
({ ids }: { ids: string[] }) => apiDismissNotificationRequests(ids),
|
||||||
|
(_data, { dispatch, getState, discardLoadData, actionArg: { ids } }) => {
|
||||||
|
const count = ids.reduce(
|
||||||
|
(count, id) => count + selectNotificationCountForRequest(getState(), id),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(decreasePendingNotificationsCount(count));
|
||||||
|
|
||||||
|
// The payload is not used in any functions
|
||||||
|
return discardLoadData;
|
||||||
|
},
|
||||||
|
);
|
|
@ -18,7 +18,6 @@ import {
|
||||||
importFetchedStatuses,
|
importFetchedStatuses,
|
||||||
} from './importer';
|
} from './importer';
|
||||||
import { submitMarkers } from './markers';
|
import { submitMarkers } from './markers';
|
||||||
import { decreasePendingNotificationsCount } from './notification_policies';
|
|
||||||
import { notificationsUpdate } from "./notifications_typed";
|
import { notificationsUpdate } from "./notifications_typed";
|
||||||
import { register as registerPushNotifications } from './push_notifications';
|
import { register as registerPushNotifications } from './push_notifications';
|
||||||
import { saveSettings } from './settings';
|
import { saveSettings } from './settings';
|
||||||
|
@ -44,26 +43,6 @@ export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
||||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_REQUEST = 'NOTIFICATION_REQUESTS_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_SUCCESS = 'NOTIFICATION_REQUESTS_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUESTS_FETCH_FAIL = 'NOTIFICATION_REQUESTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_REQUEST = 'NOTIFICATION_REQUESTS_EXPAND_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_SUCCESS = 'NOTIFICATION_REQUESTS_EXPAND_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUESTS_EXPAND_FAIL = 'NOTIFICATION_REQUESTS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_REQUEST = 'NOTIFICATION_REQUEST_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_SUCCESS = 'NOTIFICATION_REQUEST_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_FETCH_FAIL = 'NOTIFICATION_REQUEST_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_REQUEST = 'NOTIFICATION_REQUEST_ACCEPT_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_SUCCESS = 'NOTIFICATION_REQUEST_ACCEPT_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_ACCEPT_FAIL = 'NOTIFICATION_REQUEST_ACCEPT_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_REQUEST = 'NOTIFICATION_REQUEST_DISMISS_REQUEST';
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_SUCCESS = 'NOTIFICATION_REQUEST_DISMISS_SUCCESS';
|
|
||||||
export const NOTIFICATION_REQUEST_DISMISS_FAIL = 'NOTIFICATION_REQUEST_DISMISS_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_REQUEST = 'NOTIFICATION_REQUESTS_ACCEPT_REQUEST';
|
export const NOTIFICATION_REQUESTS_ACCEPT_REQUEST = 'NOTIFICATION_REQUESTS_ACCEPT_REQUEST';
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_SUCCESS = 'NOTIFICATION_REQUESTS_ACCEPT_SUCCESS';
|
export const NOTIFICATION_REQUESTS_ACCEPT_SUCCESS = 'NOTIFICATION_REQUESTS_ACCEPT_SUCCESS';
|
||||||
export const NOTIFICATION_REQUESTS_ACCEPT_FAIL = 'NOTIFICATION_REQUESTS_ACCEPT_FAIL';
|
export const NOTIFICATION_REQUESTS_ACCEPT_FAIL = 'NOTIFICATION_REQUESTS_ACCEPT_FAIL';
|
||||||
|
@ -72,14 +51,6 @@ export const NOTIFICATION_REQUESTS_DISMISS_REQUEST = 'NOTIFICATION_REQUESTS_DISM
|
||||||
export const NOTIFICATION_REQUESTS_DISMISS_SUCCESS = 'NOTIFICATION_REQUESTS_DISMISS_SUCCESS';
|
export const NOTIFICATION_REQUESTS_DISMISS_SUCCESS = 'NOTIFICATION_REQUESTS_DISMISS_SUCCESS';
|
||||||
export const NOTIFICATION_REQUESTS_DISMISS_FAIL = 'NOTIFICATION_REQUESTS_DISMISS_FAIL';
|
export const NOTIFICATION_REQUESTS_DISMISS_FAIL = 'NOTIFICATION_REQUESTS_DISMISS_FAIL';
|
||||||
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST = 'NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS = 'NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL = 'NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS';
|
|
||||||
export const NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL = 'NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL';
|
|
||||||
|
|
||||||
defineMessages({
|
defineMessages({
|
||||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||||
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
||||||
|
@ -93,12 +64,6 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectNotificationCountForRequest = (state, id) => {
|
|
||||||
const requests = state.getIn(['notificationRequests', 'items']);
|
|
||||||
const thisRequest = requests.find(request => request.get('id') === id);
|
|
||||||
return thisRequest ? thisRequest.get('notifications_count') : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const loadPending = () => ({
|
export const loadPending = () => ({
|
||||||
type: NOTIFICATIONS_LOAD_PENDING,
|
type: NOTIFICATIONS_LOAD_PENDING,
|
||||||
});
|
});
|
||||||
|
@ -343,296 +308,3 @@ export function setBrowserPermission (value) {
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchNotificationRequests = () => (dispatch, getState) => {
|
|
||||||
const params = {};
|
|
||||||
|
|
||||||
if (getState().getIn(['notificationRequests', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getState().getIn(['notificationRequests', 'items'])?.size > 0) {
|
|
||||||
params.since_id = getState().getIn(['notificationRequests', 'items', 0, 'id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationRequestsRequest());
|
|
||||||
|
|
||||||
api().get('/api/v1/notifications/requests', { params }).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
|
||||||
dispatch(fetchNotificationRequestsSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationRequestsFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsRequest = () => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsSuccess = (requests, next) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_SUCCESS,
|
|
||||||
requests,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestsFail = error => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequests = () => (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['notificationRequests', 'next']);
|
|
||||||
|
|
||||||
if (!url || getState().getIn(['notificationRequests', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandNotificationRequestsRequest());
|
|
||||||
|
|
||||||
api().get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
|
||||||
dispatch(expandNotificationRequestsSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandNotificationRequestsFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandNotificationRequestsRequest = () => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequestsSuccess = (requests, next) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_SUCCESS,
|
|
||||||
requests,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationRequestsFail = error => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequest = id => (dispatch, getState) => {
|
|
||||||
const current = getState().getIn(['notificationRequests', 'current']);
|
|
||||||
|
|
||||||
if (current.getIn(['item', 'id']) === id || current.get('isLoading')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().get(`/api/v1/notifications/requests/${id}`).then(({ data }) => {
|
|
||||||
dispatch(fetchNotificationRequestSuccess(data));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestSuccess = request => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_SUCCESS,
|
|
||||||
request,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequest = (id) => (dispatch, getState) => {
|
|
||||||
const count = selectNotificationCountForRequest(getState(), id);
|
|
||||||
dispatch(acceptNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/${id}/accept`).then(() => {
|
|
||||||
dispatch(acceptNotificationRequestSuccess(id));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(acceptNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const acceptNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestSuccess = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_SUCCESS,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_ACCEPT_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequest = (id) => (dispatch, getState) => {
|
|
||||||
const count = selectNotificationCountForRequest(getState(), id);
|
|
||||||
dispatch(dismissNotificationRequestRequest(id));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{
|
|
||||||
dispatch(dismissNotificationRequestSuccess(id));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(dismissNotificationRequestFail(id, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dismissNotificationRequestRequest = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestSuccess = id => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_SUCCESS,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestFail = (id, error) => ({
|
|
||||||
type: NOTIFICATION_REQUEST_DISMISS_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequests = (ids) => (dispatch, getState) => {
|
|
||||||
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
|
|
||||||
dispatch(acceptNotificationRequestsRequest(ids));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/accept`, { id: ids }).then(() => {
|
|
||||||
dispatch(acceptNotificationRequestsSuccess(ids));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(acceptNotificationRequestFail(ids, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsRequest = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_REQUEST,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsSuccess = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_SUCCESS,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const acceptNotificationRequestsFail = (ids, error) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_ACCEPT_FAIL,
|
|
||||||
ids,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequests = (ids) => (dispatch, getState) => {
|
|
||||||
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
|
|
||||||
dispatch(acceptNotificationRequestsRequest(ids));
|
|
||||||
|
|
||||||
api().post(`/api/v1/notifications/requests/dismiss`, { id: ids }).then(() => {
|
|
||||||
dispatch(dismissNotificationRequestsSuccess(ids));
|
|
||||||
dispatch(decreasePendingNotificationsCount(count));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(dismissNotificationRequestFail(ids, err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsRequest = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_REQUEST,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsSuccess = ids => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_SUCCESS,
|
|
||||||
ids,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dismissNotificationRequestsFail = (ids, error) => ({
|
|
||||||
type: NOTIFICATION_REQUESTS_DISMISS_FAIL,
|
|
||||||
ids,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequest = accountId => (dispatch, getState) => {
|
|
||||||
const current = getState().getIn(['notificationRequests', 'current']);
|
|
||||||
const params = { account_id: accountId };
|
|
||||||
|
|
||||||
if (current.getIn(['item', 'account']) === accountId) {
|
|
||||||
if (current.getIn(['notifications', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.getIn(['notifications', 'items'])?.size > 0) {
|
|
||||||
params.since_id = current.getIn(['notifications', 'items', 0, 'id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchNotificationsForRequestRequest());
|
|
||||||
|
|
||||||
api().get('/api/v1/notifications', { params }).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
|
||||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
|
||||||
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));
|
|
||||||
|
|
||||||
dispatch(fetchNotificationsForRequestSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchNotificationsForRequestFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestRequest = () => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestSuccess = (notifications, next) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS,
|
|
||||||
notifications,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchNotificationsForRequestFail = (error) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequest = () => (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['notificationRequests', 'current', 'notifications', 'next']);
|
|
||||||
|
|
||||||
if (!url || getState().getIn(['notificationRequests', 'current', 'notifications', 'isLoading'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandNotificationsForRequestRequest());
|
|
||||||
|
|
||||||
api().get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
|
||||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
|
||||||
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));
|
|
||||||
|
|
||||||
dispatch(expandNotificationsForRequestSuccess(response.data, next?.uri));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandNotificationsForRequestFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestRequest = () => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestSuccess = (notifications, next) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS,
|
|
||||||
notifications,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expandNotificationsForRequestFail = (error) => ({
|
|
||||||
type: NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,14 +1,43 @@
|
||||||
import api, { apiRequest, getLinks } from 'mastodon/api';
|
import api, {
|
||||||
import type { ApiNotificationGroupsResultJSON } from 'mastodon/api_types/notifications';
|
apiRequest,
|
||||||
|
getLinks,
|
||||||
|
apiRequestGet,
|
||||||
|
apiRequestPost,
|
||||||
|
} from 'mastodon/api';
|
||||||
|
import type {
|
||||||
|
ApiNotificationGroupsResultJSON,
|
||||||
|
ApiNotificationRequestJSON,
|
||||||
|
ApiNotificationJSON,
|
||||||
|
} from 'mastodon/api_types/notifications';
|
||||||
|
|
||||||
export const apiFetchNotifications = async (params?: {
|
export const apiFetchNotifications = async (
|
||||||
|
params?: {
|
||||||
|
account_id?: string;
|
||||||
|
since_id?: string;
|
||||||
|
},
|
||||||
|
url?: string,
|
||||||
|
) => {
|
||||||
|
const response = await api().request<ApiNotificationJSON[]>({
|
||||||
|
method: 'GET',
|
||||||
|
url: url ?? '/api/v1/notifications',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
notifications: response.data,
|
||||||
|
links: getLinks(response),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiFetchNotificationGroups = async (params?: {
|
||||||
|
url?: string;
|
||||||
exclude_types?: string[];
|
exclude_types?: string[];
|
||||||
max_id?: string;
|
max_id?: string;
|
||||||
since_id?: string;
|
since_id?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const response = await api().request<ApiNotificationGroupsResultJSON>({
|
const response = await api().request<ApiNotificationGroupsResultJSON>({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/v2_alpha/notifications',
|
url: '/api/v2/notifications',
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,3 +53,43 @@ export const apiFetchNotifications = async (params?: {
|
||||||
|
|
||||||
export const apiClearNotifications = () =>
|
export const apiClearNotifications = () =>
|
||||||
apiRequest<undefined>('POST', 'v1/notifications/clear');
|
apiRequest<undefined>('POST', 'v1/notifications/clear');
|
||||||
|
|
||||||
|
export const apiFetchNotificationRequests = async (
|
||||||
|
params?: {
|
||||||
|
since_id?: string;
|
||||||
|
},
|
||||||
|
url?: string,
|
||||||
|
) => {
|
||||||
|
const response = await api().request<ApiNotificationRequestJSON[]>({
|
||||||
|
method: 'GET',
|
||||||
|
url: url ?? '/api/v1/notifications/requests',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
requests: response.data,
|
||||||
|
links: getLinks(response),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiFetchNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestGet<ApiNotificationRequestJSON>(
|
||||||
|
`v1/notifications/requests/${id}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiAcceptNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestPost(`v1/notifications/requests/${id}/accept`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiDismissNotificationRequest = async (id: string) => {
|
||||||
|
return apiRequestPost(`v1/notifications/requests/${id}/dismiss`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiAcceptNotificationRequests = async (id: string[]) => {
|
||||||
|
return apiRequestPost('v1/notifications/requests/accept', { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiDismissNotificationRequests = async (id: string[]) => {
|
||||||
|
return apiRequestPost('v1/notifications/dismiss/dismiss', { id });
|
||||||
|
};
|
||||||
|
|
|
@ -149,3 +149,12 @@ export interface ApiNotificationGroupsResultJSON {
|
||||||
statuses: ApiStatusJSON[];
|
statuses: ApiStatusJSON[];
|
||||||
notification_groups: ApiNotificationGroupJSON[];
|
notification_groups: ApiNotificationGroupJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiNotificationRequestJSON {
|
||||||
|
id: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
notifications_count: string;
|
||||||
|
account: ApiAccountJSON;
|
||||||
|
last_status?: ApiStatusJSON;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { initBlockModal } from 'mastodon/actions/blocks';
|
import { initBlockModal } from 'mastodon/actions/blocks';
|
||||||
import { initMuteModal } from 'mastodon/actions/mutes';
|
import { initMuteModal } from 'mastodon/actions/mutes';
|
||||||
import { acceptNotificationRequest, dismissNotificationRequest } from 'mastodon/actions/notifications';
|
import { acceptNotificationRequest, dismissNotificationRequest } from 'mastodon/actions/notification_requests';
|
||||||
import { initReport } from 'mastodon/actions/reports';
|
import { initReport } from 'mastodon/actions/reports';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import { CheckBox } from 'mastodon/components/check_box';
|
import { CheckBox } from 'mastodon/components/check_box';
|
||||||
|
@ -40,11 +40,11 @@ export const NotificationRequest = ({ id, accountId, notificationsCount, checked
|
||||||
const { push: historyPush } = useHistory();
|
const { push: historyPush } = useHistory();
|
||||||
|
|
||||||
const handleDismiss = useCallback(() => {
|
const handleDismiss = useCallback(() => {
|
||||||
dispatch(dismissNotificationRequest(id));
|
dispatch(dismissNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleAccept = useCallback(() => {
|
const handleAccept = useCallback(() => {
|
||||||
dispatch(acceptNotificationRequest(id));
|
dispatch(acceptNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleMute = useCallback(() => {
|
const handleMute = useCallback(() => {
|
||||||
|
|
|
@ -10,7 +10,13 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||||
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||||
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
|
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
|
||||||
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
||||||
import { fetchNotificationRequest, fetchNotificationsForRequest, expandNotificationsForRequest, acceptNotificationRequest, dismissNotificationRequest } from 'mastodon/actions/notifications';
|
import {
|
||||||
|
fetchNotificationRequest,
|
||||||
|
fetchNotificationsForRequest,
|
||||||
|
expandNotificationsForRequest,
|
||||||
|
acceptNotificationRequest,
|
||||||
|
dismissNotificationRequest,
|
||||||
|
} from 'mastodon/actions/notification_requests';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
|
@ -44,28 +50,28 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||||
const columnRef = useRef();
|
const columnRef = useRef();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const notificationRequest = useSelector(state => state.getIn(['notificationRequests', 'current', 'item', 'id']) === id ? state.getIn(['notificationRequests', 'current', 'item']) : null);
|
const notificationRequest = useSelector(state => state.notificationRequests.current.item?.id === id ? state.notificationRequests.current.item : null);
|
||||||
const accountId = notificationRequest?.get('account');
|
const accountId = notificationRequest?.account_id;
|
||||||
const account = useSelector(state => state.getIn(['accounts', accountId]));
|
const account = useSelector(state => state.getIn(['accounts', accountId]));
|
||||||
const notifications = useSelector(state => state.getIn(['notificationRequests', 'current', 'notifications', 'items']));
|
const notifications = useSelector(state => state.notificationRequests.current.notifications.items);
|
||||||
const isLoading = useSelector(state => state.getIn(['notificationRequests', 'current', 'notifications', 'isLoading']));
|
const isLoading = useSelector(state => state.notificationRequests.current.notifications.isLoading);
|
||||||
const hasMore = useSelector(state => !!state.getIn(['notificationRequests', 'current', 'notifications', 'next']));
|
const hasMore = useSelector(state => !!state.notificationRequests.current.notifications.next);
|
||||||
const removed = useSelector(state => state.getIn(['notificationRequests', 'current', 'removed']));
|
const removed = useSelector(state => state.notificationRequests.current.removed);
|
||||||
|
|
||||||
const handleHeaderClick = useCallback(() => {
|
const handleHeaderClick = useCallback(() => {
|
||||||
columnRef.current?.scrollTop();
|
columnRef.current?.scrollTop();
|
||||||
}, [columnRef]);
|
}, [columnRef]);
|
||||||
|
|
||||||
const handleLoadMore = useCallback(() => {
|
const handleLoadMore = useCallback(() => {
|
||||||
dispatch(expandNotificationsForRequest());
|
dispatch(expandNotificationsForRequest({ accountId }));
|
||||||
}, [dispatch]);
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
const handleDismiss = useCallback(() => {
|
const handleDismiss = useCallback(() => {
|
||||||
dispatch(dismissNotificationRequest(id));
|
dispatch(dismissNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleAccept = useCallback(() => {
|
const handleAccept = useCallback(() => {
|
||||||
dispatch(acceptNotificationRequest(id));
|
dispatch(acceptNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleMoveUp = useCallback(id => {
|
const handleMoveUp = useCallback(id => {
|
||||||
|
@ -79,12 +85,12 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||||
}, [columnRef, notifications]);
|
}, [columnRef, notifications]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchNotificationRequest(id));
|
dispatch(fetchNotificationRequest({ id }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (accountId) {
|
if (accountId) {
|
||||||
dispatch(fetchNotificationsForRequest(accountId));
|
dispatch(fetchNotificationsForRequest({ accountId }));
|
||||||
}
|
}
|
||||||
}, [dispatch, accountId]);
|
}, [dispatch, accountId]);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,12 @@ import ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?rea
|
||||||
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import { fetchNotificationRequests, expandNotificationRequests, acceptNotificationRequests, dismissNotificationRequests } from 'mastodon/actions/notifications';
|
import {
|
||||||
|
fetchNotificationRequests,
|
||||||
|
expandNotificationRequests,
|
||||||
|
acceptNotificationRequests,
|
||||||
|
dismissNotificationRequests,
|
||||||
|
} from 'mastodon/actions/notification_requests';
|
||||||
import { changeSetting } from 'mastodon/actions/settings';
|
import { changeSetting } from 'mastodon/actions/settings';
|
||||||
import { CheckBox } from 'mastodon/components/check_box';
|
import { CheckBox } from 'mastodon/components/check_box';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
|
@ -84,7 +89,7 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
|
||||||
message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }),
|
message: intl.formatMessage(messages.confirmAcceptMultipleMessage, { count: selectedItems.length }),
|
||||||
confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}),
|
confirm: intl.formatMessage(messages.confirmAcceptMultipleButton, { count: selectedItems.length}),
|
||||||
onConfirm: () =>
|
onConfirm: () =>
|
||||||
dispatch(acceptNotificationRequests(selectedItems)),
|
dispatch(acceptNotificationRequests({ ids: selectedItems })),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [dispatch, intl, selectedItems]);
|
}, [dispatch, intl, selectedItems]);
|
||||||
|
@ -97,7 +102,7 @@ const SelectRow = ({selectAllChecked, toggleSelectAll, selectedItems, selectionM
|
||||||
message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }),
|
message: intl.formatMessage(messages.confirmDismissMultipleMessage, { count: selectedItems.length }),
|
||||||
confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}),
|
confirm: intl.formatMessage(messages.confirmDismissMultipleButton, { count: selectedItems.length}),
|
||||||
onConfirm: () =>
|
onConfirm: () =>
|
||||||
dispatch(dismissNotificationRequests(selectedItems)),
|
dispatch(dismissNotificationRequests({ ids: selectedItems })),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [dispatch, intl, selectedItems]);
|
}, [dispatch, intl, selectedItems]);
|
||||||
|
@ -161,9 +166,9 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
const columnRef = useRef();
|
const columnRef = useRef();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isLoading = useSelector(state => state.getIn(['notificationRequests', 'isLoading']));
|
const isLoading = useSelector(state => state.notificationRequests.isLoading);
|
||||||
const notificationRequests = useSelector(state => state.getIn(['notificationRequests', 'items']));
|
const notificationRequests = useSelector(state => state.notificationRequests.items);
|
||||||
const hasMore = useSelector(state => !!state.getIn(['notificationRequests', 'next']));
|
const hasMore = useSelector(state => !!state.notificationRequests.next);
|
||||||
|
|
||||||
const [selectionMode, setSelectionMode] = useState(false);
|
const [selectionMode, setSelectionMode] = useState(false);
|
||||||
const [checkedRequestIds, setCheckedRequestIds] = useState([]);
|
const [checkedRequestIds, setCheckedRequestIds] = useState([]);
|
||||||
|
@ -182,7 +187,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
else
|
else
|
||||||
ids.push(id);
|
ids.push(id);
|
||||||
|
|
||||||
setSelectAllChecked(ids.length === notificationRequests.size);
|
setSelectAllChecked(ids.length === notificationRequests.length);
|
||||||
|
|
||||||
return [...ids];
|
return [...ids];
|
||||||
});
|
});
|
||||||
|
@ -193,7 +198,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
if(checked)
|
if(checked)
|
||||||
setCheckedRequestIds([]);
|
setCheckedRequestIds([]);
|
||||||
else
|
else
|
||||||
setCheckedRequestIds(notificationRequests.map(request => request.get('id')).toArray());
|
setCheckedRequestIds(notificationRequests.map(request => request.id));
|
||||||
|
|
||||||
return !checked;
|
return !checked;
|
||||||
});
|
});
|
||||||
|
@ -217,7 +222,7 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
multiColumn={multiColumn}
|
multiColumn={multiColumn}
|
||||||
showBackButton
|
showBackButton
|
||||||
appendContent={
|
appendContent={
|
||||||
notificationRequests.size > 0 && (
|
notificationRequests.length > 0 && (
|
||||||
<SelectRow selectionMode={selectionMode} setSelectionMode={setSelectionMode} selectAllChecked={selectAllChecked} toggleSelectAll={toggleSelectAll} selectedItems={checkedRequestIds} />
|
<SelectRow selectionMode={selectionMode} setSelectionMode={setSelectionMode} selectAllChecked={selectAllChecked} toggleSelectAll={toggleSelectAll} selectedItems={checkedRequestIds} />
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -236,12 +241,12 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||||
>
|
>
|
||||||
{notificationRequests.map(request => (
|
{notificationRequests.map(request => (
|
||||||
<NotificationRequest
|
<NotificationRequest
|
||||||
key={request.get('id')}
|
key={request.id}
|
||||||
id={request.get('id')}
|
id={request.id}
|
||||||
accountId={request.get('account')}
|
accountId={request.account_id}
|
||||||
notificationsCount={request.get('notifications_count')}
|
notificationsCount={request.notifications_count}
|
||||||
showCheckbox={selectionMode}
|
showCheckbox={selectionMode}
|
||||||
checked={checkedRequestIds.includes(request.get('id'))}
|
checked={checkedRequestIds.includes(request.id)}
|
||||||
toggleCheck={handleCheck}
|
toggleCheck={handleCheck}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Edita",
|
"status.edit": "Edita",
|
||||||
"status.edited": "Darrera edició {date}",
|
"status.edited": "Darrera edició {date}",
|
||||||
"status.edited_x_times": "Editat {count, plural, one {{count} vegada} other {{count} vegades}}",
|
"status.edited_x_times": "Editat {count, plural, one {{count} vegada} other {{count} vegades}}",
|
||||||
|
"status.embed": "Obté el codi encastat",
|
||||||
"status.favourite": "Favorit",
|
"status.favourite": "Favorit",
|
||||||
"status.favourites": "{count, plural, one {favorit} other {favorits}}",
|
"status.favourites": "{count, plural, one {favorit} other {favorits}}",
|
||||||
"status.filter": "Filtra aquest tut",
|
"status.filter": "Filtra aquest tut",
|
||||||
|
|
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Edit",
|
"status.edit": "Edit",
|
||||||
"status.edited": "Last edited {date}",
|
"status.edited": "Last edited {date}",
|
||||||
"status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
|
"status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
|
||||||
|
"status.embed": "Get embed code",
|
||||||
"status.favourite": "Favourite",
|
"status.favourite": "Favourite",
|
||||||
"status.favourites": "{count, plural, one {favorite} other {favorites}}",
|
"status.favourites": "{count, plural, one {favorite} other {favorites}}",
|
||||||
"status.filter": "Filter this post",
|
"status.filter": "Filter this post",
|
||||||
|
|
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Editar",
|
"status.edit": "Editar",
|
||||||
"status.edited": "Última edición: {date}",
|
"status.edited": "Última edición: {date}",
|
||||||
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
||||||
|
"status.embed": "Obtener código para insertar",
|
||||||
"status.favourite": "Marcar como favorito",
|
"status.favourite": "Marcar como favorito",
|
||||||
"status.favourites": "{count, plural, one {# voto} other {# votos}}",
|
"status.favourites": "{count, plural, one {# voto} other {# votos}}",
|
||||||
"status.filter": "Filtrar este mensaje",
|
"status.filter": "Filtrar este mensaje",
|
||||||
|
|
|
@ -376,7 +376,7 @@
|
||||||
"ignore_notifications_modal.ignore": "Ignorar notificaciones",
|
"ignore_notifications_modal.ignore": "Ignorar notificaciones",
|
||||||
"ignore_notifications_modal.limited_accounts_title": "¿Ignorar notificaciones de cuentas moderadas?",
|
"ignore_notifications_modal.limited_accounts_title": "¿Ignorar notificaciones de cuentas moderadas?",
|
||||||
"ignore_notifications_modal.new_accounts_title": "¿Ignorar notificaciones de cuentas nuevas?",
|
"ignore_notifications_modal.new_accounts_title": "¿Ignorar notificaciones de cuentas nuevas?",
|
||||||
"ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te sigue?",
|
"ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te siguen?",
|
||||||
"ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?",
|
"ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?",
|
"ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?",
|
||||||
"interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta, y guardala para más adelante.",
|
"interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta, y guardala para más adelante.",
|
||||||
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Editar",
|
"status.edit": "Editar",
|
||||||
"status.edited": "Última edición {date}",
|
"status.edited": "Última edición {date}",
|
||||||
"status.edited_x_times": "Editado {count, plural, one {{count} time} other {{count} veces}}",
|
"status.edited_x_times": "Editado {count, plural, one {{count} time} other {{count} veces}}",
|
||||||
|
"status.embed": "Obtener código para incrustar",
|
||||||
"status.favourite": "Favorito",
|
"status.favourite": "Favorito",
|
||||||
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
||||||
"status.filter": "Filtrar esta publicación",
|
"status.filter": "Filtrar esta publicación",
|
||||||
|
|
|
@ -376,7 +376,7 @@
|
||||||
"ignore_notifications_modal.ignore": "Ignorar notificaciones",
|
"ignore_notifications_modal.ignore": "Ignorar notificaciones",
|
||||||
"ignore_notifications_modal.limited_accounts_title": "¿Ignorar notificaciones de cuentas moderadas?",
|
"ignore_notifications_modal.limited_accounts_title": "¿Ignorar notificaciones de cuentas moderadas?",
|
||||||
"ignore_notifications_modal.new_accounts_title": "¿Ignorar notificaciones de cuentas nuevas?",
|
"ignore_notifications_modal.new_accounts_title": "¿Ignorar notificaciones de cuentas nuevas?",
|
||||||
"ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te sigue?",
|
"ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te siguen?",
|
||||||
"ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?",
|
"ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?",
|
"ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?",
|
||||||
"interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta, y guardala para más adelante.",
|
"interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta, y guardala para más adelante.",
|
||||||
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Editar",
|
"status.edit": "Editar",
|
||||||
"status.edited": "Última edición {date}",
|
"status.edited": "Última edición {date}",
|
||||||
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
||||||
|
"status.embed": "Obtener código para incrustar",
|
||||||
"status.favourite": "Favorito",
|
"status.favourite": "Favorito",
|
||||||
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
||||||
"status.filter": "Filtrar esta publicación",
|
"status.filter": "Filtrar esta publicación",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "Sinu nimekirjad",
|
"lists.subheading": "Sinu nimekirjad",
|
||||||
"load_pending": "{count, plural, one {# uus kirje} other {# uut kirjet}}",
|
"load_pending": "{count, plural, one {# uus kirje} other {# uut kirjet}}",
|
||||||
"loading_indicator.label": "Laadimine…",
|
"loading_indicator.label": "Laadimine…",
|
||||||
|
"media_gallery.hide": "Peida",
|
||||||
"moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.",
|
"moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Peida teavituste hulgast",
|
"mute_modal.hide_from_notifications": "Peida teavituste hulgast",
|
||||||
"mute_modal.hide_options": "Peida valikud",
|
"mute_modal.hide_options": "Peida valikud",
|
||||||
|
@ -779,6 +780,7 @@
|
||||||
"status.bookmark": "Järjehoidja",
|
"status.bookmark": "Järjehoidja",
|
||||||
"status.cancel_reblog_private": "Lõpeta jagamine",
|
"status.cancel_reblog_private": "Lõpeta jagamine",
|
||||||
"status.cannot_reblog": "Seda postitust ei saa jagada",
|
"status.cannot_reblog": "Seda postitust ei saa jagada",
|
||||||
|
"status.continued_thread": "Jätkatud lõim",
|
||||||
"status.copy": "Kopeeri postituse link",
|
"status.copy": "Kopeeri postituse link",
|
||||||
"status.delete": "Kustuta",
|
"status.delete": "Kustuta",
|
||||||
"status.detailed_status": "Detailne vestluskuva",
|
"status.detailed_status": "Detailne vestluskuva",
|
||||||
|
@ -787,6 +789,7 @@
|
||||||
"status.edit": "Muuda",
|
"status.edit": "Muuda",
|
||||||
"status.edited": "Viimati muudetud {date}",
|
"status.edited": "Viimati muudetud {date}",
|
||||||
"status.edited_x_times": "Muudetud {count, plural, one{{count} kord} other {{count} korda}}",
|
"status.edited_x_times": "Muudetud {count, plural, one{{count} kord} other {{count} korda}}",
|
||||||
|
"status.embed": "Hangi manustamiskood",
|
||||||
"status.favourite": "Lemmik",
|
"status.favourite": "Lemmik",
|
||||||
"status.favourites": "{count, plural, one {lemmik} other {lemmikud}}",
|
"status.favourites": "{count, plural, one {lemmik} other {lemmikud}}",
|
||||||
"status.filter": "Filtreeri seda postitust",
|
"status.filter": "Filtreeri seda postitust",
|
||||||
|
@ -811,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Keegi pole seda postitust veel jaganud. Kui keegi seda teeb, näeb seda siin.",
|
"status.reblogs.empty": "Keegi pole seda postitust veel jaganud. Kui keegi seda teeb, näeb seda siin.",
|
||||||
"status.redraft": "Kustuta & alga uuesti",
|
"status.redraft": "Kustuta & alga uuesti",
|
||||||
"status.remove_bookmark": "Eemalda järjehoidja",
|
"status.remove_bookmark": "Eemalda järjehoidja",
|
||||||
|
"status.replied_in_thread": "Vastatud lõimes",
|
||||||
"status.replied_to": "Vastas kasutajale {name}",
|
"status.replied_to": "Vastas kasutajale {name}",
|
||||||
"status.reply": "Vasta",
|
"status.reply": "Vasta",
|
||||||
"status.replyAll": "Vasta lõimele",
|
"status.replyAll": "Vasta lõimele",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "Zure zerrendak",
|
"lists.subheading": "Zure zerrendak",
|
||||||
"load_pending": "{count, plural, one {elementu berri #} other {# elementu berri}}",
|
"load_pending": "{count, plural, one {elementu berri #} other {# elementu berri}}",
|
||||||
"loading_indicator.label": "Kargatzen…",
|
"loading_indicator.label": "Kargatzen…",
|
||||||
|
"media_gallery.hide": "Ezkutatu",
|
||||||
"moved_to_account_banner.text": "Zure {disabledAccount} kontua desgaituta dago une honetan, {movedToAccount} kontura aldatu zinelako.",
|
"moved_to_account_banner.text": "Zure {disabledAccount} kontua desgaituta dago une honetan, {movedToAccount} kontura aldatu zinelako.",
|
||||||
"mute_modal.hide_from_notifications": "Ezkutatu jakinarazpenetatik",
|
"mute_modal.hide_from_notifications": "Ezkutatu jakinarazpenetatik",
|
||||||
"mute_modal.hide_options": "Ezkutatu aukerak",
|
"mute_modal.hide_options": "Ezkutatu aukerak",
|
||||||
|
@ -775,6 +776,7 @@
|
||||||
"status.bookmark": "Laster-marka",
|
"status.bookmark": "Laster-marka",
|
||||||
"status.cancel_reblog_private": "Kendu bultzada",
|
"status.cancel_reblog_private": "Kendu bultzada",
|
||||||
"status.cannot_reblog": "Bidalketa honi ezin zaio bultzada eman",
|
"status.cannot_reblog": "Bidalketa honi ezin zaio bultzada eman",
|
||||||
|
"status.continued_thread": "Harian jarraitu zuen",
|
||||||
"status.copy": "Kopiatu bidalketaren esteka",
|
"status.copy": "Kopiatu bidalketaren esteka",
|
||||||
"status.delete": "Ezabatu",
|
"status.delete": "Ezabatu",
|
||||||
"status.detailed_status": "Elkarrizketaren ikuspegi xehetsua",
|
"status.detailed_status": "Elkarrizketaren ikuspegi xehetsua",
|
||||||
|
@ -783,6 +785,7 @@
|
||||||
"status.edit": "Editatu",
|
"status.edit": "Editatu",
|
||||||
"status.edited": "Azken edizioa: {date}",
|
"status.edited": "Azken edizioa: {date}",
|
||||||
"status.edited_x_times": "{count, plural, one {behin} other {{count} aldiz}} editatua",
|
"status.edited_x_times": "{count, plural, one {behin} other {{count} aldiz}} editatua",
|
||||||
|
"status.embed": "Lortu txertatzeko kodea",
|
||||||
"status.favourite": "Gogokoa",
|
"status.favourite": "Gogokoa",
|
||||||
"status.favourites": "{count, plural, one {gogoko} other {gogoko}}",
|
"status.favourites": "{count, plural, one {gogoko} other {gogoko}}",
|
||||||
"status.filter": "Iragazi bidalketa hau",
|
"status.filter": "Iragazi bidalketa hau",
|
||||||
|
@ -807,6 +810,7 @@
|
||||||
"status.reblogs.empty": "Inork ez dio bultzada eman bidalketa honi oraindik. Inork egiten badu, hemen agertuko da.",
|
"status.reblogs.empty": "Inork ez dio bultzada eman bidalketa honi oraindik. Inork egiten badu, hemen agertuko da.",
|
||||||
"status.redraft": "Ezabatu eta berridatzi",
|
"status.redraft": "Ezabatu eta berridatzi",
|
||||||
"status.remove_bookmark": "Kendu laster-marka",
|
"status.remove_bookmark": "Kendu laster-marka",
|
||||||
|
"status.replied_in_thread": "Harian erantzun zuen",
|
||||||
"status.replied_to": "{name} erabiltzaileari erantzuna",
|
"status.replied_to": "{name} erabiltzaileari erantzuna",
|
||||||
"status.reply": "Erantzun",
|
"status.reply": "Erantzun",
|
||||||
"status.replyAll": "Erantzun harian",
|
"status.replyAll": "Erantzun harian",
|
||||||
|
|
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Rætta",
|
"status.edit": "Rætta",
|
||||||
"status.edited": "Seinast broytt {date}",
|
"status.edited": "Seinast broytt {date}",
|
||||||
"status.edited_x_times": "Rættað {count, plural, one {{count} ferð} other {{count} ferð}}",
|
"status.edited_x_times": "Rættað {count, plural, one {{count} ferð} other {{count} ferð}}",
|
||||||
|
"status.embed": "Fá kodu at seta inn",
|
||||||
"status.favourite": "Dámdur postur",
|
"status.favourite": "Dámdur postur",
|
||||||
"status.favourites": "{count, plural, one {yndispostur} other {yndispostar}}",
|
"status.favourites": "{count, plural, one {yndispostur} other {yndispostar}}",
|
||||||
"status.filter": "Filtrera hendan postin",
|
"status.filter": "Filtrera hendan postin",
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"account.followers.empty": "Personne ne suit ce compte pour l'instant.",
|
"account.followers.empty": "Personne ne suit ce compte pour l'instant.",
|
||||||
"account.followers_counter": "{count, plural, one {{counter} abonné·e} other {{counter} abonné·e·s}}",
|
"account.followers_counter": "{count, plural, one {{counter} abonné·e} other {{counter} abonné·e·s}}",
|
||||||
"account.following": "Abonné·e",
|
"account.following": "Abonné·e",
|
||||||
|
"account.following_counter": "{count, plural, one {{counter} abonnement} other {{counter} abonnements}}",
|
||||||
"account.follows.empty": "Ce compte ne suit personne présentement.",
|
"account.follows.empty": "Ce compte ne suit personne présentement.",
|
||||||
"account.go_to_profile": "Voir ce profil",
|
"account.go_to_profile": "Voir ce profil",
|
||||||
"account.hide_reblogs": "Masquer les boosts de @{name}",
|
"account.hide_reblogs": "Masquer les boosts de @{name}",
|
||||||
|
@ -788,6 +789,7 @@
|
||||||
"status.edit": "Modifier",
|
"status.edit": "Modifier",
|
||||||
"status.edited": "Dernière modification le {date}",
|
"status.edited": "Dernière modification le {date}",
|
||||||
"status.edited_x_times": "Modifiée {count, plural, one {{count} fois} other {{count} fois}}",
|
"status.edited_x_times": "Modifiée {count, plural, one {{count} fois} other {{count} fois}}",
|
||||||
|
"status.embed": "Obtenir le code d'intégration",
|
||||||
"status.favourite": "Ajouter aux favoris",
|
"status.favourite": "Ajouter aux favoris",
|
||||||
"status.favourites": "{count, plural, one {favori} other {favoris}}",
|
"status.favourites": "{count, plural, one {favori} other {favoris}}",
|
||||||
"status.filter": "Filtrer cette publication",
|
"status.filter": "Filtrer cette publication",
|
||||||
|
@ -812,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Personne n’a encore boosté cette publication. Lorsque quelqu’un le fera, elle apparaîtra ici.",
|
"status.reblogs.empty": "Personne n’a encore boosté cette publication. Lorsque quelqu’un le fera, elle apparaîtra ici.",
|
||||||
"status.redraft": "Supprimer et réécrire",
|
"status.redraft": "Supprimer et réécrire",
|
||||||
"status.remove_bookmark": "Retirer des signets",
|
"status.remove_bookmark": "Retirer des signets",
|
||||||
|
"status.replied_in_thread": "A répondu dans un fil de discussion",
|
||||||
"status.replied_to": "A répondu à {name}",
|
"status.replied_to": "A répondu à {name}",
|
||||||
"status.reply": "Répondre",
|
"status.reply": "Répondre",
|
||||||
"status.replyAll": "Répondre à cette discussion",
|
"status.replyAll": "Répondre à cette discussion",
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"account.followers.empty": "Personne ne suit cet·te utilisateur·rice pour l’instant.",
|
"account.followers.empty": "Personne ne suit cet·te utilisateur·rice pour l’instant.",
|
||||||
"account.followers_counter": "{count, plural, one {{counter} abonné·e} other {{counter} abonné·e·s}}",
|
"account.followers_counter": "{count, plural, one {{counter} abonné·e} other {{counter} abonné·e·s}}",
|
||||||
"account.following": "Abonnements",
|
"account.following": "Abonnements",
|
||||||
|
"account.following_counter": "{count, plural, one {{counter} abonnement} other {{counter} abonnements}}",
|
||||||
"account.follows.empty": "Cet·te utilisateur·rice ne suit personne pour l’instant.",
|
"account.follows.empty": "Cet·te utilisateur·rice ne suit personne pour l’instant.",
|
||||||
"account.go_to_profile": "Aller au profil",
|
"account.go_to_profile": "Aller au profil",
|
||||||
"account.hide_reblogs": "Masquer les partages de @{name}",
|
"account.hide_reblogs": "Masquer les partages de @{name}",
|
||||||
|
@ -788,6 +789,7 @@
|
||||||
"status.edit": "Modifier",
|
"status.edit": "Modifier",
|
||||||
"status.edited": "Dernière modification le {date}",
|
"status.edited": "Dernière modification le {date}",
|
||||||
"status.edited_x_times": "Modifié {count, plural, one {{count} fois} other {{count} fois}}",
|
"status.edited_x_times": "Modifié {count, plural, one {{count} fois} other {{count} fois}}",
|
||||||
|
"status.embed": "Obtenir le code d'intégration",
|
||||||
"status.favourite": "Ajouter aux favoris",
|
"status.favourite": "Ajouter aux favoris",
|
||||||
"status.favourites": "{count, plural, one {favori} other {favoris}}",
|
"status.favourites": "{count, plural, one {favori} other {favoris}}",
|
||||||
"status.filter": "Filtrer ce message",
|
"status.filter": "Filtrer ce message",
|
||||||
|
@ -812,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Personne n’a encore partagé ce message. Lorsque quelqu’un le fera, il apparaîtra ici.",
|
"status.reblogs.empty": "Personne n’a encore partagé ce message. Lorsque quelqu’un le fera, il apparaîtra ici.",
|
||||||
"status.redraft": "Supprimer et réécrire",
|
"status.redraft": "Supprimer et réécrire",
|
||||||
"status.remove_bookmark": "Retirer des marque-pages",
|
"status.remove_bookmark": "Retirer des marque-pages",
|
||||||
|
"status.replied_in_thread": "A répondu dans un fil de discussion",
|
||||||
"status.replied_to": "En réponse à {name}",
|
"status.replied_to": "En réponse à {name}",
|
||||||
"status.reply": "Répondre",
|
"status.reply": "Répondre",
|
||||||
"status.replyAll": "Répondre au fil",
|
"status.replyAll": "Répondre au fil",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "Do liostaí",
|
"lists.subheading": "Do liostaí",
|
||||||
"load_pending": "{count, plural, one {# mír nua} two {# mír nua} few {# mír nua} many {# mír nua} other {# mír nua}}",
|
"load_pending": "{count, plural, one {# mír nua} two {# mír nua} few {# mír nua} many {# mír nua} other {# mír nua}}",
|
||||||
"loading_indicator.label": "Á lódáil…",
|
"loading_indicator.label": "Á lódáil…",
|
||||||
|
"media_gallery.hide": "Folaigh",
|
||||||
"moved_to_account_banner.text": "Tá do chuntas {disabledAccount} díchumasaithe faoi láthair toisc gur bhog tú go {movedToAccount}.",
|
"moved_to_account_banner.text": "Tá do chuntas {disabledAccount} díchumasaithe faoi láthair toisc gur bhog tú go {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Folaigh ó fhógraí",
|
"mute_modal.hide_from_notifications": "Folaigh ó fhógraí",
|
||||||
"mute_modal.hide_options": "Folaigh roghanna",
|
"mute_modal.hide_options": "Folaigh roghanna",
|
||||||
|
@ -779,6 +780,7 @@
|
||||||
"status.bookmark": "Leabharmharcanna",
|
"status.bookmark": "Leabharmharcanna",
|
||||||
"status.cancel_reblog_private": "Dímhol",
|
"status.cancel_reblog_private": "Dímhol",
|
||||||
"status.cannot_reblog": "Ní féidir an phostáil seo a mholadh",
|
"status.cannot_reblog": "Ní féidir an phostáil seo a mholadh",
|
||||||
|
"status.continued_thread": "Snáithe ar lean",
|
||||||
"status.copy": "Cóipeáil an nasc chuig an bpostáil",
|
"status.copy": "Cóipeáil an nasc chuig an bpostáil",
|
||||||
"status.delete": "Scrios",
|
"status.delete": "Scrios",
|
||||||
"status.detailed_status": "Amharc comhrá mionsonraithe",
|
"status.detailed_status": "Amharc comhrá mionsonraithe",
|
||||||
|
@ -787,6 +789,7 @@
|
||||||
"status.edit": "Cuir in eagar",
|
"status.edit": "Cuir in eagar",
|
||||||
"status.edited": "Arna chuir in eagar anuas {date}",
|
"status.edited": "Arna chuir in eagar anuas {date}",
|
||||||
"status.edited_x_times": "Curtha in eagar {count, plural, one {{count} uair amháin} two {{count} uair} few {{count} uair} many {{count} uair} other {{count} uair}}",
|
"status.edited_x_times": "Curtha in eagar {count, plural, one {{count} uair amháin} two {{count} uair} few {{count} uair} many {{count} uair} other {{count} uair}}",
|
||||||
|
"status.embed": "Faigh cód leabú",
|
||||||
"status.favourite": "Is fearr leat",
|
"status.favourite": "Is fearr leat",
|
||||||
"status.favourites": "{count, plural, one {a bhfuil grá agat do} two {gráite} few {gráite} many {gráite} other {gráite}}",
|
"status.favourites": "{count, plural, one {a bhfuil grá agat do} two {gráite} few {gráite} many {gráite} other {gráite}}",
|
||||||
"status.filter": "Déan scagadh ar an bpostáil seo",
|
"status.filter": "Déan scagadh ar an bpostáil seo",
|
||||||
|
@ -811,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Níor mhol éinne an phostáil seo fós. Nuair a mholfaidh duine éigin í, taispeánfar anseo é sin.",
|
"status.reblogs.empty": "Níor mhol éinne an phostáil seo fós. Nuair a mholfaidh duine éigin í, taispeánfar anseo é sin.",
|
||||||
"status.redraft": "Scrios ⁊ athdhréachtaigh",
|
"status.redraft": "Scrios ⁊ athdhréachtaigh",
|
||||||
"status.remove_bookmark": "Bain leabharmharc",
|
"status.remove_bookmark": "Bain leabharmharc",
|
||||||
|
"status.replied_in_thread": "D'fhreagair sa snáithe",
|
||||||
"status.replied_to": "D'fhreagair {name}",
|
"status.replied_to": "D'fhreagair {name}",
|
||||||
"status.reply": "Freagair",
|
"status.reply": "Freagair",
|
||||||
"status.replyAll": "Freagair le snáithe",
|
"status.replyAll": "Freagair le snáithe",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "Na liostaichean agad",
|
"lists.subheading": "Na liostaichean agad",
|
||||||
"load_pending": "{count, plural, one {# nì ùr} two {# nì ùr} few {# nithean ùra} other {# nì ùr}}",
|
"load_pending": "{count, plural, one {# nì ùr} two {# nì ùr} few {# nithean ùra} other {# nì ùr}}",
|
||||||
"loading_indicator.label": "’Ga luchdadh…",
|
"loading_indicator.label": "’Ga luchdadh…",
|
||||||
|
"media_gallery.hide": "Falaich",
|
||||||
"moved_to_account_banner.text": "Tha an cunntas {disabledAccount} agad à comas on a rinn thu imrich gu {movedToAccount}.",
|
"moved_to_account_banner.text": "Tha an cunntas {disabledAccount} agad à comas on a rinn thu imrich gu {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Falaich o na brathan",
|
"mute_modal.hide_from_notifications": "Falaich o na brathan",
|
||||||
"mute_modal.hide_options": "Roghainnean falaich",
|
"mute_modal.hide_options": "Roghainnean falaich",
|
||||||
|
@ -779,6 +780,7 @@
|
||||||
"status.bookmark": "Cuir ris na comharran-lìn",
|
"status.bookmark": "Cuir ris na comharran-lìn",
|
||||||
"status.cancel_reblog_private": "Na brosnaich tuilleadh",
|
"status.cancel_reblog_private": "Na brosnaich tuilleadh",
|
||||||
"status.cannot_reblog": "Cha ghabh am post seo brosnachadh",
|
"status.cannot_reblog": "Cha ghabh am post seo brosnachadh",
|
||||||
|
"status.continued_thread": "Pàirt de shnàithlean",
|
||||||
"status.copy": "Dèan lethbhreac dhen cheangal dhan phost",
|
"status.copy": "Dèan lethbhreac dhen cheangal dhan phost",
|
||||||
"status.delete": "Sguab às",
|
"status.delete": "Sguab às",
|
||||||
"status.detailed_status": "Mion-shealladh a’ chòmhraidh",
|
"status.detailed_status": "Mion-shealladh a’ chòmhraidh",
|
||||||
|
@ -787,6 +789,7 @@
|
||||||
"status.edit": "Deasaich",
|
"status.edit": "Deasaich",
|
||||||
"status.edited": "An deasachadh mu dheireadh {date}",
|
"status.edited": "An deasachadh mu dheireadh {date}",
|
||||||
"status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{count} turas} two {{count} thuras} few {{count} tursan} other {{count} turas}}",
|
"status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{count} turas} two {{count} thuras} few {{count} tursan} other {{count} turas}}",
|
||||||
|
"status.embed": "Faigh còd leabachaidh",
|
||||||
"status.favourite": "Cuir ris na h-annsachdan",
|
"status.favourite": "Cuir ris na h-annsachdan",
|
||||||
"status.favourites": "{count, plural, one {annsachd} two {annsachd} few {annsachdan} other {annsachd}}",
|
"status.favourites": "{count, plural, one {annsachd} two {annsachd} few {annsachdan} other {annsachd}}",
|
||||||
"status.filter": "Criathraich am post seo",
|
"status.filter": "Criathraich am post seo",
|
||||||
|
@ -811,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Chan deach am post seo a bhrosnachadh le duine sam bith fhathast. Nuair a bhrosnaicheas cuideigin e, nochdaidh iad an-seo.",
|
"status.reblogs.empty": "Chan deach am post seo a bhrosnachadh le duine sam bith fhathast. Nuair a bhrosnaicheas cuideigin e, nochdaidh iad an-seo.",
|
||||||
"status.redraft": "Sguab às ⁊ dèan dreachd ùr",
|
"status.redraft": "Sguab às ⁊ dèan dreachd ùr",
|
||||||
"status.remove_bookmark": "Thoir an comharra-lìn air falbh",
|
"status.remove_bookmark": "Thoir an comharra-lìn air falbh",
|
||||||
|
"status.replied_in_thread": "Freagairt do shnàithlean",
|
||||||
"status.replied_to": "Air {name} fhreagairt",
|
"status.replied_to": "Air {name} fhreagairt",
|
||||||
"status.reply": "Freagair",
|
"status.reply": "Freagair",
|
||||||
"status.replyAll": "Freagair dhan t-snàithlean",
|
"status.replyAll": "Freagair dhan t-snàithlean",
|
||||||
|
|
|
@ -355,6 +355,7 @@
|
||||||
"hints.profiles.see_more_followers": "Vider plus de sequitores sur {domain}",
|
"hints.profiles.see_more_followers": "Vider plus de sequitores sur {domain}",
|
||||||
"hints.profiles.see_more_follows": "Vider plus de sequites sur {domain}",
|
"hints.profiles.see_more_follows": "Vider plus de sequites sur {domain}",
|
||||||
"hints.profiles.see_more_posts": "Vider plus de messages sur {domain}",
|
"hints.profiles.see_more_posts": "Vider plus de messages sur {domain}",
|
||||||
|
"hints.threads.replies_may_be_missing": "Responsas de altere servitores pote esser perdite.",
|
||||||
"hints.threads.see_more": "Vider plus de responsas sur {domain}",
|
"hints.threads.see_more": "Vider plus de responsas sur {domain}",
|
||||||
"home.column_settings.show_reblogs": "Monstrar impulsos",
|
"home.column_settings.show_reblogs": "Monstrar impulsos",
|
||||||
"home.column_settings.show_replies": "Monstrar responsas",
|
"home.column_settings.show_replies": "Monstrar responsas",
|
||||||
|
|
|
@ -789,6 +789,7 @@
|
||||||
"status.edit": "Breyta",
|
"status.edit": "Breyta",
|
||||||
"status.edited": "Síðast breytt {date}",
|
"status.edited": "Síðast breytt {date}",
|
||||||
"status.edited_x_times": "Breytt {count, plural, one {{count} sinni} other {{count} sinnum}}",
|
"status.edited_x_times": "Breytt {count, plural, one {{count} sinni} other {{count} sinnum}}",
|
||||||
|
"status.embed": "Ná í innfellanlegan kóða",
|
||||||
"status.favourite": "Eftirlæti",
|
"status.favourite": "Eftirlæti",
|
||||||
"status.favourites": "{count, plural, one {eftirlæti} other {eftirlæti}}",
|
"status.favourites": "{count, plural, one {eftirlæti} other {eftirlæti}}",
|
||||||
"status.filter": "Sía þessa færslu",
|
"status.filter": "Sía þessa færslu",
|
||||||
|
|
|
@ -371,6 +371,14 @@
|
||||||
"ignore_notifications_modal.disclaimer": "O Mastodon não pode informar utilizadores que ignoraste as notificações deles. Ignorar notificações não irá parar as mensagens serem enviadas.",
|
"ignore_notifications_modal.disclaimer": "O Mastodon não pode informar utilizadores que ignoraste as notificações deles. Ignorar notificações não irá parar as mensagens serem enviadas.",
|
||||||
"ignore_notifications_modal.filter_instead": "Filtrar em vez disso",
|
"ignore_notifications_modal.filter_instead": "Filtrar em vez disso",
|
||||||
"ignore_notifications_modal.filter_to_act_users": "Ainda poderá aceitar, rejeitar, ou reportar utilizadores",
|
"ignore_notifications_modal.filter_to_act_users": "Ainda poderá aceitar, rejeitar, ou reportar utilizadores",
|
||||||
|
"ignore_notifications_modal.filter_to_avoid_confusion": "A filtragem ajuda a evitar potenciais equívocos",
|
||||||
|
"ignore_notifications_modal.filter_to_review_separately": "Pode rever as notificações filtradas separadamente",
|
||||||
|
"ignore_notifications_modal.ignore": "Ignorar notificações",
|
||||||
|
"ignore_notifications_modal.limited_accounts_title": "Ignorar notificações de contas moderadas?",
|
||||||
|
"ignore_notifications_modal.new_accounts_title": "Ignorar notificações de contas novas?",
|
||||||
|
"ignore_notifications_modal.not_followers_title": "Ignorar notificações de pessoas que não o seguem?",
|
||||||
|
"ignore_notifications_modal.not_following_title": "Ignorar notificações de pessoas que não segue?",
|
||||||
|
"ignore_notifications_modal.private_mentions_title": "Ignorar notificações de Menções Privadas não solicitadas?",
|
||||||
"interaction_modal.description.favourite": "Com uma conta no Mastodon, pode adicionar assinalar esta publicação como favorita para que o autor saiba que gostou e guardá-la para mais tarde.",
|
"interaction_modal.description.favourite": "Com uma conta no Mastodon, pode adicionar assinalar esta publicação como favorita para que o autor saiba que gostou e guardá-la para mais tarde.",
|
||||||
"interaction_modal.description.follow": "Com uma conta no Mastodon, pode seguir {name} para receber as suas publicações na sua página inicial.",
|
"interaction_modal.description.follow": "Com uma conta no Mastodon, pode seguir {name} para receber as suas publicações na sua página inicial.",
|
||||||
"interaction_modal.description.reblog": "Com uma conta no Mastodon, pode impulsionar esta publicação para compartilhá-lo com os seus seguidores.",
|
"interaction_modal.description.reblog": "Com uma conta no Mastodon, pode impulsionar esta publicação para compartilhá-lo com os seus seguidores.",
|
||||||
|
@ -449,6 +457,7 @@
|
||||||
"lists.subheading": "As tuas listas",
|
"lists.subheading": "As tuas listas",
|
||||||
"load_pending": "{count, plural, one {# novo item} other {# novos itens}}",
|
"load_pending": "{count, plural, one {# novo item} other {# novos itens}}",
|
||||||
"loading_indicator.label": "A carregar…",
|
"loading_indicator.label": "A carregar…",
|
||||||
|
"media_gallery.hide": "Esconder",
|
||||||
"moved_to_account_banner.text": "A sua conta {disabledAccount} está, no momento, desativada, porque você migrou para {movedToAccount}.",
|
"moved_to_account_banner.text": "A sua conta {disabledAccount} está, no momento, desativada, porque você migrou para {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Ocultar das notificações",
|
"mute_modal.hide_from_notifications": "Ocultar das notificações",
|
||||||
"mute_modal.hide_options": "Ocultar opções",
|
"mute_modal.hide_options": "Ocultar opções",
|
||||||
|
@ -460,6 +469,7 @@
|
||||||
"mute_modal.you_wont_see_mentions": "Não verá publicações que os mencionem.",
|
"mute_modal.you_wont_see_mentions": "Não verá publicações que os mencionem.",
|
||||||
"mute_modal.you_wont_see_posts": "Eles podem continuar a ver as suas publicações, mas você não verá as deles.",
|
"mute_modal.you_wont_see_posts": "Eles podem continuar a ver as suas publicações, mas você não verá as deles.",
|
||||||
"navigation_bar.about": "Sobre",
|
"navigation_bar.about": "Sobre",
|
||||||
|
"navigation_bar.administration": "Administração",
|
||||||
"navigation_bar.advanced_interface": "Abrir na interface web avançada",
|
"navigation_bar.advanced_interface": "Abrir na interface web avançada",
|
||||||
"navigation_bar.blocks": "Utilizadores bloqueados",
|
"navigation_bar.blocks": "Utilizadores bloqueados",
|
||||||
"navigation_bar.bookmarks": "Marcadores",
|
"navigation_bar.bookmarks": "Marcadores",
|
||||||
|
@ -476,6 +486,7 @@
|
||||||
"navigation_bar.follows_and_followers": "Seguindo e seguidores",
|
"navigation_bar.follows_and_followers": "Seguindo e seguidores",
|
||||||
"navigation_bar.lists": "Listas",
|
"navigation_bar.lists": "Listas",
|
||||||
"navigation_bar.logout": "Sair",
|
"navigation_bar.logout": "Sair",
|
||||||
|
"navigation_bar.moderation": "Moderação",
|
||||||
"navigation_bar.mutes": "Utilizadores silenciados",
|
"navigation_bar.mutes": "Utilizadores silenciados",
|
||||||
"navigation_bar.opened_in_classic_interface": "Por norma, publicações, contas, e outras páginas específicas são abertas na interface web clássica.",
|
"navigation_bar.opened_in_classic_interface": "Por norma, publicações, contas, e outras páginas específicas são abertas na interface web clássica.",
|
||||||
"navigation_bar.personal": "Pessoal",
|
"navigation_bar.personal": "Pessoal",
|
||||||
|
@ -491,9 +502,13 @@
|
||||||
"notification.admin.report_statuses": "{name} denunicou {target} por {category}",
|
"notification.admin.report_statuses": "{name} denunicou {target} por {category}",
|
||||||
"notification.admin.report_statuses_other": "{name} denunciou {target}",
|
"notification.admin.report_statuses_other": "{name} denunciou {target}",
|
||||||
"notification.admin.sign_up": "{name} inscreveu-se",
|
"notification.admin.sign_up": "{name} inscreveu-se",
|
||||||
|
"notification.admin.sign_up.name_and_others": "{name} e {count, plural, one {# outro} other {# outros}} inscreveram-se",
|
||||||
"notification.favourite": "{name} assinalou a sua publicação como favorita",
|
"notification.favourite": "{name} assinalou a sua publicação como favorita",
|
||||||
|
"notification.favourite.name_and_others_with_link": "{name} e <a>{count, plural, one {# outro} other {# outros}}</a> assinalou a sua publicação como favorita",
|
||||||
"notification.follow": "{name} começou a seguir-te",
|
"notification.follow": "{name} começou a seguir-te",
|
||||||
|
"notification.follow.name_and_others": "{name} e {count, plural, one {# outro} other {# outros}} começaram a segui-lo",
|
||||||
"notification.follow_request": "{name} pediu para segui-lo",
|
"notification.follow_request": "{name} pediu para segui-lo",
|
||||||
|
"notification.follow_request.name_and_others": "{name} e {count, plural, one {# outro} other {# outros}} pediram para segui-lo",
|
||||||
"notification.label.mention": "Menção",
|
"notification.label.mention": "Menção",
|
||||||
"notification.label.private_mention": "Menção privada",
|
"notification.label.private_mention": "Menção privada",
|
||||||
"notification.label.private_reply": "Resposta privada",
|
"notification.label.private_reply": "Resposta privada",
|
||||||
|
@ -511,6 +526,7 @@
|
||||||
"notification.own_poll": "A sua sondagem terminou",
|
"notification.own_poll": "A sua sondagem terminou",
|
||||||
"notification.poll": "Terminou uma sondagem em que votou",
|
"notification.poll": "Terminou uma sondagem em que votou",
|
||||||
"notification.reblog": "{name} reforçou a tua publicação",
|
"notification.reblog": "{name} reforçou a tua publicação",
|
||||||
|
"notification.reblog.name_and_others_with_link": "{name} e <a>{count, plural, one {# outro} other {# outros}}</a> reforçaram a sua publicação",
|
||||||
"notification.relationships_severance_event": "Perdeu as ligações com {name}",
|
"notification.relationships_severance_event": "Perdeu as ligações com {name}",
|
||||||
"notification.relationships_severance_event.account_suspension": "Um administrador de {from} suspendeu {target}, o que significa que já não pode receber atualizações dele ou interagir com ele.",
|
"notification.relationships_severance_event.account_suspension": "Um administrador de {from} suspendeu {target}, o que significa que já não pode receber atualizações dele ou interagir com ele.",
|
||||||
"notification.relationships_severance_event.domain_block": "Um administrador de {from} bloqueou {target}, incluindo {followersCount} dos seus seguidores e {followingCount, plural, one {# conta} other {# contas}} que segue.",
|
"notification.relationships_severance_event.domain_block": "Um administrador de {from} bloqueou {target}, incluindo {followersCount} dos seus seguidores e {followingCount, plural, one {# conta} other {# contas}} que segue.",
|
||||||
|
@ -519,13 +535,24 @@
|
||||||
"notification.status": "{name} acabou de publicar",
|
"notification.status": "{name} acabou de publicar",
|
||||||
"notification.update": "{name} editou uma publicação",
|
"notification.update": "{name} editou uma publicação",
|
||||||
"notification_requests.accept": "Aceitar",
|
"notification_requests.accept": "Aceitar",
|
||||||
|
"notification_requests.accept_multiple": "{count, plural, one {Aceitar # pedidos…} other {Aceitar # pedidos…}}",
|
||||||
|
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {Aceitar pedido} other {Aceitar pedidos}}",
|
||||||
|
"notification_requests.confirm_accept_multiple.message": "Está prestes a aceitar {count, plural, one {um pedido de notificação} other {# pedidos de notificação}}. Tem a certeza de que pretende continuar?",
|
||||||
|
"notification_requests.confirm_accept_multiple.title": "Aceitar pedidos de notificação?",
|
||||||
|
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Rejeitar pedido} other {Rejeitar pedidos}}",
|
||||||
|
"notification_requests.confirm_dismiss_multiple.message": "Está prestes a rejeitar {count, plural, one {um pedido de notificação} other {# pedidos de notificação}}. Não será fácil voltar a {count, plural, one {aceder-lhe} other {aceder-lhes}}. Tem a certeza de que pretende continuar?",
|
||||||
|
"notification_requests.confirm_dismiss_multiple.title": "Rejeitar pedidos de notificação?",
|
||||||
"notification_requests.dismiss": "Descartar",
|
"notification_requests.dismiss": "Descartar",
|
||||||
|
"notification_requests.dismiss_multiple": "{count, plural, one {Rejeitar # pedido…} other {Rejeitar # pedidos…}}",
|
||||||
|
"notification_requests.edit_selection": "Editar",
|
||||||
|
"notification_requests.exit_selection": "Concluído",
|
||||||
"notification_requests.explainer_for_limited_account": "As notificações desta conta foram filtradas porque a conta foi limitada por um moderador.",
|
"notification_requests.explainer_for_limited_account": "As notificações desta conta foram filtradas porque a conta foi limitada por um moderador.",
|
||||||
"notification_requests.explainer_for_limited_remote_account": "As notificações desta conta foram filtradas porque a conta ou o seu servidor foram limitados por um moderador.",
|
"notification_requests.explainer_for_limited_remote_account": "As notificações desta conta foram filtradas porque a conta ou o seu servidor foram limitados por um moderador.",
|
||||||
"notification_requests.maximize": "Maximizar",
|
"notification_requests.maximize": "Maximizar",
|
||||||
"notification_requests.minimize_banner": "Minimizar o cabeçalho das notificações filtradas",
|
"notification_requests.minimize_banner": "Minimizar o cabeçalho das notificações filtradas",
|
||||||
"notification_requests.notifications_from": "Notificações de {name}",
|
"notification_requests.notifications_from": "Notificações de {name}",
|
||||||
"notification_requests.title": "Notificações filtradas",
|
"notification_requests.title": "Notificações filtradas",
|
||||||
|
"notification_requests.view": "Ver notificações",
|
||||||
"notifications.clear": "Limpar notificações",
|
"notifications.clear": "Limpar notificações",
|
||||||
"notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?",
|
"notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?",
|
||||||
"notifications.clear_title": "Limpar notificações?",
|
"notifications.clear_title": "Limpar notificações?",
|
||||||
|
@ -562,6 +589,12 @@
|
||||||
"notifications.permission_denied": "Notificações no ambiente de trabalho não estão disponíveis porque a permissão, solicitada pelo navegador, foi recusada anteriormente",
|
"notifications.permission_denied": "Notificações no ambiente de trabalho não estão disponíveis porque a permissão, solicitada pelo navegador, foi recusada anteriormente",
|
||||||
"notifications.permission_denied_alert": "Notificações no ambiente de trabalho não podem ser ativadas, pois a permissão do navegador foi recusada anteriormente",
|
"notifications.permission_denied_alert": "Notificações no ambiente de trabalho não podem ser ativadas, pois a permissão do navegador foi recusada anteriormente",
|
||||||
"notifications.permission_required": "Notificações no ambiente de trabalho não estão disponíveis porque a permissão necessária não foi concedida.",
|
"notifications.permission_required": "Notificações no ambiente de trabalho não estão disponíveis porque a permissão necessária não foi concedida.",
|
||||||
|
"notifications.policy.accept": "Aceitar",
|
||||||
|
"notifications.policy.accept_hint": "Mostrar nas notificações",
|
||||||
|
"notifications.policy.drop": "Ignorar",
|
||||||
|
"notifications.policy.drop_hint": "Enviar para o vazio, para nunca mais ser visto",
|
||||||
|
"notifications.policy.filter": "Filtrar",
|
||||||
|
"notifications.policy.filter_hint": "Enviar para a caixa de notificações filtradas",
|
||||||
"notifications.policy.filter_limited_accounts_hint": "Limitado pelos moderadores do servidor",
|
"notifications.policy.filter_limited_accounts_hint": "Limitado pelos moderadores do servidor",
|
||||||
"notifications.policy.filter_limited_accounts_title": "Contas moderadas",
|
"notifications.policy.filter_limited_accounts_title": "Contas moderadas",
|
||||||
"notifications.policy.filter_new_accounts.hint": "Criada nos últimos {days, plural, one {um dia} other {# dias}}",
|
"notifications.policy.filter_new_accounts.hint": "Criada nos últimos {days, plural, one {um dia} other {# dias}}",
|
||||||
|
@ -572,6 +605,7 @@
|
||||||
"notifications.policy.filter_not_following_title": "Pessoas que você não segue",
|
"notifications.policy.filter_not_following_title": "Pessoas que você não segue",
|
||||||
"notifications.policy.filter_private_mentions_hint": "Filtrado, a menos que seja em resposta à sua própria menção ou se você seguir o remetente",
|
"notifications.policy.filter_private_mentions_hint": "Filtrado, a menos que seja em resposta à sua própria menção ou se você seguir o remetente",
|
||||||
"notifications.policy.filter_private_mentions_title": "Menções privadas não solicitadas",
|
"notifications.policy.filter_private_mentions_title": "Menções privadas não solicitadas",
|
||||||
|
"notifications.policy.title": "Gerir notificações de…",
|
||||||
"notifications_permission_banner.enable": "Ativar notificações no ambiente de trabalho",
|
"notifications_permission_banner.enable": "Ativar notificações no ambiente de trabalho",
|
||||||
"notifications_permission_banner.how_to_control": "Para receber notificações quando o Mastodon não estiver aberto, ative as notificações no ambiente de trabalho. Depois da sua ativação, pode controlar precisamente quais tipos de interações geram notificações, através do botão {icon} acima.",
|
"notifications_permission_banner.how_to_control": "Para receber notificações quando o Mastodon não estiver aberto, ative as notificações no ambiente de trabalho. Depois da sua ativação, pode controlar precisamente quais tipos de interações geram notificações, através do botão {icon} acima.",
|
||||||
"notifications_permission_banner.title": "Nunca perca nada",
|
"notifications_permission_banner.title": "Nunca perca nada",
|
||||||
|
@ -746,6 +780,7 @@
|
||||||
"status.bookmark": "Guardar nos marcadores",
|
"status.bookmark": "Guardar nos marcadores",
|
||||||
"status.cancel_reblog_private": "Deixar de reforçar",
|
"status.cancel_reblog_private": "Deixar de reforçar",
|
||||||
"status.cannot_reblog": "Não é possível partilhar esta publicação",
|
"status.cannot_reblog": "Não é possível partilhar esta publicação",
|
||||||
|
"status.continued_thread": "Continuação da conserva",
|
||||||
"status.copy": "Copiar hiperligação para a publicação",
|
"status.copy": "Copiar hiperligação para a publicação",
|
||||||
"status.delete": "Eliminar",
|
"status.delete": "Eliminar",
|
||||||
"status.detailed_status": "Vista pormenorizada da conversa",
|
"status.detailed_status": "Vista pormenorizada da conversa",
|
||||||
|
@ -754,6 +789,7 @@
|
||||||
"status.edit": "Editar",
|
"status.edit": "Editar",
|
||||||
"status.edited": "Última edição em {date}",
|
"status.edited": "Última edição em {date}",
|
||||||
"status.edited_x_times": "Editado {count, plural,one {{count} vez} other {{count} vezes}}",
|
"status.edited_x_times": "Editado {count, plural,one {{count} vez} other {{count} vezes}}",
|
||||||
|
"status.embed": "Obter código de incorporação",
|
||||||
"status.favourite": "Assinalar como favorito",
|
"status.favourite": "Assinalar como favorito",
|
||||||
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
"status.favourites": "{count, plural, one {favorito} other {favoritos}}",
|
||||||
"status.filter": "Filtrar esta publicação",
|
"status.filter": "Filtrar esta publicação",
|
||||||
|
@ -778,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Ainda ninguém reforçou esta publicação. Quando alguém o fizer, ele irá aparecer aqui.",
|
"status.reblogs.empty": "Ainda ninguém reforçou esta publicação. Quando alguém o fizer, ele irá aparecer aqui.",
|
||||||
"status.redraft": "Apagar & reescrever",
|
"status.redraft": "Apagar & reescrever",
|
||||||
"status.remove_bookmark": "Retirar dos marcadores",
|
"status.remove_bookmark": "Retirar dos marcadores",
|
||||||
|
"status.replied_in_thread": "Responder na conversa",
|
||||||
"status.replied_to": "Respondeu a {name}",
|
"status.replied_to": "Respondeu a {name}",
|
||||||
"status.reply": "Responder",
|
"status.reply": "Responder",
|
||||||
"status.replyAll": "Responder à conversa",
|
"status.replyAll": "Responder à conversa",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "รายการของคุณ",
|
"lists.subheading": "รายการของคุณ",
|
||||||
"load_pending": "{count, plural, other {# รายการใหม่}}",
|
"load_pending": "{count, plural, other {# รายการใหม่}}",
|
||||||
"loading_indicator.label": "กำลังโหลด…",
|
"loading_indicator.label": "กำลังโหลด…",
|
||||||
|
"media_gallery.hide": "ซ่อน",
|
||||||
"moved_to_account_banner.text": "มีการปิดใช้งานบัญชีของคุณ {disabledAccount} ในปัจจุบันเนื่องจากคุณได้ย้ายไปยัง {movedToAccount}",
|
"moved_to_account_banner.text": "มีการปิดใช้งานบัญชีของคุณ {disabledAccount} ในปัจจุบันเนื่องจากคุณได้ย้ายไปยัง {movedToAccount}",
|
||||||
"mute_modal.hide_from_notifications": "ซ่อนจากการแจ้งเตือน",
|
"mute_modal.hide_from_notifications": "ซ่อนจากการแจ้งเตือน",
|
||||||
"mute_modal.hide_options": "ซ่อนตัวเลือก",
|
"mute_modal.hide_options": "ซ่อนตัวเลือก",
|
||||||
|
@ -779,6 +780,7 @@
|
||||||
"status.bookmark": "เพิ่มที่คั่นหน้า",
|
"status.bookmark": "เพิ่มที่คั่นหน้า",
|
||||||
"status.cancel_reblog_private": "เลิกดัน",
|
"status.cancel_reblog_private": "เลิกดัน",
|
||||||
"status.cannot_reblog": "ไม่สามารถดันโพสต์นี้",
|
"status.cannot_reblog": "ไม่สามารถดันโพสต์นี้",
|
||||||
|
"status.continued_thread": "กระทู้ต่อเนื่อง",
|
||||||
"status.copy": "คัดลอกลิงก์ไปยังโพสต์",
|
"status.copy": "คัดลอกลิงก์ไปยังโพสต์",
|
||||||
"status.delete": "ลบ",
|
"status.delete": "ลบ",
|
||||||
"status.detailed_status": "มุมมองการสนทนาโดยละเอียด",
|
"status.detailed_status": "มุมมองการสนทนาโดยละเอียด",
|
||||||
|
@ -787,6 +789,7 @@
|
||||||
"status.edit": "แก้ไข",
|
"status.edit": "แก้ไข",
|
||||||
"status.edited": "แก้ไขล่าสุดเมื่อ {date}",
|
"status.edited": "แก้ไขล่าสุดเมื่อ {date}",
|
||||||
"status.edited_x_times": "แก้ไข {count, plural, other {{count} ครั้ง}}",
|
"status.edited_x_times": "แก้ไข {count, plural, other {{count} ครั้ง}}",
|
||||||
|
"status.embed": "รับโค้ดฝังตัว",
|
||||||
"status.favourite": "ชื่นชอบ",
|
"status.favourite": "ชื่นชอบ",
|
||||||
"status.favourites": "{count, plural, other {รายการโปรด}}",
|
"status.favourites": "{count, plural, other {รายการโปรด}}",
|
||||||
"status.filter": "กรองโพสต์นี้",
|
"status.filter": "กรองโพสต์นี้",
|
||||||
|
@ -811,6 +814,7 @@
|
||||||
"status.reblogs.empty": "ยังไม่มีใครดันโพสต์นี้ เมื่อใครสักคนดัน เขาจะปรากฏที่นี่",
|
"status.reblogs.empty": "ยังไม่มีใครดันโพสต์นี้ เมื่อใครสักคนดัน เขาจะปรากฏที่นี่",
|
||||||
"status.redraft": "ลบแล้วร่างใหม่",
|
"status.redraft": "ลบแล้วร่างใหม่",
|
||||||
"status.remove_bookmark": "เอาที่คั่นหน้าออก",
|
"status.remove_bookmark": "เอาที่คั่นหน้าออก",
|
||||||
|
"status.replied_in_thread": "ตอบกลับในกระทู้",
|
||||||
"status.replied_to": "ตอบกลับ {name}",
|
"status.replied_to": "ตอบกลับ {name}",
|
||||||
"status.reply": "ตอบกลับ",
|
"status.reply": "ตอบกลับ",
|
||||||
"status.replyAll": "ตอบกลับกระทู้",
|
"status.replyAll": "ตอบกลับกระทู้",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"lists.subheading": "Danh sách của bạn",
|
"lists.subheading": "Danh sách của bạn",
|
||||||
"load_pending": "{count, plural, one {# tút mới} other {# tút mới}}",
|
"load_pending": "{count, plural, one {# tút mới} other {# tút mới}}",
|
||||||
"loading_indicator.label": "Đang tải…",
|
"loading_indicator.label": "Đang tải…",
|
||||||
|
"media_gallery.hide": "Ẩn",
|
||||||
"moved_to_account_banner.text": "Tài khoản {disabledAccount} của bạn hiện không khả dụng vì bạn đã chuyển sang {movedToAccount}.",
|
"moved_to_account_banner.text": "Tài khoản {disabledAccount} của bạn hiện không khả dụng vì bạn đã chuyển sang {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Ẩn thông báo",
|
"mute_modal.hide_from_notifications": "Ẩn thông báo",
|
||||||
"mute_modal.hide_options": "Tùy chọn ẩn",
|
"mute_modal.hide_options": "Tùy chọn ẩn",
|
||||||
|
@ -779,6 +780,7 @@
|
||||||
"status.bookmark": "Lưu",
|
"status.bookmark": "Lưu",
|
||||||
"status.cancel_reblog_private": "Hủy đăng lại",
|
"status.cancel_reblog_private": "Hủy đăng lại",
|
||||||
"status.cannot_reblog": "Không thể đăng lại tút này",
|
"status.cannot_reblog": "Không thể đăng lại tút này",
|
||||||
|
"status.continued_thread": "Tiếp tục trong chủ đề",
|
||||||
"status.copy": "Sao chép URL",
|
"status.copy": "Sao chép URL",
|
||||||
"status.delete": "Xóa",
|
"status.delete": "Xóa",
|
||||||
"status.detailed_status": "Xem chi tiết thêm",
|
"status.detailed_status": "Xem chi tiết thêm",
|
||||||
|
@ -787,6 +789,7 @@
|
||||||
"status.edit": "Sửa",
|
"status.edit": "Sửa",
|
||||||
"status.edited": "Sửa lần cuối {date}",
|
"status.edited": "Sửa lần cuối {date}",
|
||||||
"status.edited_x_times": "Đã sửa {count, plural, other {{count} lần}}",
|
"status.edited_x_times": "Đã sửa {count, plural, other {{count} lần}}",
|
||||||
|
"status.embed": "Lấy mã nhúng",
|
||||||
"status.favourite": "Thích",
|
"status.favourite": "Thích",
|
||||||
"status.favourites": "{count, plural, other {lượt thích}}",
|
"status.favourites": "{count, plural, other {lượt thích}}",
|
||||||
"status.filter": "Lọc tút này",
|
"status.filter": "Lọc tút này",
|
||||||
|
@ -811,6 +814,7 @@
|
||||||
"status.reblogs.empty": "Tút này chưa có ai đăng lại. Nếu có, nó sẽ hiển thị ở đây.",
|
"status.reblogs.empty": "Tút này chưa có ai đăng lại. Nếu có, nó sẽ hiển thị ở đây.",
|
||||||
"status.redraft": "Xóa và viết lại",
|
"status.redraft": "Xóa và viết lại",
|
||||||
"status.remove_bookmark": "Bỏ lưu",
|
"status.remove_bookmark": "Bỏ lưu",
|
||||||
|
"status.replied_in_thread": "Trả lời trong chủ đề",
|
||||||
"status.replied_to": "Trả lời {name}",
|
"status.replied_to": "Trả lời {name}",
|
||||||
"status.reply": "Trả lời",
|
"status.reply": "Trả lời",
|
||||||
"status.replyAll": "Trả lời",
|
"status.replyAll": "Trả lời",
|
||||||
|
|
19
app/javascript/mastodon/models/notification_request.ts
Normal file
19
app/javascript/mastodon/models/notification_request.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import type { ApiNotificationRequestJSON } from 'mastodon/api_types/notifications';
|
||||||
|
|
||||||
|
export interface NotificationRequest
|
||||||
|
extends Omit<ApiNotificationRequestJSON, 'account' | 'notifications_count'> {
|
||||||
|
account_id: string;
|
||||||
|
notifications_count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createNotificationRequestFromJSON(
|
||||||
|
requestJSON: ApiNotificationRequestJSON,
|
||||||
|
): NotificationRequest {
|
||||||
|
const { account, notifications_count, ...request } = requestJSON;
|
||||||
|
|
||||||
|
return {
|
||||||
|
account_id: account.id,
|
||||||
|
notifications_count: +notifications_count,
|
||||||
|
...request,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,114 +0,0 @@
|
||||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
|
||||||
|
|
||||||
import { blockAccountSuccess, muteAccountSuccess } from 'mastodon/actions/accounts';
|
|
||||||
import {
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_SUCCESS,
|
|
||||||
NOTIFICATION_REQUESTS_EXPAND_FAIL,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_SUCCESS,
|
|
||||||
NOTIFICATION_REQUESTS_FETCH_FAIL,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_REQUEST,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_SUCCESS,
|
|
||||||
NOTIFICATION_REQUEST_FETCH_FAIL,
|
|
||||||
NOTIFICATION_REQUEST_ACCEPT_REQUEST,
|
|
||||||
NOTIFICATION_REQUEST_DISMISS_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_ACCEPT_REQUEST,
|
|
||||||
NOTIFICATION_REQUESTS_DISMISS_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS,
|
|
||||||
NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL,
|
|
||||||
} from 'mastodon/actions/notifications';
|
|
||||||
|
|
||||||
import { notificationToMap } from './notifications';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
|
||||||
items: ImmutableList(),
|
|
||||||
isLoading: false,
|
|
||||||
next: null,
|
|
||||||
current: ImmutableMap({
|
|
||||||
isLoading: false,
|
|
||||||
item: null,
|
|
||||||
removed: false,
|
|
||||||
notifications: ImmutableMap({
|
|
||||||
items: ImmutableList(),
|
|
||||||
isLoading: false,
|
|
||||||
next: null,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const normalizeRequest = request => fromJS({
|
|
||||||
...request,
|
|
||||||
account: request.account.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeRequest = (state, id) => {
|
|
||||||
if (state.getIn(['current', 'item', 'id']) === id) {
|
|
||||||
state = state.setIn(['current', 'removed'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.update('items', list => list.filterNot(item => item.get('id') === id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeRequestByAccount = (state, account_id) => {
|
|
||||||
if (state.getIn(['current', 'item', 'account']) === account_id) {
|
|
||||||
state = state.setIn(['current', 'removed'], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.update('items', list => list.filterNot(item => item.get('account') === account_id));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const notificationRequestsReducer = (state = initialState, action) => {
|
|
||||||
switch(action.type) {
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_SUCCESS:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.update('items', list => ImmutableList(action.requests.map(normalizeRequest)).concat(list));
|
|
||||||
map.set('isLoading', false);
|
|
||||||
map.update('next', next => next ?? action.next);
|
|
||||||
});
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_SUCCESS:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.update('items', list => list.concat(ImmutableList(action.requests.map(normalizeRequest))));
|
|
||||||
map.set('isLoading', false);
|
|
||||||
map.set('next', action.next);
|
|
||||||
});
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_REQUEST:
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_REQUEST:
|
|
||||||
return state.set('isLoading', true);
|
|
||||||
case NOTIFICATION_REQUESTS_EXPAND_FAIL:
|
|
||||||
case NOTIFICATION_REQUESTS_FETCH_FAIL:
|
|
||||||
return state.set('isLoading', false);
|
|
||||||
case NOTIFICATION_REQUEST_ACCEPT_REQUEST:
|
|
||||||
case NOTIFICATION_REQUEST_DISMISS_REQUEST:
|
|
||||||
return removeRequest(state, action.id);
|
|
||||||
case NOTIFICATION_REQUESTS_ACCEPT_REQUEST:
|
|
||||||
case NOTIFICATION_REQUESTS_DISMISS_REQUEST:
|
|
||||||
return action.ids.reduce((state, id) => removeRequest(state, id), state);
|
|
||||||
case blockAccountSuccess.type:
|
|
||||||
return removeRequestByAccount(state, action.payload.relationship.id);
|
|
||||||
case muteAccountSuccess.type:
|
|
||||||
return action.payload.relationship.muting_notifications ? removeRequestByAccount(state, action.payload.relationship.id) : state;
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_REQUEST:
|
|
||||||
return state.set('current', initialState.get('current').set('isLoading', true));
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_SUCCESS:
|
|
||||||
return state.update('current', map => map.set('isLoading', false).set('item', normalizeRequest(action.request)));
|
|
||||||
case NOTIFICATION_REQUEST_FETCH_FAIL:
|
|
||||||
return state.update('current', map => map.set('isLoading', false));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST:
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_REQUEST:
|
|
||||||
return state.setIn(['current', 'notifications', 'isLoading'], true);
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS:
|
|
||||||
return state.updateIn(['current', 'notifications'], map => map.set('isLoading', false).update('items', list => ImmutableList(action.notifications.map(notificationToMap)).concat(list)).update('next', next => next ?? action.next));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_SUCCESS:
|
|
||||||
return state.updateIn(['current', 'notifications'], map => map.set('isLoading', false).update('items', list => list.concat(ImmutableList(action.notifications.map(notificationToMap)))).set('next', action.next));
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL:
|
|
||||||
case NOTIFICATIONS_FOR_REQUEST_EXPAND_FAIL:
|
|
||||||
return state.setIn(['current', 'notifications', 'isLoading'], false);
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
182
app/javascript/mastodon/reducers/notification_requests.ts
Normal file
182
app/javascript/mastodon/reducers/notification_requests.ts
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
import { createReducer, isAnyOf } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
import {
|
||||||
|
blockAccountSuccess,
|
||||||
|
muteAccountSuccess,
|
||||||
|
} from 'mastodon/actions/accounts';
|
||||||
|
import {
|
||||||
|
fetchNotificationRequests,
|
||||||
|
expandNotificationRequests,
|
||||||
|
fetchNotificationRequest,
|
||||||
|
fetchNotificationsForRequest,
|
||||||
|
expandNotificationsForRequest,
|
||||||
|
acceptNotificationRequest,
|
||||||
|
dismissNotificationRequest,
|
||||||
|
acceptNotificationRequests,
|
||||||
|
dismissNotificationRequests,
|
||||||
|
} from 'mastodon/actions/notification_requests';
|
||||||
|
import type { NotificationRequest } from 'mastodon/models/notification_request';
|
||||||
|
import { createNotificationRequestFromJSON } from 'mastodon/models/notification_request';
|
||||||
|
|
||||||
|
import { notificationToMap } from './notifications';
|
||||||
|
|
||||||
|
interface NotificationsListState {
|
||||||
|
items: unknown[]; // TODO
|
||||||
|
isLoading: boolean;
|
||||||
|
next: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CurrentNotificationRequestState {
|
||||||
|
item: NotificationRequest | null;
|
||||||
|
isLoading: boolean;
|
||||||
|
removed: boolean;
|
||||||
|
notifications: NotificationsListState;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NotificationRequestsState {
|
||||||
|
items: NotificationRequest[];
|
||||||
|
isLoading: boolean;
|
||||||
|
next: string | null;
|
||||||
|
current: CurrentNotificationRequestState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: NotificationRequestsState = {
|
||||||
|
items: [],
|
||||||
|
isLoading: false,
|
||||||
|
next: null,
|
||||||
|
current: {
|
||||||
|
item: null,
|
||||||
|
isLoading: false,
|
||||||
|
removed: false,
|
||||||
|
notifications: {
|
||||||
|
isLoading: false,
|
||||||
|
items: [],
|
||||||
|
next: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRequest = (state: NotificationRequestsState, id: string) => {
|
||||||
|
if (state.current.item?.id === id) {
|
||||||
|
state.current.removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.items = state.items.filter((item) => item.id !== id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRequestByAccount = (
|
||||||
|
state: NotificationRequestsState,
|
||||||
|
account_id: string,
|
||||||
|
) => {
|
||||||
|
if (state.current.item?.account_id === account_id) {
|
||||||
|
state.current.removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.items = state.items.filter((item) => item.account_id !== account_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const notificationRequestsReducer =
|
||||||
|
createReducer<NotificationRequestsState>(initialState, (builder) => {
|
||||||
|
builder
|
||||||
|
.addCase(fetchNotificationRequests.fulfilled, (state, action) => {
|
||||||
|
state.items = action.payload.requests
|
||||||
|
.map(createNotificationRequestFromJSON)
|
||||||
|
.concat(state.items);
|
||||||
|
state.isLoading = false;
|
||||||
|
state.next ??= action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(expandNotificationRequests.fulfilled, (state, action) => {
|
||||||
|
state.items = state.items.concat(
|
||||||
|
action.payload.requests.map(createNotificationRequestFromJSON),
|
||||||
|
);
|
||||||
|
state.isLoading = false;
|
||||||
|
state.next = action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(blockAccountSuccess, (state, action) => {
|
||||||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||||||
|
})
|
||||||
|
.addCase(muteAccountSuccess, (state, action) => {
|
||||||
|
if (action.payload.relationship.muting_notifications)
|
||||||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.pending, (state) => {
|
||||||
|
state.current = { ...initialState.current, isLoading: true };
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.rejected, (state) => {
|
||||||
|
state.current.isLoading = false;
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.isLoading = false;
|
||||||
|
state.current.item = createNotificationRequestFromJSON(action.payload);
|
||||||
|
})
|
||||||
|
.addCase(fetchNotificationsForRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
state.current.notifications.items.unshift(
|
||||||
|
...action.payload.notifications.map(notificationToMap),
|
||||||
|
);
|
||||||
|
state.current.notifications.next ??= action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addCase(expandNotificationsForRequest.fulfilled, (state, action) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
state.current.notifications.items.push(
|
||||||
|
...action.payload.notifications.map(notificationToMap),
|
||||||
|
);
|
||||||
|
state.current.notifications.next = action.payload.next ?? null;
|
||||||
|
})
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationRequests.pending,
|
||||||
|
expandNotificationRequests.pending,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.isLoading = true;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationRequests.rejected,
|
||||||
|
expandNotificationRequests.rejected,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.isLoading = false;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
acceptNotificationRequest.pending,
|
||||||
|
dismissNotificationRequest.pending,
|
||||||
|
),
|
||||||
|
(state, action) => {
|
||||||
|
removeRequest(state, action.meta.arg.id);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
acceptNotificationRequests.pending,
|
||||||
|
dismissNotificationRequests.pending,
|
||||||
|
),
|
||||||
|
(state, action) => {
|
||||||
|
action.meta.arg.ids.forEach((id) => {
|
||||||
|
removeRequest(state, id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationsForRequest.pending,
|
||||||
|
expandNotificationsForRequest.pending,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.current.notifications.isLoading = true;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.addMatcher(
|
||||||
|
isAnyOf(
|
||||||
|
fetchNotificationsForRequest.rejected,
|
||||||
|
expandNotificationsForRequest.rejected,
|
||||||
|
),
|
||||||
|
(state) => {
|
||||||
|
state.current.notifications.isLoading = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
|
@ -33,8 +33,12 @@ interface AppThunkConfig {
|
||||||
}
|
}
|
||||||
type AppThunkApi = Pick<GetThunkAPI<AppThunkConfig>, 'getState' | 'dispatch'>;
|
type AppThunkApi = Pick<GetThunkAPI<AppThunkConfig>, 'getState' | 'dispatch'>;
|
||||||
|
|
||||||
interface AppThunkOptions {
|
interface AppThunkOptions<Arg> {
|
||||||
useLoadingBar?: boolean;
|
useLoadingBar?: boolean;
|
||||||
|
condition?: (
|
||||||
|
arg: Arg,
|
||||||
|
{ getState }: { getState: AppThunkApi['getState'] },
|
||||||
|
) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
||||||
|
@ -42,7 +46,7 @@ const createBaseAsyncThunk = createAsyncThunk.withTypes<AppThunkConfig>();
|
||||||
export function createThunk<Arg = void, Returned = void>(
|
export function createThunk<Arg = void, Returned = void>(
|
||||||
name: string,
|
name: string,
|
||||||
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
||||||
options: AppThunkOptions = {},
|
options: AppThunkOptions<Arg> = {},
|
||||||
) {
|
) {
|
||||||
return createBaseAsyncThunk(
|
return createBaseAsyncThunk(
|
||||||
name,
|
name,
|
||||||
|
@ -70,6 +74,7 @@ export function createThunk<Arg = void, Returned = void>(
|
||||||
if (options.useLoadingBar) return { useLoadingBar: true };
|
if (options.useLoadingBar) return { useLoadingBar: true };
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
condition: options.condition,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +101,7 @@ type ArgsType = Record<string, unknown> | undefined;
|
||||||
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||||
|
|
||||||
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
||||||
|
@ -104,17 +109,19 @@ export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, DiscardLoadData>,
|
| OnData<Args, LoadDataResult, DiscardLoadData>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, void>>;
|
): ReturnType<typeof createThunk<Args, void>>;
|
||||||
|
|
||||||
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
||||||
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
export function createDataLoadingThunk<LoadDataResult, Args extends ArgsType>(
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?: AppThunkOptions | OnData<Args, LoadDataResult, void>,
|
onDataOrThunkOptions?:
|
||||||
thunkOptions?: AppThunkOptions,
|
| AppThunkOptions<Args>
|
||||||
|
| OnData<Args, LoadDataResult, void>,
|
||||||
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||||
|
|
||||||
// Overload when there is an `onData` method returning something
|
// Overload when there is an `onData` method returning something
|
||||||
|
@ -126,9 +133,9 @@ export function createDataLoadingThunk<
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, Returned>,
|
| OnData<Args, LoadDataResult, Returned>,
|
||||||
thunkOptions?: AppThunkOptions,
|
thunkOptions?: AppThunkOptions<Args>,
|
||||||
): ReturnType<typeof createThunk<Args, Returned>>;
|
): ReturnType<typeof createThunk<Args, Returned>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,6 +161,7 @@ export function createDataLoadingThunk<
|
||||||
* @param maybeThunkOptions
|
* @param maybeThunkOptions
|
||||||
* Additional Mastodon specific options for the thunk. Currently supports:
|
* Additional Mastodon specific options for the thunk. Currently supports:
|
||||||
* - `useLoadingBar` to display a loading bar while this action is pending. Defaults to true.
|
* - `useLoadingBar` to display a loading bar while this action is pending. Defaults to true.
|
||||||
|
* - `condition` is passed to `createAsyncThunk` (https://redux-toolkit.js.org/api/createAsyncThunk#canceling-before-execution)
|
||||||
* @returns The created thunk
|
* @returns The created thunk
|
||||||
*/
|
*/
|
||||||
export function createDataLoadingThunk<
|
export function createDataLoadingThunk<
|
||||||
|
@ -164,12 +172,12 @@ export function createDataLoadingThunk<
|
||||||
name: string,
|
name: string,
|
||||||
loadData: LoadData<Args, LoadDataResult>,
|
loadData: LoadData<Args, LoadDataResult>,
|
||||||
onDataOrThunkOptions?:
|
onDataOrThunkOptions?:
|
||||||
| AppThunkOptions
|
| AppThunkOptions<Args>
|
||||||
| OnData<Args, LoadDataResult, Returned>,
|
| OnData<Args, LoadDataResult, Returned>,
|
||||||
maybeThunkOptions?: AppThunkOptions,
|
maybeThunkOptions?: AppThunkOptions<Args>,
|
||||||
) {
|
) {
|
||||||
let onData: OnData<Args, LoadDataResult, Returned> | undefined;
|
let onData: OnData<Args, LoadDataResult, Returned> | undefined;
|
||||||
let thunkOptions: AppThunkOptions | undefined;
|
let thunkOptions: AppThunkOptions<Args> | undefined;
|
||||||
|
|
||||||
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
||||||
else if (typeof onDataOrThunkOptions === 'object')
|
else if (typeof onDataOrThunkOptions === 'object')
|
||||||
|
@ -203,6 +211,9 @@ export function createDataLoadingThunk<
|
||||||
return undefined as Returned;
|
return undefined as Returned;
|
||||||
else return result;
|
else return result;
|
||||||
},
|
},
|
||||||
{ useLoadingBar: thunkOptions?.useLoadingBar ?? true },
|
{
|
||||||
|
useLoadingBar: thunkOptions?.useLoadingBar ?? true,
|
||||||
|
condition: thunkOptions?.condition,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10234,6 +10234,7 @@ noscript {
|
||||||
scroll-padding: 16px;
|
scroll-padding: 16px;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
&__card {
|
&__card {
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
|
|
|
@ -26,6 +26,7 @@ class CustomEmoji < ApplicationRecord
|
||||||
|
|
||||||
LOCAL_LIMIT = (ENV['MAX_EMOJI_SIZE'] || 256.kilobytes).to_i
|
LOCAL_LIMIT = (ENV['MAX_EMOJI_SIZE'] || 256.kilobytes).to_i
|
||||||
LIMIT = [LOCAL_LIMIT, (ENV['MAX_REMOTE_EMOJI_SIZE'] || 256.kilobytes).to_i].max
|
LIMIT = [LOCAL_LIMIT, (ENV['MAX_REMOTE_EMOJI_SIZE'] || 256.kilobytes).to_i].max
|
||||||
|
MINIMUM_SHORTCODE_SIZE = 2
|
||||||
|
|
||||||
SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'
|
SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ class CustomEmoji < ApplicationRecord
|
||||||
validates_attachment :image, content_type: { content_type: IMAGE_MIME_TYPES }, presence: true
|
validates_attachment :image, content_type: { content_type: IMAGE_MIME_TYPES }, presence: true
|
||||||
validates_attachment_size :image, less_than: LIMIT, unless: :local?
|
validates_attachment_size :image, less_than: LIMIT, unless: :local?
|
||||||
validates_attachment_size :image, less_than: LOCAL_LIMIT, if: :local?
|
validates_attachment_size :image, less_than: LOCAL_LIMIT, if: :local?
|
||||||
validates :shortcode, uniqueness: { scope: :domain }, format: { with: SHORTCODE_ONLY_RE }, length: { minimum: 2 }
|
validates :shortcode, uniqueness: { scope: :domain }, format: { with: SHORTCODE_ONLY_RE }, length: { minimum: MINIMUM_SHORTCODE_SIZE }
|
||||||
|
|
||||||
scope :local, -> { where(domain: nil) }
|
scope :local, -> { where(domain: nil) }
|
||||||
scope :remote, -> { where.not(domain: nil) }
|
scope :remote, -> { where.not(domain: nil) }
|
||||||
|
|
|
@ -39,7 +39,7 @@ class PreviewCard < ApplicationRecord
|
||||||
include Attachmentable
|
include Attachmentable
|
||||||
|
|
||||||
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
|
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
|
||||||
LIMIT = 2.megabytes
|
LIMIT = Rails.configuration.x.use_vips ? 8.megabytes : 2.megabytes
|
||||||
|
|
||||||
BLURHASH_OPTIONS = {
|
BLURHASH_OPTIONS = {
|
||||||
x_comp: 4,
|
x_comp: 4,
|
||||||
|
|
|
@ -109,9 +109,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_versions
|
def api_versions
|
||||||
{
|
Mastodon::Version.api_versions
|
||||||
mastodon: 1,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
4
config/initializers/regexp.rb
Normal file
4
config/initializers/regexp.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# 0.5s is a fairly high timeout, but that should account for slow servers under load
|
||||||
|
Regexp.timeout = 0.5 if Regexp.respond_to?(:timeout=)
|
|
@ -15,6 +15,12 @@ et:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Põhjus
|
text: Põhjus
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: pole kehtiv domeeninimi
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} ei ole kehtiv domeeninimi"
|
||||||
|
too_many_lines: on üle limiidi %{limit} rida
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -18,6 +18,9 @@ fr-CA:
|
||||||
attributes:
|
attributes:
|
||||||
domain:
|
domain:
|
||||||
invalid: n'est pas un nom de domaine valide
|
invalid: n'est pas un nom de domaine valide
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} n'est pas un nom de domaine valide"
|
||||||
|
too_many_lines: dépasse la limite de %{limit} lignes
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -18,6 +18,9 @@ fr:
|
||||||
attributes:
|
attributes:
|
||||||
domain:
|
domain:
|
||||||
invalid: n'est pas un nom de domaine valide
|
invalid: n'est pas un nom de domaine valide
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} n'est pas un nom de domaine valide"
|
||||||
|
too_many_lines: dépasse la limite de %{limit} lignes
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -15,6 +15,12 @@ ga:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Fáth
|
text: Fáth
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: nach ainm fearainn bailí é
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: Ní ainm fearainn bailí é %{value}
|
||||||
|
too_many_lines: thar an teorainn de %{limit} línte
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -15,6 +15,12 @@ gd:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Adhbhar
|
text: Adhbhar
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: "– chan eil seo ’na ainm àrainne dligheach"
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: Chan eil %{value} ’na ainm àrainne dligheach
|
||||||
|
too_many_lines: "– tha seo thar crìoch de %{limit} nan loidhnichean"
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -11,15 +11,21 @@ ro:
|
||||||
locale: Localizare
|
locale: Localizare
|
||||||
password: Parolă
|
password: Parolă
|
||||||
user/account:
|
user/account:
|
||||||
username: Nume utilizator
|
username: Nume de utilizator
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Motiv
|
text: Motiv
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: nu este un nume de domeniu valid
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} nu este un nume de domeniu valid"
|
||||||
|
too_many_lines: este peste limita de %{limit} linii
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
username:
|
username:
|
||||||
invalid: doar litere, numere și sublinieri
|
invalid: trebuie să conțină numai litere, cifre și bară jos (_)
|
||||||
reserved: este rezervat
|
reserved: este rezervat
|
||||||
admin/webhook:
|
admin/webhook:
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -56,4 +62,4 @@ ro:
|
||||||
webhook:
|
webhook:
|
||||||
attributes:
|
attributes:
|
||||||
events:
|
events:
|
||||||
invalid_permissions: nu poate include evenimente la care nu aveți drepturi
|
invalid_permissions: nu poate include evenimente la care nu aveți dreptul
|
||||||
|
|
|
@ -15,6 +15,12 @@ th:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: เหตุผล
|
text: เหตุผล
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: ไม่ใช่ชื่อโดเมนที่ถูกต้อง
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} ไม่ใช่ชื่อโดเมนที่ถูกต้อง"
|
||||||
|
too_many_lines: เกินขีดจำกัด %{limit} บรรทัด
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -15,6 +15,12 @@ vi:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Lý do
|
text: Lý do
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: không phải là một tên miền hợp lệ
|
||||||
|
messages:
|
||||||
|
invalid_domain_on_line: "%{value} không phải là một tên miền hợp lệ"
|
||||||
|
too_many_lines: vượt quá giới hạn %{limit} dòng
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -14,9 +14,9 @@ lv:
|
||||||
not_found_in_database: Nederīga %{authentication_keys} vai parole.
|
not_found_in_database: Nederīga %{authentication_keys} vai parole.
|
||||||
omniauth_user_creation_failure: Kļūda šīs identitātes konta izveidošanā.
|
omniauth_user_creation_failure: Kļūda šīs identitātes konta izveidošanā.
|
||||||
pending: Tavs konts joprojām tiek pārskatīts.
|
pending: Tavs konts joprojām tiek pārskatīts.
|
||||||
timeout: Tava sesija ir beigusies. Lūdzu, pieraksties vēlreiz, lai turpinātu.
|
timeout: Sesijair beigusies. Lūgums vēlreiz pieteikties, lai turpinātu.
|
||||||
unauthenticated: Lai turpinātu, tev ir jāpierakstās vai jāreģistrējas.
|
unauthenticated: Lai turpinātu, jāpiesakās vai jāreģistrējas.
|
||||||
unconfirmed: Lai turpinātu, tev ir jāapstiprina savu e-pasta adresi.
|
unconfirmed: Lai turpinātu, jāapliecina sava e-pasta adrese.
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
action: Apstiprini savu e-pasta adresi
|
action: Apstiprini savu e-pasta adresi
|
||||||
|
@ -108,7 +108,7 @@ lv:
|
||||||
unlocks:
|
unlocks:
|
||||||
send_instructions: Pēc dažām minūtēm tu saņemsi e-pastu ar norādījumiem, kā atbloķēt savu kontu. Lūdzu, pārbaudi spama mapi, ja neesi saņēmis šo e-pastu.
|
send_instructions: Pēc dažām minūtēm tu saņemsi e-pastu ar norādījumiem, kā atbloķēt savu kontu. Lūdzu, pārbaudi spama mapi, ja neesi saņēmis šo e-pastu.
|
||||||
send_paranoid_instructions: Ja tavs konts eksistē, dažu minūšu laikā tu saņemsi e-pastu ar norādījumiem, kā to atbloķēt. Lūdzu, pārbaudi spama mapi, ja neesi saņēmis šo e-pastu.
|
send_paranoid_instructions: Ja tavs konts eksistē, dažu minūšu laikā tu saņemsi e-pastu ar norādījumiem, kā to atbloķēt. Lūdzu, pārbaudi spama mapi, ja neesi saņēmis šo e-pastu.
|
||||||
unlocked: Tavs konts ir veiksmīgi atbloķēts. Lūdzu, pieraksties, lai turpinātu.
|
unlocked: Konts tika veiksmīgi atbloķēts. Lūgums pieteikties, lai turpinātu.
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
already_confirmed: jau tika apstiprināts, lūdzu, mēģini pierakstīties
|
already_confirmed: jau tika apstiprināts, lūdzu, mēģini pierakstīties
|
||||||
|
|
|
@ -2,58 +2,58 @@
|
||||||
ro:
|
ro:
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Adresa ta de e-mail a fost confirmată cu succes.
|
confirmed: Adresa dvs. de e-mail a fost confirmată cu succes.
|
||||||
send_instructions: Vei primi un e-mail cu instrucțiuni despre cum să confirmi adresa ta de e-mail în câteva minute. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_instructions: Veți primi un e-mail în câteva minute cu instrucțiuni despre cum să vă confirmați adresa de e-mail. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
send_paranoid_instructions: Dacă adresa ta de e-mail există în baza noastră de date, în câteva minute vei primi un e-mail cu instrucțiuni pentru confirmarea adresei tale de e-mail. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_paranoid_instructions: Dacă adresa dvs. de e-mail există în baza noastră de date, veți primi în câteva minute un e-mail cu instrucțiuni pentru confirmarea adresei de e-mail. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
failure:
|
failure:
|
||||||
already_authenticated: Ești deja conectat.
|
already_authenticated: Sunteți deja conectat.
|
||||||
inactive: Contul tău nu este încă activat.
|
inactive: Contul dvs. nu este încă activat.
|
||||||
invalid: "%{authentication_keys} sau parolă greșită."
|
invalid: "%{authentication_keys} sau parolă greșită."
|
||||||
last_attempt: Mai ai încă o încercare înainte ca contul tău să fie blocat.
|
last_attempt: Mai aveți o încercare înainte ca contul dvs. să fie blocat.
|
||||||
locked: Contul tău este blocat.
|
locked: Contul dvs. este blocat.
|
||||||
not_found_in_database: "%{authentication_keys} sau parolă greșită."
|
not_found_in_database: "%{authentication_keys} sau parolă greșită."
|
||||||
omniauth_user_creation_failure: Eroare la crearea unui cont pentru această identitate.
|
omniauth_user_creation_failure: Eroare la crearea unui cont pentru această identitate.
|
||||||
pending: Contul tău este încă în curs de revizuire.
|
pending: Contul dvs. este încă în curs de revizuire.
|
||||||
timeout: Sesiunea ta a expirat. Te rugăm să te conectezi din nou pentru a continua.
|
timeout: Sesiunea dvs. a expirat. Vă rugăm să vă conectați din nou pentru a continua.
|
||||||
unauthenticated: Trebuie să te conectezi sau să te înregistrezi înainte de a continua.
|
unauthenticated: Trebuie să vă conectați sau să vă înregistrați înainte de a continua.
|
||||||
unconfirmed: Trebuie să confirmi adresa ta de e-mail înainte de a continua.
|
unconfirmed: Trebuie să vă confirmați adresa de e-mail înainte de a continua.
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
action: Verifică adresa de e-mail
|
action: Verificare adresă de e-mail
|
||||||
action_with_app: Confirmați și reveniți la %{app}
|
action_with_app: Confirmați și reveniți la %{app}
|
||||||
explanation: Ai creat un cont pe %{host} cu această adresă de e-mail. Ești la un clic distanță de a-l activa. Dacă nu ai fost tu, ignoră acest e-mail.
|
explanation: Ați creat un cont pe %{host} cu această adresă de e-mail. Sunteți la un clic distanță de a-l activa. Dacă nu ați fost dvs., vă rugăm să ignorați acest e-mail.
|
||||||
explanation_when_pending: Ai solicitat o invitație către %{host} cu această adresă de e-mail. Odată ce îți confirmi adresa de e-mail, îți vom revizui cererea. Te poți autentifica pentru a-ți schimba detaliile sau pentru a-ți șterge contul, dar nu poți accesa majoritatea funcțiilor până când contul tău nu este aprobat. Dacă cererea ta este respinsă, datele tale vor fi șterse, astfel încât nu va fi necesară nicio altă acțiune din partea ta. Dacă nu ai fost tu, ignoră acest e-mail.
|
explanation_when_pending: Ați aplicat pentru o invitație pentru %{host} cu această adresă de e-mail. Odată ce vă confirmați adresa de e-mail, vă vom examina cererea. Vă puteți autentifica pentru a vă schimba detaliile sau pentru a vă șterge contul, dar nu puteți accesa majoritatea funcțiilor până când contul dvs. nu este aprobat. Dacă cererea dvs. este respinsă, datele dvs. vor fi șterse, astfel încât nu va fi necesară nicio acțiune suplimentară din partea dvs. Dacă nu ați fost dvs., vă rugăm să ignorați acest e-mail.
|
||||||
extra_html: Te rugăm să verifici și <a href="%{terms_path}">regulile serverului</a> și <a href="%{policy_path}">termenii noștri de serviciu</a>.
|
extra_html: Te rugăm să verifici și <a href="%{terms_path}">regulile serverului</a> și <a href="%{policy_path}">termenii noștri de serviciu</a>.
|
||||||
subject: 'Mastodon: Instrucțiuni de confirmare pentru %{instance}'
|
subject: 'Mastodon: Instrucțiuni de confirmare pentru %{instance}'
|
||||||
title: Verifică adresa de e-mail
|
title: Verificați adresa de e-mail
|
||||||
email_changed:
|
email_changed:
|
||||||
explanation: 'Adresa de e-mail pentru contul tău este schimbată la:'
|
explanation: 'Adresa de e-mail a contului dvs. este schimbată în:'
|
||||||
extra: Dacă nu v-ați schimbat adresa de e-mail, probabil că cineva a obținut acces la contul dvs. Te rugăm să îți schimbi parola imediat sau să contactezi administratorul serverului dacă nu ai acces la contul tău.
|
extra: Dacă nu v-ați schimbat adresa de e-mail, probabil că cineva a obținut acces la contul dvs. Vă rugăm să vă schimbați parola imediat sau să contactați administratorul serverului dacă nu aveți acces la contul dvs.
|
||||||
subject: 'Mastodon: E-mail schimbat'
|
subject: 'Mastodon: Adresă de e-mail schimbată'
|
||||||
title: Noua adresa de e-mail
|
title: Adresă de e-mail nouă
|
||||||
password_change:
|
password_change:
|
||||||
explanation: Parola contului tău a fost schimbată.
|
explanation: Parola pentru contul dvs. a fost schimbată.
|
||||||
extra: Dacă nu v-ați schimbat parola, este posibil ca cineva să fi obținut acces la contul dvs. Te rugăm să îți schimbi parola imediat sau să contactezi administratorul serverului dacă nu ai acces la contul tău.
|
extra: Dacă nu v-ați schimbat parola, probabil că cineva a obținut acces la contul dvs. Vă rugăm să vă schimbați parola imediat sau să contactați administratorul serverului dacă nu aveți acces la contul dvs.
|
||||||
subject: 'Mastodon: Parolă schimbată'
|
subject: 'Mastodon: Parolă schimbată'
|
||||||
title: Parolă schimbată
|
title: Parolă schimbată
|
||||||
reconfirmation_instructions:
|
reconfirmation_instructions:
|
||||||
explanation: Confirmă noua adresă pentru a schimba adresa de e-mail.
|
explanation: Confirmați noua adresă pentru a vă schimba adresa de e-mail.
|
||||||
extra: Dacă această modificare nu a fost inițiată de dvs., vă rugăm să ignorați acest e-mail. Adresa de e-mail pentru contul Mastodon nu se va schimba până când nu accesați link-ul de mai sus.
|
extra: Dacă această modificare nu a fost inițiată de dvs., vă rugăm să ignorați acest e-mail. Adresa de e-mail pentru contul Mastodon nu se va schimba până când nu accesați link-ul de mai sus.
|
||||||
subject: 'Mastodon: Confirmați e-mailul pentru %{instance}'
|
subject: 'Mastodon: Confirmați e-mailul pentru %{instance}'
|
||||||
title: Verifică adresa de e-mail
|
title: Verificați adresa de e-mail
|
||||||
reset_password_instructions:
|
reset_password_instructions:
|
||||||
action: Schimbă parola
|
action: Schimbați parola
|
||||||
explanation: Ați solicitat o nouă parolă pentru contul dvs.
|
explanation: Ați solicitat o nouă parolă pentru contul dvs.
|
||||||
extra: Dacă nu ați solicitat acest lucru, ignorați acest e-mail. Parola dvs. nu se va schimba până când nu veți accesa link-ul de mai sus și nu veți crea unul nou.
|
extra: Dacă nu ați solicitat acest lucru, vă rugăm să ignorați acest e-mail. Parola dvs. nu se va schimba până când nu veți accesa link-ul de mai sus și nu veți crea unul nou.
|
||||||
subject: 'Mastodon: Instrucțiuni pentru resetarea parolei'
|
subject: 'Mastodon: Instrucțiuni pentru resetarea parolei'
|
||||||
title: Resetare parolă
|
title: Resetare parolă
|
||||||
two_factor_disabled:
|
two_factor_disabled:
|
||||||
explanation: Conectarea este acum posibilă folosind doar adresa de e-mail și parola.
|
explanation: Conectarea este acum posibilă folosind doar adresa de e-mail și parola.
|
||||||
subject: 'Mastodon: Autentificare cu doi factori dezactivată'
|
subject: 'Mastodon: Autentificarea cu doi factori dezactivată'
|
||||||
subtitle: Autentificarea cu doi factori pentru contul dvs. a fost dezactivată.
|
subtitle: Autentificarea cu doi factori pentru contul dvs. a fost dezactivată.
|
||||||
title: A2F dezactivată
|
title: A2F dezactivată
|
||||||
two_factor_enabled:
|
two_factor_enabled:
|
||||||
explanation: Pentru autentificare va fi necesar un token generat de aplicația TOTP asociată.
|
explanation: Pentru conectare va fi necesar un token generat de aplicația TOTP asociată.
|
||||||
subject: 'Mastodon: Autentificare în doi pași activată'
|
subject: 'Mastodon: Autentificare în doi pași activată'
|
||||||
subtitle: Autentificarea cu doi factori a fost activată pentru contul dvs.
|
subtitle: Autentificarea cu doi factori a fost activată pentru contul dvs.
|
||||||
title: A2F activată
|
title: A2F activată
|
||||||
|
@ -61,18 +61,18 @@ ro:
|
||||||
explanation: Codurile de recuperare anterioare au fost invalidate și s-au generat altele noi.
|
explanation: Codurile de recuperare anterioare au fost invalidate și s-au generat altele noi.
|
||||||
subject: 'Mastodon: Coduri de recuperare în doi pași regenerate'
|
subject: 'Mastodon: Coduri de recuperare în doi pași regenerate'
|
||||||
subtitle: Codurile de recuperare anterioare au fost invalidate și s-au generat altele noi.
|
subtitle: Codurile de recuperare anterioare au fost invalidate și s-au generat altele noi.
|
||||||
title: Codurile de recuperare în doi pași au fost modificate
|
title: Codurile de recuperare în doi pași modificate
|
||||||
unlock_instructions:
|
unlock_instructions:
|
||||||
subject: 'Mastodon: Instrucțiuni de deblocare'
|
subject: 'Mastodon: Instrucțiuni de deblocare'
|
||||||
webauthn_credential:
|
webauthn_credential:
|
||||||
added:
|
added:
|
||||||
explanation: Următoarea cheie de securitate a fost adăugată în contul tău
|
explanation: Următoarea cheie de securitate a fost adăugată în contul dvs.
|
||||||
subject: 'Mastodon: Noua cheie de securitate'
|
subject: 'Mastodon: Noua cheie de securitate'
|
||||||
title: A fost adăugată o nouă cheie de securitate
|
title: A fost adăugată o nouă cheie de securitate
|
||||||
deleted:
|
deleted:
|
||||||
explanation: Următoarea cheie de securitate a fost ștearsă din contul tău
|
explanation: Următoarea cheie de securitate a fost ștearsă din contul dvs.
|
||||||
subject: 'Mastodon: Cheie de securitate ștearsă'
|
subject: 'Mastodon: Cheie de securitate ștearsă'
|
||||||
title: Una dintre cheile tale de securitate a fost ștearsă
|
title: Una dintre cheile dvs. de securitate a fost ștearsă
|
||||||
webauthn_disabled:
|
webauthn_disabled:
|
||||||
explanation: Autentificarea cu chei de securitate a fost dezactivată pentru contul dvs.
|
explanation: Autentificarea cu chei de securitate a fost dezactivată pentru contul dvs.
|
||||||
extra: Conectarea este acum posibilă folosind doar token-ul generat de aplicația TOTP asociată.
|
extra: Conectarea este acum posibilă folosind doar token-ul generat de aplicația TOTP asociată.
|
||||||
|
@ -84,31 +84,31 @@ ro:
|
||||||
subject: 'Mastodon: Autentificarea prin chei de securitate activată'
|
subject: 'Mastodon: Autentificarea prin chei de securitate activată'
|
||||||
title: Chei de securitate activate
|
title: Chei de securitate activate
|
||||||
omniauth_callbacks:
|
omniauth_callbacks:
|
||||||
failure: Nu te-am putut autentifica de la %{kind} deoarece "%{reason}".
|
failure: Nu v-am putut autentifica de la %{kind} deoarece "%{reason}".
|
||||||
success: Autentificat cu succes din contul %{kind}.
|
success: Autentificat cu succes din contul %{kind}.
|
||||||
passwords:
|
passwords:
|
||||||
no_token: Nu puteți accesa această pagină fără să veniți dintr-un e-mail de resetare a parolei. Dacă vii dintr-un e-mail de resetare a parolei, te rugăm să te asiguri că ai folosit URL-ul complet furnizat.
|
no_token: Nu puteți accesa această pagină fără să veniți dintr-un e-mail de resetare a parolei. Dacă veniți dintr-un e-mail de resetare a parolei, vă rugăm asigurați-vă că ați folosit URL-ul complet furnizat.
|
||||||
send_instructions: Dacă adresa ta de e-mail există în baza noastră de date, vei primi în câteva minute un link de recuperare a parolei la adresa ta de e-mail. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_instructions: Dacă adresa dvs. de e-mail există în baza noastră de date, veți primi în câteva minute un link de recuperare a parolei la adresa dvs. de e-mail. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
send_paranoid_instructions: Dacă adresa ta de e-mail există în baza noastră de date, vei primi în câteva minute un link de recuperare a parolei la adresa ta de e-mail. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_paranoid_instructions: Dacă adresa dvs. de e-mail există în baza noastră de date, veți primi în câteva minute un link de recuperare a parolei la adresa dvs. de e-mail. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
updated: Parola ta a fost schimbată cu succes. Acum ești conectat.
|
updated: Parola dvs. a fost schimbată cu succes. Acum sunteți conectat.
|
||||||
updated_not_active: Parola ta a fost schimbată cu succes.
|
updated_not_active: Parola dvs. a fost schimbată cu succes.
|
||||||
registrations:
|
registrations:
|
||||||
destroyed: La revedere! Contul tău a fost anulat cu succes. Sperăm să te vedem din nou în curând.
|
destroyed: La revedere! Contul dvs. a fost anulat cu succes. Sperăm să vă vedem din nou în curând.
|
||||||
signed_up: Bine ați venit! V-ați înregistrat cu succes.
|
signed_up: Bine ați venit! V-ați înregistrat cu succes.
|
||||||
signed_up_but_inactive: V-ați înregistrat cu succes. Cu toate acestea, nu vă putem conecta deoarece contul dvs. nu este încă activat.
|
signed_up_but_inactive: V-ați înregistrat cu succes. Cu toate acestea, nu vă putem conecta deoarece contul dvs. nu este încă activat.
|
||||||
signed_up_but_locked: V-ați înregistrat cu succes. Cu toate acestea, nu vă putem conecta deoarece contul dvs. este blocat.
|
signed_up_but_locked: V-ați înregistrat cu succes. Cu toate acestea, nu vă putem conecta deoarece contul dvs. este blocat.
|
||||||
signed_up_but_pending: Un mesaj cu un link de confirmare a fost trimis la adresa ta de e-mail. După ce faceți clic pe link, vă vom revizui cererea. Veți fi notificat dacă este aprobat.
|
signed_up_but_pending: Un mesaj cu un link de confirmare a fost trimis la adresa dvs. de e-mail. După ce faceți clic pe link, vă vom revizui cererea. Veți fi notificat dacă este aprobat.
|
||||||
signed_up_but_unconfirmed: Un mesaj cu un link de confirmare a fost trimis la adresa ta de e-mail. Vă rugăm să urmați link-ul pentru a vă activa contul. Vă rugăm să verificați folderul spam dacă nu ați primit acest e-mail.
|
signed_up_but_unconfirmed: Un mesaj cu un link de confirmare a fost trimis la adresa dvs. de e-mail. Vă rugăm să urmați link-ul pentru a vă activa contul. Vă rugăm să verificați folderul spam dacă nu ați primit acest e-mail.
|
||||||
update_needs_confirmation: Ți-ai actualizat contul cu succes, dar trebuie să verificăm noua ta adresă de e-mail. Vă rugăm să verificați adresa de e-mail și să urmați link-ul de confirmare pentru a confirma noua dvs. adresă de e-mail. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
update_needs_confirmation: V-ați actualizat contul cu succes, dar trebuie să verificăm noua dvs. adresă de e-mail. Vă rugăm să verificați adresa de e-mail și să urmați link-ul de confirmare pentru a confirma noua dvs. adresă de e-mail. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
updated: Contul dvs. a fost actualizat cu succes.
|
updated: Contul dvs. a fost actualizat cu succes.
|
||||||
sessions:
|
sessions:
|
||||||
already_signed_out: Deconectat cu succes.
|
already_signed_out: Deconectat cu succes.
|
||||||
signed_in: Conectat cu succes.
|
signed_in: Conectat cu succes.
|
||||||
signed_out: Deconectat cu succes.
|
signed_out: Deconectat cu succes.
|
||||||
unlocks:
|
unlocks:
|
||||||
send_instructions: Veți primi un e-mail cu instrucțiuni despre cum să vă deblocați contul în câteva minute. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_instructions: Veți primi un e-mail cu instrucțiuni despre cum să vă deblocați contul în câteva minute. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
send_paranoid_instructions: Dacă contul tău există, vei primi un e-mail cu instrucțiuni pentru cum să-l deblochezi în câteva minute. Te rugăm să verifici dosarul spam dacă nu ai primit acest e-mail.
|
send_paranoid_instructions: Dacă contul dvs. există, veți primi un e-mail cu instrucțiuni pentru cum să-l deblocați în câteva minute. Vă rugăm să verificați dosarul spam dacă nu ați primit acest e-mail.
|
||||||
unlocked: Contul tău a fost deblocat cu succes. Te rugăm să te autentifici pentru a continua.
|
unlocked: Contul dvs. a fost deblocat cu succes. Vă rugăm să vă autentificați pentru a continua.
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
already_confirmed: a fost deja confirmat, încercați să vă conectați
|
already_confirmed: a fost deja confirmat, încercați să vă conectați
|
||||||
|
|
|
@ -3,10 +3,10 @@ ro:
|
||||||
activerecord:
|
activerecord:
|
||||||
attributes:
|
attributes:
|
||||||
doorkeeper/application:
|
doorkeeper/application:
|
||||||
name: Numele aplicației
|
name: Nume aplicație
|
||||||
redirect_uri: URI de redirecționare
|
redirect_uri: URI de redirecționare
|
||||||
scopes: Domenii
|
scopes: Domenii
|
||||||
website: Pagina web a aplicației
|
website: Website aplicație
|
||||||
errors:
|
errors:
|
||||||
models:
|
models:
|
||||||
doorkeeper/application:
|
doorkeeper/application:
|
||||||
|
@ -19,60 +19,60 @@ ro:
|
||||||
doorkeeper:
|
doorkeeper:
|
||||||
applications:
|
applications:
|
||||||
buttons:
|
buttons:
|
||||||
authorize: Autorizează
|
authorize: Autorizare
|
||||||
cancel: Anulează
|
cancel: Anulare
|
||||||
destroy: Distruge
|
destroy: Distrugere
|
||||||
edit: Editează
|
edit: Editare
|
||||||
submit: Trimite
|
submit: Trimitere
|
||||||
confirmations:
|
confirmations:
|
||||||
destroy: Ești sigur?
|
destroy: Sunteți sigur?
|
||||||
edit:
|
edit:
|
||||||
title: Editați aplicația
|
title: Editare aplicație
|
||||||
form:
|
form:
|
||||||
error: Ups! Verificați formularul pentru posibile erori
|
error: Ups! Verificați formularul pentru posibile erori
|
||||||
help:
|
help:
|
||||||
native_redirect_uri: Utilizați %{native_redirect_uri} pentru teste locale
|
native_redirect_uri: Utilizați %{native_redirect_uri} pentru teste locale
|
||||||
redirect_uri: Folosește câte o linie per URI
|
redirect_uri: Folosiți câte o linie per URI
|
||||||
scopes: Separați domeniile cu spații. Lăsați necompletat pentru a utiliza domeniile implicite.
|
scopes: Separați domeniile cu spații. Lăsați necompletat pentru a utiliza domeniile implicite.
|
||||||
index:
|
index:
|
||||||
application: Aplicație
|
application: Aplicație
|
||||||
callback_url: URL pentru callback
|
callback_url: Callback URL
|
||||||
delete: Șterge
|
delete: Ștergere
|
||||||
empty: Nu aveți aplicații.
|
empty: Nu aveți aplicații.
|
||||||
name: Nume
|
name: Nume
|
||||||
new: Aplicație nouă
|
new: Aplicație nouă
|
||||||
scopes: Domenii
|
scopes: Domenii
|
||||||
show: Arată
|
show: Afișare
|
||||||
title: Aplicațiile tale
|
title: Aplicațiile dvs.
|
||||||
new:
|
new:
|
||||||
title: Aplicație nouă
|
title: Aplicație nouă
|
||||||
show:
|
show:
|
||||||
actions: Acțiuni
|
actions: Acțiuni
|
||||||
application_id: Cheie client
|
application_id: Cheie client
|
||||||
callback_urls: URL-uri de callback
|
callback_urls: Callback URL-uri
|
||||||
scopes: Domenii
|
scopes: Domenii
|
||||||
secret: Codul secret al clientului
|
secret: Secretul clientului
|
||||||
title: 'Aplicație: %{name}'
|
title: 'Aplicație: %{name}'
|
||||||
authorizations:
|
authorizations:
|
||||||
buttons:
|
buttons:
|
||||||
authorize: Autorizează
|
authorize: Autorizare
|
||||||
deny: Interzice
|
deny: Refuzare
|
||||||
error:
|
error:
|
||||||
title: A apărut o eroare
|
title: A apărut o eroare
|
||||||
new:
|
new:
|
||||||
prompt_html: "%{client_name} dorește să îți acceseze contul. Este o aplicație terță. <strong>Dacă nu aveți încredere în ea, atunci nu ar trebui să o autorizați.</strong>"
|
prompt_html: "%{client_name} dorește să îți acceseze contul. Este o aplicație terță. <strong>Dacă nu aveți încredere în ea, atunci nu ar trebui să o autorizați.</strong>"
|
||||||
review_permissions: Revizuiește permisiunile
|
review_permissions: Revizuiți permisiunile
|
||||||
title: Autorizare necesară
|
title: Autorizare necesară
|
||||||
show:
|
show:
|
||||||
title: Copiați acest cod de autorizare și lipiți-l în aplicație.
|
title: Copiați acest cod de autorizare și lipiți-l în aplicație.
|
||||||
authorized_applications:
|
authorized_applications:
|
||||||
buttons:
|
buttons:
|
||||||
revoke: Revocați
|
revoke: Revocare
|
||||||
confirmations:
|
confirmations:
|
||||||
revoke: Ești sigur?
|
revoke: Sunteți sigur?
|
||||||
index:
|
index:
|
||||||
authorized_at: Autorizat pe %{date}
|
authorized_at: Autorizat pe %{date}
|
||||||
description_html: Acestea sunt aplicațiile care vă pot accesa contul folosind API. Dacă există aplicații pe care nu le recunoașteți, sau o aplicație se comportă necorespunzător, puteți revoca accesul.
|
description_html: Acestea sunt aplicațiile care vă pot accesa contul folosind API-ul. Dacă există aplicații pe care nu le recunoașteți, sau o aplicație se comportă necorespunzător, puteți revoca accesul.
|
||||||
last_used_at: Utilizat ultima dată pe %{date}
|
last_used_at: Utilizat ultima dată pe %{date}
|
||||||
never_used: Nu a fost folosit niciodată
|
never_used: Nu a fost folosit niciodată
|
||||||
scopes: Permisiuni
|
scopes: Permisiuni
|
||||||
|
@ -86,9 +86,9 @@ ro:
|
||||||
invalid_grant: Acordarea autorizației furnizată este invalidă, expirată, revocată, nu corespunde URI-ului de redirecționare folosit în cererea de autorizare, sau a fost eliberat altui client.
|
invalid_grant: Acordarea autorizației furnizată este invalidă, expirată, revocată, nu corespunde URI-ului de redirecționare folosit în cererea de autorizare, sau a fost eliberat altui client.
|
||||||
invalid_redirect_uri: Uri-ul de redirecționare inclus nu este valid.
|
invalid_redirect_uri: Uri-ul de redirecționare inclus nu este valid.
|
||||||
invalid_request:
|
invalid_request:
|
||||||
missing_param: 'Lipseste parametrul necesar: %{value}.'
|
missing_param: 'Lipsește parametrul necesar: %{value}.'
|
||||||
request_not_authorized: Solicitarea trebuie să fie autorizată. Parametrul necesar pentru solicitarea de autorizare lipsește sau este invalid.
|
request_not_authorized: Solicitarea trebuie să fie autorizată. Parametrul necesar pentru solicitarea de autorizare lipsește sau este invalid.
|
||||||
unknown: Solicitarea nu are un parametru necesar, include un parametru nesuportat sau este dealtfel formatat incorect.
|
unknown: Solicitarea nu are un parametru necesar, include un parametru nesuportat sau este formatat incorect.
|
||||||
invalid_resource_owner: Acreditările proprietarului de resurse nu sunt valide sau proprietarul de resurse nu poate fi găsit
|
invalid_resource_owner: Acreditările proprietarului de resurse nu sunt valide sau proprietarul de resurse nu poate fi găsit
|
||||||
invalid_scope: Domeniul de aplicare solicitat este invalid, necunoscut sau incorect.
|
invalid_scope: Domeniul de aplicare solicitat este invalid, necunoscut sau incorect.
|
||||||
invalid_token:
|
invalid_token:
|
||||||
|
@ -137,12 +137,12 @@ ro:
|
||||||
notifications: Notificări
|
notifications: Notificări
|
||||||
push: Notificări push
|
push: Notificări push
|
||||||
reports: Rapoarte
|
reports: Rapoarte
|
||||||
search: Caută
|
search: Căutare
|
||||||
statuses: Postări
|
statuses: Postări
|
||||||
layouts:
|
layouts:
|
||||||
admin:
|
admin:
|
||||||
nav:
|
nav:
|
||||||
applications: Aplicaţii
|
applications: Aplicații
|
||||||
oauth2_provider: Furnizor OAuth2
|
oauth2_provider: Furnizor OAuth2
|
||||||
application:
|
application:
|
||||||
title: Este necesară autorizarea OAuth
|
title: Este necesară autorizarea OAuth
|
||||||
|
@ -160,7 +160,7 @@ ro:
|
||||||
read:accounts: vede informațiile privind conturile
|
read:accounts: vede informațiile privind conturile
|
||||||
read:blocks: vede blocurile tale
|
read:blocks: vede blocurile tale
|
||||||
read:bookmarks: vede marcajele tale
|
read:bookmarks: vede marcajele tale
|
||||||
read:favourites: vezi favoritele tale
|
read:favourites: vede favoritele tale
|
||||||
read:filters: vede filtrele tale
|
read:filters: vede filtrele tale
|
||||||
read:follows: vede urmăririle tale
|
read:follows: vede urmăririle tale
|
||||||
read:lists: vede listele tale
|
read:lists: vede listele tale
|
||||||
|
@ -168,7 +168,7 @@ ro:
|
||||||
read:notifications: vede notificările tale
|
read:notifications: vede notificările tale
|
||||||
read:reports: vede raportările tale
|
read:reports: vede raportările tale
|
||||||
read:search: caută în numele tău
|
read:search: caută în numele tău
|
||||||
read:statuses: vede toate stările
|
read:statuses: vede toate postările
|
||||||
write: modifică toate datele contului tău
|
write: modifică toate datele contului tău
|
||||||
write:accounts: modifică profilul tău
|
write:accounts: modifică profilul tău
|
||||||
write:blocks: blochează conturile și domeniile
|
write:blocks: blochează conturile și domeniile
|
||||||
|
|
|
@ -604,7 +604,7 @@ es-MX:
|
||||||
suspend_description_html: La cuenta y todos sus contenidos serán inaccesibles y eventualmente eliminados, e interactuar con ella será imposible. Reversible durante 30 días. Cierra todos los reportes contra esta cuenta.
|
suspend_description_html: La cuenta y todos sus contenidos serán inaccesibles y eventualmente eliminados, e interactuar con ella será imposible. Reversible durante 30 días. Cierra todos los reportes contra esta cuenta.
|
||||||
actions_description_html: Decide qué medidas tomar para resolver esta denuncia. Si tomas una acción punitiva contra la cuenta denunciada, se le enviará a dicha cuenta una notificación por correo electrónico, excepto cuando se seleccione la categoría <strong>Spam</strong>.
|
actions_description_html: Decide qué medidas tomar para resolver esta denuncia. Si tomas una acción punitiva contra la cuenta denunciada, se le enviará a dicha cuenta una notificación por correo electrónico, excepto cuando se seleccione la categoría <strong>Spam</strong>.
|
||||||
actions_description_remote_html: Decide qué medidas tomar para resolver este reporte. Esto solo afectará a la forma en que <strong>tu servidor</strong> se comunica con esta cuenta remota y gestiona su contenido.
|
actions_description_remote_html: Decide qué medidas tomar para resolver este reporte. Esto solo afectará a la forma en que <strong>tu servidor</strong> se comunica con esta cuenta remota y gestiona su contenido.
|
||||||
actions_no_posts: Este informe no incluye ninguna publicación asociada a eliminar
|
actions_no_posts: Este informe no tiene ningún mensaje asociado para eliminar
|
||||||
add_to_report: Añadir más al reporte
|
add_to_report: Añadir más al reporte
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Ya suspendido en este servidor
|
local: Ya suspendido en este servidor
|
||||||
|
@ -911,8 +911,8 @@ es-MX:
|
||||||
trends:
|
trends:
|
||||||
allow: Permitir
|
allow: Permitir
|
||||||
approved: Aprobado
|
approved: Aprobado
|
||||||
confirm_allow: "¿Estás seguro de que deseas permitir la etiqueta seleccionada?"
|
confirm_allow: "¿Estás seguro de que deseas permitir las etiquetas seleccionadas?"
|
||||||
confirm_disallow: "¿Estás seguro de que deseas restringir la etiqueta seleccionada?"
|
confirm_disallow: "¿Estás seguro de que deseas restringir las etiquetas seleccionadas?"
|
||||||
disallow: Rechazar
|
disallow: Rechazar
|
||||||
links:
|
links:
|
||||||
allow: Permitir enlace
|
allow: Permitir enlace
|
||||||
|
@ -980,7 +980,7 @@ es-MX:
|
||||||
used_by_over_week:
|
used_by_over_week:
|
||||||
one: Usada por una persona durante la última semana
|
one: Usada por una persona durante la última semana
|
||||||
other: Usada por %{count} personas durante la última semana
|
other: Usada por %{count} personas durante la última semana
|
||||||
title: Recomendaciones y tendencias
|
title: Recomendaciones y Tendencias
|
||||||
trending: En tendencia
|
trending: En tendencia
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Añadir nuevo
|
add_new: Añadir nuevo
|
||||||
|
|
|
@ -604,7 +604,7 @@ es:
|
||||||
suspend_description_html: La cuenta y todos sus contenidos serán inaccesibles y finalmente eliminados, e interactuar con ella será imposible. Reversible durante 30 días. Cierra todos los informes contra esta cuenta.
|
suspend_description_html: La cuenta y todos sus contenidos serán inaccesibles y finalmente eliminados, e interactuar con ella será imposible. Reversible durante 30 días. Cierra todos los informes contra esta cuenta.
|
||||||
actions_description_html: Decide qué medidas tomar para resolver esta denuncia. Si tomas una acción punitiva contra la cuenta denunciada, se le enviará a dicha cuenta una notificación por correo electrónico, excepto cuando se seleccione la categoría <strong>Spam</strong>.
|
actions_description_html: Decide qué medidas tomar para resolver esta denuncia. Si tomas una acción punitiva contra la cuenta denunciada, se le enviará a dicha cuenta una notificación por correo electrónico, excepto cuando se seleccione la categoría <strong>Spam</strong>.
|
||||||
actions_description_remote_html: Decide qué medidas tomar para resolver este informe. Esto solo afectará a la forma en que <strong>tu servidor</strong> se comunica con esta cuenta remota y gestiona su contenido.
|
actions_description_remote_html: Decide qué medidas tomar para resolver este informe. Esto solo afectará a la forma en que <strong>tu servidor</strong> se comunica con esta cuenta remota y gestiona su contenido.
|
||||||
actions_no_posts: Este informe no incluye ninguna publicación asociada a eliminar
|
actions_no_posts: Este informe no tiene ningún mensaje asociado para eliminar
|
||||||
add_to_report: Añadir más al reporte
|
add_to_report: Añadir más al reporte
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Ya suspendido en este servidor
|
local: Ya suspendido en este servidor
|
||||||
|
@ -911,8 +911,8 @@ es:
|
||||||
trends:
|
trends:
|
||||||
allow: Permitir
|
allow: Permitir
|
||||||
approved: Aprobadas
|
approved: Aprobadas
|
||||||
confirm_allow: "¿Estás seguro de que deseas permitir la etiqueta seleccionada?"
|
confirm_allow: "¿Estás seguro de que deseas permitir las etiquetas seleccionadas?"
|
||||||
confirm_disallow: "¿Estás seguro de que deseas restringir la etiqueta seleccionada?"
|
confirm_disallow: "¿Estás seguro de que deseas restringir las etiquetas seleccionadas?"
|
||||||
disallow: No permitir
|
disallow: No permitir
|
||||||
links:
|
links:
|
||||||
allow: Permitir enlace
|
allow: Permitir enlace
|
||||||
|
@ -980,7 +980,7 @@ es:
|
||||||
used_by_over_week:
|
used_by_over_week:
|
||||||
one: Usada por una persona durante la última semana
|
one: Usada por una persona durante la última semana
|
||||||
other: Usada por %{count} personas durante la última semana
|
other: Usada por %{count} personas durante la última semana
|
||||||
title: Recomendaciones y tendencias
|
title: Recomendaciones y Tendencias
|
||||||
trending: En tendencia
|
trending: En tendencia
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Añadir nuevo
|
add_new: Añadir nuevo
|
||||||
|
|
|
@ -24,6 +24,7 @@ et:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Täida tegevus
|
action: Täida tegevus
|
||||||
|
already_silenced: See konto on juba piiratud.
|
||||||
already_suspended: See konto on juba peatatud.
|
already_suspended: See konto on juba peatatud.
|
||||||
title: Rakenda moderaatori tegevus kasutajale %{acct}
|
title: Rakenda moderaatori tegevus kasutajale %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -133,6 +134,7 @@ et:
|
||||||
resubscribe: Telli taas
|
resubscribe: Telli taas
|
||||||
role: Roll
|
role: Roll
|
||||||
search: Otsi
|
search: Otsi
|
||||||
|
search_same_email_domain: Muud kasutajad sama e-posti domeeniga
|
||||||
search_same_ip: Teised kasutajad, kellel on sama IP
|
search_same_ip: Teised kasutajad, kellel on sama IP
|
||||||
security: Turvalisus
|
security: Turvalisus
|
||||||
security_measures:
|
security_measures:
|
||||||
|
@ -173,21 +175,26 @@ et:
|
||||||
approve_appeal: Rahulda vaidlustus
|
approve_appeal: Rahulda vaidlustus
|
||||||
approve_user: Kinnita kasutaja
|
approve_user: Kinnita kasutaja
|
||||||
assigned_to_self_report: Määras Teavituse
|
assigned_to_self_report: Määras Teavituse
|
||||||
|
change_email_user: Muuda kasutaja e-posti
|
||||||
change_role_user: Muuda kasutaja rolli
|
change_role_user: Muuda kasutaja rolli
|
||||||
confirm_user: Kasutaja kinnitatud
|
confirm_user: Kasutaja kinnitatud
|
||||||
create_account_warning: Lisas hoiatuse
|
create_account_warning: Lisas hoiatuse
|
||||||
create_announcement: Lisas teadaande
|
create_announcement: Lisas teadaande
|
||||||
|
create_canonical_email_block: Loo e-posti blokeering
|
||||||
create_custom_emoji: Lisas kohandatud emotikoni
|
create_custom_emoji: Lisas kohandatud emotikoni
|
||||||
create_domain_allow: Lisas lubatud domeeni
|
create_domain_allow: Lisas lubatud domeeni
|
||||||
create_domain_block: Domeeni blokeerimine
|
create_domain_block: Domeeni blokeerimine
|
||||||
|
create_email_domain_block: Loo e-posti domeeni blokeering
|
||||||
create_ip_block: IP-reegli lisamine
|
create_ip_block: IP-reegli lisamine
|
||||||
create_unavailable_domain: Kättesaamatu domeeni lisamine
|
create_unavailable_domain: Kättesaamatu domeeni lisamine
|
||||||
create_user_role: Loo roll
|
create_user_role: Loo roll
|
||||||
demote_user: Alandas kasutaja
|
demote_user: Alandas kasutaja
|
||||||
destroy_announcement: Eemaldas teadaande
|
destroy_announcement: Eemaldas teadaande
|
||||||
|
destroy_canonical_email_block: Kustuta e-posti blokeering
|
||||||
destroy_custom_emoji: Eemaldas kohandatud emotikoni
|
destroy_custom_emoji: Eemaldas kohandatud emotikoni
|
||||||
destroy_domain_allow: Eemaldas lubatud domeeni
|
destroy_domain_allow: Eemaldas lubatud domeeni
|
||||||
destroy_domain_block: Domeeniblokeeringu eemaldamine
|
destroy_domain_block: Domeeniblokeeringu eemaldamine
|
||||||
|
destroy_email_domain_block: Kustuta e-posti domeeni blokeering
|
||||||
destroy_instance: Domeeni kustutamine
|
destroy_instance: Domeeni kustutamine
|
||||||
destroy_ip_block: IP-reegli kustutamine
|
destroy_ip_block: IP-reegli kustutamine
|
||||||
destroy_status: Kustuta postitus
|
destroy_status: Kustuta postitus
|
||||||
|
@ -228,20 +235,26 @@ et:
|
||||||
approve_appeal_html: "%{name} kiitis heaks modereerimise otsuse vaidlustuse %{target} poolt"
|
approve_appeal_html: "%{name} kiitis heaks modereerimise otsuse vaidlustuse %{target} poolt"
|
||||||
approve_user_html: "%{name} kiitis heaks registreerimise %{target} poolt"
|
approve_user_html: "%{name} kiitis heaks registreerimise %{target} poolt"
|
||||||
assigned_to_self_report_html: "%{name} määras raporti %{target} endale"
|
assigned_to_self_report_html: "%{name} määras raporti %{target} endale"
|
||||||
|
change_email_user_html: "%{name} muutis kasutaja %{target} e-postiaadressi"
|
||||||
change_role_user_html: "%{name} muutis %{target} rolli"
|
change_role_user_html: "%{name} muutis %{target} rolli"
|
||||||
|
confirm_user_html: "%{name} kinnitas kasutaja %{target} e-postiaadressi"
|
||||||
create_account_warning_html: "%{name} saatis %{target} hoiatuse"
|
create_account_warning_html: "%{name} saatis %{target} hoiatuse"
|
||||||
create_announcement_html: "%{name} lõi uue teate %{target}"
|
create_announcement_html: "%{name} lõi uue teate %{target}"
|
||||||
|
create_canonical_email_block_html: "%{name} blokeeris e-posti räsiga %{target}"
|
||||||
create_custom_emoji_html: "%{name} laadis üles uue emotikoni %{target}"
|
create_custom_emoji_html: "%{name} laadis üles uue emotikoni %{target}"
|
||||||
create_domain_allow_html: "%{name} lubas föderatsiooni domeeniga %{target}"
|
create_domain_allow_html: "%{name} lubas föderatsiooni domeeniga %{target}"
|
||||||
create_domain_block_html: "%{name} keelas domeeni %{target}"
|
create_domain_block_html: "%{name} keelas domeeni %{target}"
|
||||||
|
create_email_domain_block_html: "%{name} blokeeris e-posti domeeni %{target}"
|
||||||
create_ip_block_html: "%{name} lõi IP-aadressile %{target} reegli"
|
create_ip_block_html: "%{name} lõi IP-aadressile %{target} reegli"
|
||||||
create_unavailable_domain_html: "%{name} lõpetas edastamise domeeni %{target}"
|
create_unavailable_domain_html: "%{name} lõpetas edastamise domeeni %{target}"
|
||||||
create_user_role_html: "%{name} lõi rolli %{target}"
|
create_user_role_html: "%{name} lõi rolli %{target}"
|
||||||
demote_user_html: "%{name} alandas kasutajat %{target}"
|
demote_user_html: "%{name} alandas kasutajat %{target}"
|
||||||
destroy_announcement_html: "%{name} kustutas teadaande %{target}"
|
destroy_announcement_html: "%{name} kustutas teadaande %{target}"
|
||||||
|
destroy_canonical_email_block_html: "%{name} eemaldas blokeeringu e-postilt räsiga %{target}"
|
||||||
destroy_custom_emoji_html: "%{name} kustutas emotikoni %{target}"
|
destroy_custom_emoji_html: "%{name} kustutas emotikoni %{target}"
|
||||||
destroy_domain_allow_html: "%{name} keelas föderatsiooni domeeniga %{target}"
|
destroy_domain_allow_html: "%{name} keelas föderatsiooni domeeniga %{target}"
|
||||||
destroy_domain_block_html: "%{name} lubas domeeni %{target}"
|
destroy_domain_block_html: "%{name} lubas domeeni %{target}"
|
||||||
|
destroy_email_domain_block_html: "%{name} eemaldas blokeeringu e-posti domeenilt %{target}"
|
||||||
destroy_instance_html: "%{name} kustutas domeeni %{target}"
|
destroy_instance_html: "%{name} kustutas domeeni %{target}"
|
||||||
destroy_ip_block_html: "%{name} kustutas IP-aadressi %{target} reegli"
|
destroy_ip_block_html: "%{name} kustutas IP-aadressi %{target} reegli"
|
||||||
destroy_status_html: "%{name} kustutas %{target} postituse"
|
destroy_status_html: "%{name} kustutas %{target} postituse"
|
||||||
|
@ -260,6 +273,7 @@ et:
|
||||||
reject_user_html: "%{name} lükkas %{target} liitumissoovi tagasi"
|
reject_user_html: "%{name} lükkas %{target} liitumissoovi tagasi"
|
||||||
remove_avatar_user_html: "%{name} eemaldas %{target} avatari"
|
remove_avatar_user_html: "%{name} eemaldas %{target} avatari"
|
||||||
reopen_report_html: "%{name} taasavas raporti %{target}"
|
reopen_report_html: "%{name} taasavas raporti %{target}"
|
||||||
|
resend_user_html: "%{name} lähtestas %{target} kinnituskirja e-posti"
|
||||||
reset_password_user_html: "%{name} lähtestas %{target} salasõna"
|
reset_password_user_html: "%{name} lähtestas %{target} salasõna"
|
||||||
resolve_report_html: "%{name} lahendas raporti %{target}"
|
resolve_report_html: "%{name} lahendas raporti %{target}"
|
||||||
sensitive_account_html: "%{name} märkis %{target} meedia kui tundlik sisu"
|
sensitive_account_html: "%{name} märkis %{target} meedia kui tundlik sisu"
|
||||||
|
@ -420,6 +434,7 @@ et:
|
||||||
attempts_over_week:
|
attempts_over_week:
|
||||||
one: "%{count} katse viimase nädala kestel"
|
one: "%{count} katse viimase nädala kestel"
|
||||||
other: "%{count} liitumiskatset viimase nädala kestel"
|
other: "%{count} liitumiskatset viimase nädala kestel"
|
||||||
|
created_msg: E-posti domeen edukalt blokeeritud
|
||||||
delete: Kustuta
|
delete: Kustuta
|
||||||
dns:
|
dns:
|
||||||
types:
|
types:
|
||||||
|
@ -428,8 +443,12 @@ et:
|
||||||
new:
|
new:
|
||||||
create: Lisa domeen
|
create: Lisa domeen
|
||||||
resolve: Domeeni lahendamine
|
resolve: Domeeni lahendamine
|
||||||
|
title: Blokeeri uus e-posti domeen
|
||||||
|
no_email_domain_block_selected: Ühtegi e-posti domeeni blokeeringut ei muudetud, kuna ühtegi ei valitud
|
||||||
not_permitted: Ei ole lubatud
|
not_permitted: Ei ole lubatud
|
||||||
|
resolved_dns_records_hint_html: Domeeninimi lahendatakse järgmistele MX-domeenidele, mis on lõppkokkuvõttes vastutavad e-kirjade vastuvõtmise eest. MX-domeeni blokeerimine blokeerib registreerimise mis tahes e-posti aadressilt, mis kasutab sama MX-domeeni, isegi kui nähtav domeeninimi on erinev. <strong>Ole ettevaatlik, et mitte blokeerida peamisi e-posti teenusepakkujaid.</strong>
|
||||||
resolved_through_html: Lahendatud %{domain} kaudu
|
resolved_through_html: Lahendatud %{domain} kaudu
|
||||||
|
title: Blokeeritud e-posti domeenid
|
||||||
export_domain_allows:
|
export_domain_allows:
|
||||||
new:
|
new:
|
||||||
title: Lubatud domeenide import
|
title: Lubatud domeenide import
|
||||||
|
@ -583,6 +602,7 @@ et:
|
||||||
resolve_description_html: Raporteeritud konto suhtes ei võeta midagi ette, juhtumit ei registreerita ja raport suletakse.
|
resolve_description_html: Raporteeritud konto suhtes ei võeta midagi ette, juhtumit ei registreerita ja raport suletakse.
|
||||||
silence_description_html: Konto saab olema nähtav ainult senistele jälgijatele või otsestele pöördujatele, mõjutates avalikku levi. On tagasipööratav. Sulgeb kõik konto suhtes esitatud raportid.
|
silence_description_html: Konto saab olema nähtav ainult senistele jälgijatele või otsestele pöördujatele, mõjutates avalikku levi. On tagasipööratav. Sulgeb kõik konto suhtes esitatud raportid.
|
||||||
suspend_description_html: See konto ja kogu selle sisu muutub kättesaamatuks ning kustub lõpuks ja igasugune suhtlus sellega muutub võimatuks. Tagasipööratav 30 päeva jooksul. Lõpetab kõik selle konto kohta esitatud kaebused.
|
suspend_description_html: See konto ja kogu selle sisu muutub kättesaamatuks ning kustub lõpuks ja igasugune suhtlus sellega muutub võimatuks. Tagasipööratav 30 päeva jooksul. Lõpetab kõik selle konto kohta esitatud kaebused.
|
||||||
|
actions_description_html: Otsusta, milliseid meetmeid selle raporti lahendamiseks võtta. Kui võtad raporteeritud konto suhtes karistusmeetme, saadetakse talle e-posti teade, välja arvatud juhul, kui valid kategooria <strong>Rämps</strong>.
|
||||||
actions_description_remote_html: Otsusta, mida teha selle raporti lahendamiseks. See mõjutab ainult seda, kuidas <strong>Sinu</strong> server selle kaugkontoga suhtleb ning selle sisu käsitleb.
|
actions_description_remote_html: Otsusta, mida teha selle raporti lahendamiseks. See mõjutab ainult seda, kuidas <strong>Sinu</strong> server selle kaugkontoga suhtleb ning selle sisu käsitleb.
|
||||||
actions_no_posts: Selle raportiga pole seotud ühtegi postitust, mida kustutada
|
actions_no_posts: Selle raportiga pole seotud ühtegi postitust, mida kustutada
|
||||||
add_to_report: Lisa raportile juurde
|
add_to_report: Lisa raportile juurde
|
||||||
|
@ -648,6 +668,7 @@ et:
|
||||||
delete_data_html: Kustuta tänasest 30 päeva pärast kasutaja <strong>@%{acct}</strong> profiil ja sisu, kui vahepeal tema kontot ei taastata
|
delete_data_html: Kustuta tänasest 30 päeva pärast kasutaja <strong>@%{acct}</strong> profiil ja sisu, kui vahepeal tema kontot ei taastata
|
||||||
preview_preamble_html: "<strong>@%{acct}</strong> saab järgmise sisuga hoiatuse:"
|
preview_preamble_html: "<strong>@%{acct}</strong> saab järgmise sisuga hoiatuse:"
|
||||||
record_strike_html: Salvesta <strong>@%{acct}</strong> kohta juhtum, et aidata selle konto tulevaste rikkumiste puhul reageerida
|
record_strike_html: Salvesta <strong>@%{acct}</strong> kohta juhtum, et aidata selle konto tulevaste rikkumiste puhul reageerida
|
||||||
|
send_email_html: Saada hoiatuskiri <strong>@%{acct}</strong>
|
||||||
warning_placeholder: Valikuline täiendav põhjendus modereerimisele.
|
warning_placeholder: Valikuline täiendav põhjendus modereerimisele.
|
||||||
target_origin: Raporteeritud konto päritolu
|
target_origin: Raporteeritud konto päritolu
|
||||||
title: Teavitused
|
title: Teavitused
|
||||||
|
@ -687,6 +708,7 @@ et:
|
||||||
manage_appeals: Vaidlustuste haldamine
|
manage_appeals: Vaidlustuste haldamine
|
||||||
manage_appeals_description: Lubab kasutajail läbi vaadata modereerimisotsuste vaidlustusi
|
manage_appeals_description: Lubab kasutajail läbi vaadata modereerimisotsuste vaidlustusi
|
||||||
manage_blocks: Keeldude haldamine
|
manage_blocks: Keeldude haldamine
|
||||||
|
manage_blocks_description: Lubab kasutajatel blokeerida e-posti teenusepakkujaid ja IP-aadresse
|
||||||
manage_custom_emojis: Halda isetehtud emotikone
|
manage_custom_emojis: Halda isetehtud emotikone
|
||||||
manage_custom_emojis_description: Lubab kasutajatel hallata serveris isetehtud emotikone
|
manage_custom_emojis_description: Lubab kasutajatel hallata serveris isetehtud emotikone
|
||||||
manage_federation: Halda födereerumist
|
manage_federation: Halda födereerumist
|
||||||
|
@ -704,6 +726,7 @@ et:
|
||||||
manage_taxonomies: Halda taksonoomiaid
|
manage_taxonomies: Halda taksonoomiaid
|
||||||
manage_taxonomies_description: Luba kasutajatel populaarset sisu üle vaadata ning uuendada siltide sätteid
|
manage_taxonomies_description: Luba kasutajatel populaarset sisu üle vaadata ning uuendada siltide sätteid
|
||||||
manage_user_access: Halda kasutajate ligipääsu
|
manage_user_access: Halda kasutajate ligipääsu
|
||||||
|
manage_user_access_description: Võimaldab kasutajatel keelata teiste kasutajate kaheastmelise autentimise, muuta oma e-posti aadressi ja lähtestada oma parooli
|
||||||
manage_users: Kasutajate haldamine
|
manage_users: Kasutajate haldamine
|
||||||
manage_users_description: Lubab kasutajail näha teiste kasutajate üksikasju ja teha nende suhtes modereerimisotsuseid
|
manage_users_description: Lubab kasutajail näha teiste kasutajate üksikasju ja teha nende suhtes modereerimisotsuseid
|
||||||
manage_webhooks: Halda webhook'e
|
manage_webhooks: Halda webhook'e
|
||||||
|
@ -1137,6 +1160,12 @@ et:
|
||||||
view_strikes: Vaata enda eelnevaid juhtumeid
|
view_strikes: Vaata enda eelnevaid juhtumeid
|
||||||
too_fast: Vorm esitatud liiga kiirelt, proovi uuesti.
|
too_fast: Vorm esitatud liiga kiirelt, proovi uuesti.
|
||||||
use_security_key: Kasuta turvavõtit
|
use_security_key: Kasuta turvavõtit
|
||||||
|
author_attribution:
|
||||||
|
example_title: Näidistekst
|
||||||
|
hint_html: Määra, kuidas sind krediteeritakse, kui linke Mastodonis jagatakse.
|
||||||
|
more_from_html: Rohkem kasutajalt %{name}
|
||||||
|
s_blog: Kasutaja %{name} blogi
|
||||||
|
title: Autori tunnustamine
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Jätka
|
confirm: Jätka
|
||||||
hint_html: "<strong>Nõuanne:</strong> Me ei küsi salasõna uuesti järgmise tunni jooksul."
|
hint_html: "<strong>Nõuanne:</strong> Me ei küsi salasõna uuesti järgmise tunni jooksul."
|
||||||
|
@ -1418,6 +1447,16 @@ et:
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
action: Jah, lõpeta tellimine
|
action: Jah, lõpeta tellimine
|
||||||
complete: Tellimine lõpetatud
|
complete: Tellimine lõpetatud
|
||||||
|
confirmation_html: Kas oled kindel, et soovid loobuda %{type} tellimisest oma e-postiaadressile %{email} Mastodonist kohas %{domain}? Saad alati uuesti tellida oma <a href="%{settings_path}">e-posti teavituste seadetest</a>.
|
||||||
|
emails:
|
||||||
|
notification_emails:
|
||||||
|
favourite: lemmikuks märkimise teavituskirjade
|
||||||
|
follow: jälgimiste teavituskirjade
|
||||||
|
follow_request: jälgimistaotluste teavituskirjade
|
||||||
|
mention: mainimiste teavituskirjade
|
||||||
|
reblog: jagamiste teavituskirjade
|
||||||
|
resubscribe_html: Kui loobusid tellimisest ekslikult, saad uuesti tellida oma <a href="%{settings_path}">e-posti teavituste seadetest</a>.
|
||||||
|
success_html: Sa ei saa enam %{type} teateid oma e-postile %{email} Mastodonist kohas %{domain}.
|
||||||
title: Loobu tellimisest
|
title: Loobu tellimisest
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
|
@ -1906,6 +1945,7 @@ et:
|
||||||
instructions_html: Kopeeri ja kleebi allpool olev kood oma lehe HTML lähtekoodi. Seejärel lisa oma kodulehe aadress profiili "Muuda profiili" taabi ühte lisavälja ning salvesta muudatused.
|
instructions_html: Kopeeri ja kleebi allpool olev kood oma lehe HTML lähtekoodi. Seejärel lisa oma kodulehe aadress profiili "Muuda profiili" taabi ühte lisavälja ning salvesta muudatused.
|
||||||
verification: Kinnitamine
|
verification: Kinnitamine
|
||||||
verified_links: Sinu kontrollitud lingid
|
verified_links: Sinu kontrollitud lingid
|
||||||
|
website_verification: Veebilehe kontrollimine
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Uue turvavõtme lisamine
|
add: Uue turvavõtme lisamine
|
||||||
create:
|
create:
|
||||||
|
|
|
@ -24,6 +24,7 @@ fr-CA:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Effectuer l'action
|
action: Effectuer l'action
|
||||||
|
already_silenced: Ce compte a déjà été limité.
|
||||||
already_suspended: Ce compte est déjà suspendu.
|
already_suspended: Ce compte est déjà suspendu.
|
||||||
title: Effectuer une action de modération sur %{acct}
|
title: Effectuer une action de modération sur %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -133,7 +134,7 @@ fr-CA:
|
||||||
resubscribe: Se réabonner
|
resubscribe: Se réabonner
|
||||||
role: Rôle
|
role: Rôle
|
||||||
search: Rechercher
|
search: Rechercher
|
||||||
search_same_email_domain: Autres utilisateurs avec le même domaine de courriel
|
search_same_email_domain: Autres utilisateur·rice·s ayant le même domaine de messagerie
|
||||||
search_same_ip: Autres utilisateur·rice·s avec la même IP
|
search_same_ip: Autres utilisateur·rice·s avec la même IP
|
||||||
security: Sécurité
|
security: Sécurité
|
||||||
security_measures:
|
security_measures:
|
||||||
|
@ -270,6 +271,7 @@ fr-CA:
|
||||||
reject_user_html: "%{name} a rejeté l’inscription de %{target}"
|
reject_user_html: "%{name} a rejeté l’inscription de %{target}"
|
||||||
remove_avatar_user_html: "%{name} a supprimé l'avatar de %{target}"
|
remove_avatar_user_html: "%{name} a supprimé l'avatar de %{target}"
|
||||||
reopen_report_html: "%{name} a rouvert le signalement %{target}"
|
reopen_report_html: "%{name} a rouvert le signalement %{target}"
|
||||||
|
resend_user_html: "%{name} a renvoyé l'e-mail de confirmation pour %{target}"
|
||||||
reset_password_user_html: "%{name} a réinitialisé le mot de passe de l'utilisateur·rice %{target}"
|
reset_password_user_html: "%{name} a réinitialisé le mot de passe de l'utilisateur·rice %{target}"
|
||||||
resolve_report_html: "%{name} a résolu le signalement %{target}"
|
resolve_report_html: "%{name} a résolu le signalement %{target}"
|
||||||
sensitive_account_html: "%{name} a marqué le média de %{target} comme sensible"
|
sensitive_account_html: "%{name} a marqué le média de %{target} comme sensible"
|
||||||
|
@ -284,6 +286,7 @@ fr-CA:
|
||||||
update_custom_emoji_html: "%{name} a mis à jour l'émoji %{target}"
|
update_custom_emoji_html: "%{name} a mis à jour l'émoji %{target}"
|
||||||
update_domain_block_html: "%{name} a mis à jour le blocage de domaine pour %{target}"
|
update_domain_block_html: "%{name} a mis à jour le blocage de domaine pour %{target}"
|
||||||
update_ip_block_html: "%{name} a modifié la règle pour l'IP %{target}"
|
update_ip_block_html: "%{name} a modifié la règle pour l'IP %{target}"
|
||||||
|
update_report_html: "%{name} a mis à jour le rapport de signalement %{target}"
|
||||||
update_status_html: "%{name} a mis à jour le message de %{target}"
|
update_status_html: "%{name} a mis à jour le message de %{target}"
|
||||||
update_user_role_html: "%{name} a changé le rôle %{target}"
|
update_user_role_html: "%{name} a changé le rôle %{target}"
|
||||||
deleted_account: compte supprimé
|
deleted_account: compte supprimé
|
||||||
|
@ -439,7 +442,12 @@ fr-CA:
|
||||||
create: Créer le blocage
|
create: Créer le blocage
|
||||||
resolve: Résoudre le domaine
|
resolve: Résoudre le domaine
|
||||||
title: Blocage d'un nouveau domaine de messagerie électronique
|
title: Blocage d'un nouveau domaine de messagerie électronique
|
||||||
|
no_email_domain_block_selected: Aucun blocage de domaine de messagerie n'a été modifié comme aucun n'a été sélectionné
|
||||||
not_permitted: Non autorisé
|
not_permitted: Non autorisé
|
||||||
|
resolved_dns_records_hint_html: |-
|
||||||
|
Le nom de domaine se réfère aux domaines MX suivants, qui sont à leur tour responsables de la réception des courriels.
|
||||||
|
|
||||||
|
Le blocage d'un domaine MX empêchera l'inscription depuis toute adresse électronique ayant recours au même domaine MX, et ce même si le nom de domaine visible est différent. <strong>Veillez à ne pas bloquer les principaux fournisseurs de services de messagerie.</strong>
|
||||||
resolved_through_html: Résolu par %{domain}
|
resolved_through_html: Résolu par %{domain}
|
||||||
title: Domaines de messagerie électronique bloqués
|
title: Domaines de messagerie électronique bloqués
|
||||||
export_domain_allows:
|
export_domain_allows:
|
||||||
|
@ -595,7 +603,9 @@ fr-CA:
|
||||||
resolve_description_html: Aucune mesure ne sera prise contre le compte signalé, aucune sanction ne sera enregistrée et le sigalement sera clôturé.
|
resolve_description_html: Aucune mesure ne sera prise contre le compte signalé, aucune sanction ne sera enregistrée et le sigalement sera clôturé.
|
||||||
silence_description_html: Le compte ne sera visible que par ceux qui le suivent déjà ou qui le recherchent manuellement, ce qui limite fortement sa portée. Cette action peut toujours être annulée. Cloture tous les signalements concernant ce compte.
|
silence_description_html: Le compte ne sera visible que par ceux qui le suivent déjà ou qui le recherchent manuellement, ce qui limite fortement sa portée. Cette action peut toujours être annulée. Cloture tous les signalements concernant ce compte.
|
||||||
suspend_description_html: Le compte et tous ses contenus seront inaccessibles et finalement supprimés, et il sera impossible d'interagir avec lui. Réversible dans les 30 jours. Cloture tous les signalements concernant ce compte.
|
suspend_description_html: Le compte et tous ses contenus seront inaccessibles et finalement supprimés, et il sera impossible d'interagir avec lui. Réversible dans les 30 jours. Cloture tous les signalements concernant ce compte.
|
||||||
|
actions_description_html: Décidez de l'action à entreprendre pour résoudre ce signalement. Si vous prenez une mesure punitive à l'encontre du compte signalé, une notification par courrier électronique lui sera envoyée, excepté lorsque la catégorie <strong>Spam</strong> est sélectionnée.
|
||||||
actions_description_remote_html: Décidez des mesures à prendre pour résoudre ce signalement. Cela n'affectera que la manière dont <strong>votre</strong> serveur communique avec ce compte distant et traite son contenu.
|
actions_description_remote_html: Décidez des mesures à prendre pour résoudre ce signalement. Cela n'affectera que la manière dont <strong>votre</strong> serveur communique avec ce compte distant et traite son contenu.
|
||||||
|
actions_no_posts: Ce signalement n'a pas de messages qui lui sont associés et qui devraient être supprimés
|
||||||
add_to_report: Ajouter davantage au rapport
|
add_to_report: Ajouter davantage au rapport
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Déjà suspendu sur ce serveur
|
local: Déjà suspendu sur ce serveur
|
||||||
|
@ -717,6 +727,7 @@ fr-CA:
|
||||||
manage_taxonomies: Gérer les taxonomies
|
manage_taxonomies: Gérer les taxonomies
|
||||||
manage_taxonomies_description: Permet aux utilisateur⋅rice⋅s d'examiner les contenus tendance et de mettre à jour les paramètres des hashtags
|
manage_taxonomies_description: Permet aux utilisateur⋅rice⋅s d'examiner les contenus tendance et de mettre à jour les paramètres des hashtags
|
||||||
manage_user_access: Gérer l'accès utilisateur
|
manage_user_access: Gérer l'accès utilisateur
|
||||||
|
manage_user_access_description: Permet aux utilisateur·rice·s de désactiver l'authentification à deux facteurs des autres utilisateur·rice·s, de modifier leur adresse électronique et de réinitialiser leur mot de passe
|
||||||
manage_users: Gérer les utilisateur·rice·s
|
manage_users: Gérer les utilisateur·rice·s
|
||||||
manage_users_description: Permet aux utilisateur⋅rice⋅s de voir les détails des autres utilisateur⋅rice⋅s et d'effectuer des actions de modération en conséquence
|
manage_users_description: Permet aux utilisateur⋅rice⋅s de voir les détails des autres utilisateur⋅rice⋅s et d'effectuer des actions de modération en conséquence
|
||||||
manage_webhooks: Gérer les points d’ancrage web
|
manage_webhooks: Gérer les points d’ancrage web
|
||||||
|
@ -879,16 +890,19 @@ fr-CA:
|
||||||
message_html: "<strong>Votre serveur web est mal configuré. La confidentialité de vos utilisateurs est en péril.</strong>"
|
message_html: "<strong>Votre serveur web est mal configuré. La confidentialité de vos utilisateurs est en péril.</strong>"
|
||||||
tags:
|
tags:
|
||||||
moderation:
|
moderation:
|
||||||
|
not_trendable: Ne peut être en tendance
|
||||||
not_usable: Non utilisable
|
not_usable: Non utilisable
|
||||||
pending_review: En attente de traitement
|
pending_review: En attente de traitement
|
||||||
review_requested: Révision requise
|
review_requested: Révision requise
|
||||||
reviewed: Traité
|
reviewed: Traité
|
||||||
title: État
|
title: État
|
||||||
|
trendable: Peut s'afficher dans les tendances
|
||||||
unreviewed: Non traité
|
unreviewed: Non traité
|
||||||
usable: Utilisable
|
usable: Utilisable
|
||||||
name: Nom
|
name: Nom
|
||||||
newest: Plus récents
|
newest: Plus récents
|
||||||
oldest: Plus anciens
|
oldest: Plus anciens
|
||||||
|
open: Afficher publiquement
|
||||||
reset: Réinitialiser
|
reset: Réinitialiser
|
||||||
review: État du traitement
|
review: État du traitement
|
||||||
search: Recherche
|
search: Recherche
|
||||||
|
@ -1434,6 +1448,15 @@ fr-CA:
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
action: Oui, me désabonner
|
action: Oui, me désabonner
|
||||||
complete: Désabonné·e
|
complete: Désabonné·e
|
||||||
|
emails:
|
||||||
|
notification_emails:
|
||||||
|
favourite: e-mails de notifications de favoris
|
||||||
|
follow: e-mails de notifications d’abonnements
|
||||||
|
follow_request: e-mails de demandes d’abonnements
|
||||||
|
mention: e-mails de notifications de mentions
|
||||||
|
reblog: e-mails de notifications de partages
|
||||||
|
resubscribe_html: Si vous vous êtes désinscrit par erreur, vous pouvez vous réinscrire à partir de vos <a href="%{settings_path}">paramètres de notification par e-mail</a>.
|
||||||
|
success_html: Vous ne recevrez plus de %{type} pour Mastodon sur %{domain} à votre adresse e-mail à %{email}.
|
||||||
title: Se désabonner
|
title: Se désabonner
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
|
|
|
@ -24,6 +24,7 @@ fr:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Effectuer l'action
|
action: Effectuer l'action
|
||||||
|
already_silenced: Ce compte a déjà été limité.
|
||||||
already_suspended: Ce compte est déjà suspendu.
|
already_suspended: Ce compte est déjà suspendu.
|
||||||
title: Effectuer une action de modération sur %{acct}
|
title: Effectuer une action de modération sur %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -133,7 +134,7 @@ fr:
|
||||||
resubscribe: Se réabonner
|
resubscribe: Se réabonner
|
||||||
role: Rôle
|
role: Rôle
|
||||||
search: Rechercher
|
search: Rechercher
|
||||||
search_same_email_domain: Autres utilisateurs avec le même domaine de courriel
|
search_same_email_domain: Autres utilisateur·rice·s ayant le même domaine de messagerie
|
||||||
search_same_ip: Autres utilisateur·rice·s avec la même IP
|
search_same_ip: Autres utilisateur·rice·s avec la même IP
|
||||||
security: Sécurité
|
security: Sécurité
|
||||||
security_measures:
|
security_measures:
|
||||||
|
@ -270,6 +271,7 @@ fr:
|
||||||
reject_user_html: "%{name} a rejeté l’inscription de %{target}"
|
reject_user_html: "%{name} a rejeté l’inscription de %{target}"
|
||||||
remove_avatar_user_html: "%{name} a supprimé l'avatar de %{target}"
|
remove_avatar_user_html: "%{name} a supprimé l'avatar de %{target}"
|
||||||
reopen_report_html: "%{name} a rouvert le signalement %{target}"
|
reopen_report_html: "%{name} a rouvert le signalement %{target}"
|
||||||
|
resend_user_html: "%{name} a renvoyé l'e-mail de confirmation pour %{target}"
|
||||||
reset_password_user_html: "%{name} a réinitialisé le mot de passe de l'utilisateur·rice %{target}"
|
reset_password_user_html: "%{name} a réinitialisé le mot de passe de l'utilisateur·rice %{target}"
|
||||||
resolve_report_html: "%{name} a résolu le signalement %{target}"
|
resolve_report_html: "%{name} a résolu le signalement %{target}"
|
||||||
sensitive_account_html: "%{name} a marqué le média de %{target} comme sensible"
|
sensitive_account_html: "%{name} a marqué le média de %{target} comme sensible"
|
||||||
|
@ -284,6 +286,7 @@ fr:
|
||||||
update_custom_emoji_html: "%{name} a mis à jour l'émoji %{target}"
|
update_custom_emoji_html: "%{name} a mis à jour l'émoji %{target}"
|
||||||
update_domain_block_html: "%{name} a mis à jour le blocage de domaine pour %{target}"
|
update_domain_block_html: "%{name} a mis à jour le blocage de domaine pour %{target}"
|
||||||
update_ip_block_html: "%{name} a modifié la règle pour l'IP %{target}"
|
update_ip_block_html: "%{name} a modifié la règle pour l'IP %{target}"
|
||||||
|
update_report_html: "%{name} a mis à jour le rapport de signalement %{target}"
|
||||||
update_status_html: "%{name} a mis à jour le message de %{target}"
|
update_status_html: "%{name} a mis à jour le message de %{target}"
|
||||||
update_user_role_html: "%{name} a changé le rôle %{target}"
|
update_user_role_html: "%{name} a changé le rôle %{target}"
|
||||||
deleted_account: compte supprimé
|
deleted_account: compte supprimé
|
||||||
|
@ -439,7 +442,12 @@ fr:
|
||||||
create: Créer le blocage
|
create: Créer le blocage
|
||||||
resolve: Résoudre le domaine
|
resolve: Résoudre le domaine
|
||||||
title: Blocage d'un nouveau domaine de messagerie électronique
|
title: Blocage d'un nouveau domaine de messagerie électronique
|
||||||
|
no_email_domain_block_selected: Aucun blocage de domaine de messagerie n'a été modifié comme aucun n'a été sélectionné
|
||||||
not_permitted: Non autorisé
|
not_permitted: Non autorisé
|
||||||
|
resolved_dns_records_hint_html: |-
|
||||||
|
Le nom de domaine se réfère aux domaines MX suivants, qui sont à leur tour responsables de la réception des courriels.
|
||||||
|
|
||||||
|
Le blocage d'un domaine MX empêchera l'inscription depuis toute adresse électronique ayant recours au même domaine MX, et ce même si le nom de domaine visible est différent. <strong>Veillez à ne pas bloquer les principaux fournisseurs de services de messagerie.</strong>
|
||||||
resolved_through_html: Résolu par %{domain}
|
resolved_through_html: Résolu par %{domain}
|
||||||
title: Domaines de messagerie électronique bloqués
|
title: Domaines de messagerie électronique bloqués
|
||||||
export_domain_allows:
|
export_domain_allows:
|
||||||
|
@ -595,7 +603,9 @@ fr:
|
||||||
resolve_description_html: Aucune mesure ne sera prise contre le compte signalé, aucune sanction ne sera enregistrée et le sigalement sera clôturé.
|
resolve_description_html: Aucune mesure ne sera prise contre le compte signalé, aucune sanction ne sera enregistrée et le sigalement sera clôturé.
|
||||||
silence_description_html: Le compte ne sera visible que par ceux qui le suivent déjà ou qui le recherchent manuellement, ce qui limite fortement sa portée. Cette action peut toujours être annulée. Cloture tous les signalements concernant ce compte.
|
silence_description_html: Le compte ne sera visible que par ceux qui le suivent déjà ou qui le recherchent manuellement, ce qui limite fortement sa portée. Cette action peut toujours être annulée. Cloture tous les signalements concernant ce compte.
|
||||||
suspend_description_html: Le compte et tous ses contenus seront inaccessibles et finalement supprimés, et il sera impossible d'interagir avec lui. Réversible dans les 30 jours. Cloture tous les signalements concernant ce compte.
|
suspend_description_html: Le compte et tous ses contenus seront inaccessibles et finalement supprimés, et il sera impossible d'interagir avec lui. Réversible dans les 30 jours. Cloture tous les signalements concernant ce compte.
|
||||||
|
actions_description_html: Décidez de l'action à entreprendre pour résoudre ce signalement. Si vous prenez une mesure punitive à l'encontre du compte signalé, une notification par courrier électronique lui sera envoyée, excepté lorsque la catégorie <strong>Spam</strong> est sélectionnée.
|
||||||
actions_description_remote_html: Décidez des mesures à prendre pour résoudre ce signalement. Cela n'affectera que la manière dont <strong>votre</strong> serveur communique avec ce compte distant et traite son contenu.
|
actions_description_remote_html: Décidez des mesures à prendre pour résoudre ce signalement. Cela n'affectera que la manière dont <strong>votre</strong> serveur communique avec ce compte distant et traite son contenu.
|
||||||
|
actions_no_posts: Ce signalement n'a pas de messages qui lui sont associés et qui devraient être supprimés
|
||||||
add_to_report: Ajouter davantage au rapport
|
add_to_report: Ajouter davantage au rapport
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Déjà suspendu sur ce serveur
|
local: Déjà suspendu sur ce serveur
|
||||||
|
@ -717,6 +727,7 @@ fr:
|
||||||
manage_taxonomies: Gérer les taxonomies
|
manage_taxonomies: Gérer les taxonomies
|
||||||
manage_taxonomies_description: Permet aux utilisateur⋅rice⋅s d'examiner les contenus tendance et de mettre à jour les paramètres des hashtags
|
manage_taxonomies_description: Permet aux utilisateur⋅rice⋅s d'examiner les contenus tendance et de mettre à jour les paramètres des hashtags
|
||||||
manage_user_access: Gérer l'accès utilisateur
|
manage_user_access: Gérer l'accès utilisateur
|
||||||
|
manage_user_access_description: Permet aux utilisateur·rice·s de désactiver l'authentification à deux facteurs des autres utilisateur·rice·s, de modifier leur adresse électronique et de réinitialiser leur mot de passe
|
||||||
manage_users: Gérer les utilisateur·rice·s
|
manage_users: Gérer les utilisateur·rice·s
|
||||||
manage_users_description: Permet aux utilisateur⋅rice⋅s de voir les détails des autres utilisateur⋅rice⋅s et d'effectuer des actions de modération en conséquence
|
manage_users_description: Permet aux utilisateur⋅rice⋅s de voir les détails des autres utilisateur⋅rice⋅s et d'effectuer des actions de modération en conséquence
|
||||||
manage_webhooks: Gérer les points d’ancrage web
|
manage_webhooks: Gérer les points d’ancrage web
|
||||||
|
@ -879,16 +890,19 @@ fr:
|
||||||
message_html: "<strong>Votre serveur web est mal configuré. La confidentialité de vos utilisateurs est en péril.</strong>"
|
message_html: "<strong>Votre serveur web est mal configuré. La confidentialité de vos utilisateurs est en péril.</strong>"
|
||||||
tags:
|
tags:
|
||||||
moderation:
|
moderation:
|
||||||
|
not_trendable: Ne peut être en tendance
|
||||||
not_usable: Non utilisable
|
not_usable: Non utilisable
|
||||||
pending_review: En attente de traitement
|
pending_review: En attente de traitement
|
||||||
review_requested: Révision requise
|
review_requested: Révision requise
|
||||||
reviewed: Traité
|
reviewed: Traité
|
||||||
title: État
|
title: État
|
||||||
|
trendable: Peut s'afficher dans les tendances
|
||||||
unreviewed: Non traité
|
unreviewed: Non traité
|
||||||
usable: Utilisable
|
usable: Utilisable
|
||||||
name: Nom
|
name: Nom
|
||||||
newest: Plus récents
|
newest: Plus récents
|
||||||
oldest: Plus anciens
|
oldest: Plus anciens
|
||||||
|
open: Afficher publiquement
|
||||||
reset: Réinitialiser
|
reset: Réinitialiser
|
||||||
review: État du traitement
|
review: État du traitement
|
||||||
search: Recherche
|
search: Recherche
|
||||||
|
@ -1434,6 +1448,15 @@ fr:
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
action: Oui, se désinscrire
|
action: Oui, se désinscrire
|
||||||
complete: Désinscrit
|
complete: Désinscrit
|
||||||
|
emails:
|
||||||
|
notification_emails:
|
||||||
|
favourite: e-mails de notifications de favoris
|
||||||
|
follow: e-mails de notifications d’abonnements
|
||||||
|
follow_request: e-mails de demandes d’abonnements
|
||||||
|
mention: e-mails de notifications de mentions
|
||||||
|
reblog: e-mails de notifications de partages
|
||||||
|
resubscribe_html: Si vous vous êtes désinscrit par erreur, vous pouvez vous réinscrire à partir de vos <a href="%{settings_path}">paramètres de notification par e-mail</a>.
|
||||||
|
success_html: Vous ne recevrez plus de %{type} pour Mastodon sur %{domain} à votre adresse e-mail à %{email}.
|
||||||
title: Se désinscrire
|
title: Se désinscrire
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
|
|
|
@ -30,6 +30,7 @@ ga:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Déan gníomh
|
action: Déan gníomh
|
||||||
|
already_silenced: Tá teorainn leis an gcuntas seo cheana féin.
|
||||||
already_suspended: Tá an cuntas seo curtha ar fionraí cheana féin.
|
already_suspended: Tá an cuntas seo curtha ar fionraí cheana féin.
|
||||||
title: Dean gníomh modhnóireachta ar %{acct}
|
title: Dean gníomh modhnóireachta ar %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -1213,6 +1214,12 @@ ga:
|
||||||
view_strikes: Féach ar stailceanna san am atá caite i gcoinne do chuntais
|
view_strikes: Féach ar stailceanna san am atá caite i gcoinne do chuntais
|
||||||
too_fast: Cuireadh an fhoirm isteach róthapa, triail arís.
|
too_fast: Cuireadh an fhoirm isteach róthapa, triail arís.
|
||||||
use_security_key: Úsáid eochair shlándála
|
use_security_key: Úsáid eochair shlándála
|
||||||
|
author_attribution:
|
||||||
|
example_title: Téacs samplach
|
||||||
|
hint_html: Rialú conas a chuirtear chun sochair tú nuair a roinntear naisc ar Mastodon.
|
||||||
|
more_from_html: Tuilleadh ó %{name}
|
||||||
|
s_blog: Blag %{name}
|
||||||
|
title: Leithdháil an údair
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Lean ar aghaidh
|
confirm: Lean ar aghaidh
|
||||||
hint_html: "<strong>Leid:</strong> Ní iarrfaimid do phasfhocal ort arís go ceann uair an chloig eile."
|
hint_html: "<strong>Leid:</strong> Ní iarrfaimid do phasfhocal ort arís go ceann uair an chloig eile."
|
||||||
|
@ -2029,6 +2036,7 @@ ga:
|
||||||
instructions_html: Cóipeáil agus greamaigh an cód thíos isteach i HTML do shuíomh Gréasáin. Ansin cuir seoladh do shuíomh Gréasáin isteach i gceann de na réimsí breise ar do phróifíl ón gcluaisín "Cuir próifíl in eagar" agus sábháil athruithe.
|
instructions_html: Cóipeáil agus greamaigh an cód thíos isteach i HTML do shuíomh Gréasáin. Ansin cuir seoladh do shuíomh Gréasáin isteach i gceann de na réimsí breise ar do phróifíl ón gcluaisín "Cuir próifíl in eagar" agus sábháil athruithe.
|
||||||
verification: Fíorú
|
verification: Fíorú
|
||||||
verified_links: Do naisc fhíoraithe
|
verified_links: Do naisc fhíoraithe
|
||||||
|
website_verification: Fíorú láithreán gréasáin
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Cuir eochair shlándála nua leis
|
add: Cuir eochair shlándála nua leis
|
||||||
create:
|
create:
|
||||||
|
|
|
@ -28,6 +28,7 @@ gd:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Gabh an gnìomh
|
action: Gabh an gnìomh
|
||||||
|
already_silenced: Chaidh an cunntas seo a chuingeachadh mu thràth.
|
||||||
already_suspended: Chaidh an cunntas seo a chur à rèim mu thràth.
|
already_suspended: Chaidh an cunntas seo a chur à rèim mu thràth.
|
||||||
title: Gabh gnìomh maorsainneachd air %{acct}
|
title: Gabh gnìomh maorsainneachd air %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -1195,6 +1196,12 @@ gd:
|
||||||
view_strikes: Seall na rabhaidhean a fhuair an cunntas agad roimhe
|
view_strikes: Seall na rabhaidhean a fhuair an cunntas agad roimhe
|
||||||
too_fast: Chaidh am foirm a chur a-null ro luath, feuch ris a-rithist.
|
too_fast: Chaidh am foirm a chur a-null ro luath, feuch ris a-rithist.
|
||||||
use_security_key: Cleachd iuchair tèarainteachd
|
use_security_key: Cleachd iuchair tèarainteachd
|
||||||
|
author_attribution:
|
||||||
|
example_title: Ball-sampaill teacsa
|
||||||
|
hint_html: Stùirich mar a thèid iomradh a thoirt ort nuair a thèid ceangal a cho-roinneadh air Mastodon.
|
||||||
|
more_from_html: Barrachd o %{name}
|
||||||
|
s_blog: Bloga aig %{name}
|
||||||
|
title: Aithris air an ùghdar
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Lean air adhart
|
confirm: Lean air adhart
|
||||||
hint_html: "<strong>Gliocas:</strong> Chan iarr sinn am facal-faire agad ort a-rithist fad uair a thìde."
|
hint_html: "<strong>Gliocas:</strong> Chan iarr sinn am facal-faire agad ort a-rithist fad uair a thìde."
|
||||||
|
@ -1998,6 +2005,7 @@ gd:
|
||||||
instructions_html: Dèan lethbhreac dhen chòd gu h-ìosal is cuir a-steach ann an HTML na làraich-lìn agad e. An uairsin, cuir seòladh na làraich-lìn agad ri fear dhe na raointean a bharrachd air a’ phròifil agad o thaba “Deasaich a’ phròifil” agus sàbhail na h-atharraichean.
|
instructions_html: Dèan lethbhreac dhen chòd gu h-ìosal is cuir a-steach ann an HTML na làraich-lìn agad e. An uairsin, cuir seòladh na làraich-lìn agad ri fear dhe na raointean a bharrachd air a’ phròifil agad o thaba “Deasaich a’ phròifil” agus sàbhail na h-atharraichean.
|
||||||
verification: Dearbhadh
|
verification: Dearbhadh
|
||||||
verified_links: Na ceanglaichean dearbhte agad
|
verified_links: Na ceanglaichean dearbhte agad
|
||||||
|
website_verification: Dearbhadh làraich-lìn
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Cuir iuchair tèarainteachd ùr ris
|
add: Cuir iuchair tèarainteachd ùr ris
|
||||||
create:
|
create:
|
||||||
|
|
|
@ -421,9 +421,21 @@ lt:
|
||||||
domain: Domenas
|
domain: Domenas
|
||||||
new:
|
new:
|
||||||
create: Pridėto domeną
|
create: Pridėto domeną
|
||||||
|
export_domain_allows:
|
||||||
|
new:
|
||||||
|
title: Importuoti domeno leidžiamus
|
||||||
|
no_file: Nėra pasirinkto failo
|
||||||
export_domain_blocks:
|
export_domain_blocks:
|
||||||
import:
|
import:
|
||||||
description_html: Netrukus importuosi domenų blokavimų sąrašą. Labai atidžiai peržiūrėk šį sąrašą, ypač jei ne tu jį sudarei.
|
description_html: Netrukus importuosi domenų blokavimų sąrašą. Labai atidžiai peržiūrėk šį sąrašą, ypač jei ne tu jį sudarei.
|
||||||
|
existing_relationships_warning: Esami sekimo sąryšiai
|
||||||
|
private_comment_description_html: 'Kad būtų lengviau atsekti, iš kur importuoti blokavimai, importuoti blokavimai bus kuriami su šiuo privačiu komentaru: <q>%{comment}</q>'
|
||||||
|
private_comment_template: Importuota iš %{source}, %{date}
|
||||||
|
title: Importuoti domeno blokavimus
|
||||||
|
invalid_domain_block: 'Vienas ar daugiau domenų blokavimų buvo praleisti dėl toliau nurodytos (-ų) klaidos (-ų): %{error}'
|
||||||
|
new:
|
||||||
|
title: Importuoti domeno blokavimus
|
||||||
|
no_file: Nėra pasirinkto failo
|
||||||
follow_recommendations:
|
follow_recommendations:
|
||||||
language: Kalbui
|
language: Kalbui
|
||||||
status: Būsena
|
status: Būsena
|
||||||
|
@ -853,18 +865,18 @@ lt:
|
||||||
exports:
|
exports:
|
||||||
archive_takeout:
|
archive_takeout:
|
||||||
date: Data
|
date: Data
|
||||||
download: Parsisiųsti archyvą
|
download: Atsisiųsti archyvą
|
||||||
hint_html: Jūs galite prašyti savo <strong>įrašų bei medijos</strong> archyvo. Eksportuota informacija bus ActivityPub formatu, skaitoma suderintų programų. Galite prašyti archyvo, kas 7 dienas.
|
hint_html: Gali paprašyti savo <strong>įrašų ir įkeltos medijos</strong> archyvo. Eksportuoti duomenys bus „ActivityPub“ formatu, kurį galima perskaityti bet kuria suderinama programine įranga. Archyvo galima prašyti kas 7 dienas.
|
||||||
in_progress: Sudaromas archyvas...
|
in_progress: Sudaromas archyvas...
|
||||||
request: Prašyti savo archyvo
|
request: Prašyti savo archyvo
|
||||||
size: Dydis
|
size: Dydis
|
||||||
blocks: Jūs blokuojate
|
blocks: Blokuoji
|
||||||
bookmarks: Žymės
|
bookmarks: Žymės
|
||||||
csv: CSV
|
csv: CSV
|
||||||
domain_blocks: Domeno blokai
|
domain_blocks: Domeno blokavimai
|
||||||
lists: Sąrašai
|
lists: Sąrašai
|
||||||
mutes: Jūs tildote
|
mutes: Nutildei
|
||||||
storage: Medijos sandėlis
|
storage: Medijos saugykla
|
||||||
featured_tags:
|
featured_tags:
|
||||||
add_new: Pridėti naują
|
add_new: Pridėti naują
|
||||||
hint_html: "<strong>Savo profilyje parodyk svarbiausius saitažodžius.</strong> Tai puikus įrankis kūrybiniams darbams ir ilgalaikiams projektams sekti, todėl svarbiausios saitažodžiai rodomi matomoje vietoje profilyje ir leidžia greitai pasiekti tavo paties įrašus."
|
hint_html: "<strong>Savo profilyje parodyk svarbiausius saitažodžius.</strong> Tai puikus įrankis kūrybiniams darbams ir ilgalaikiams projektams sekti, todėl svarbiausios saitažodžiai rodomi matomoje vietoje profilyje ir leidžia greitai pasiekti tavo paties įrašus."
|
||||||
|
@ -904,7 +916,7 @@ lt:
|
||||||
merge_long: Išsaugoti esančius įrašus ir pridėti naujus
|
merge_long: Išsaugoti esančius įrašus ir pridėti naujus
|
||||||
overwrite: Perrašyti
|
overwrite: Perrašyti
|
||||||
overwrite_long: Pakeisti senus įrašus naujais
|
overwrite_long: Pakeisti senus įrašus naujais
|
||||||
preface: Jūs galite importuoti informaciją iš kito serverio, tokią kaip sąrašą žmonių kuriuos sekate.
|
preface: Gali importuoti duomenis, kuriuos eksportavai iš kito serverio, pavyzdžiui, sekamų arba blokuojamų žmonių sąrašą.
|
||||||
success: Jūsų informacija sėkmingai įkelta ir bus apdorota kaip įmanoma greičiau
|
success: Jūsų informacija sėkmingai įkelta ir bus apdorota kaip įmanoma greičiau
|
||||||
types:
|
types:
|
||||||
blocking: Blokuojamų sąrašas
|
blocking: Blokuojamų sąrašas
|
||||||
|
@ -955,6 +967,8 @@ lt:
|
||||||
migrations:
|
migrations:
|
||||||
acct: Perkelta į
|
acct: Perkelta į
|
||||||
cancel: Atšaukti nukreipimą
|
cancel: Atšaukti nukreipimą
|
||||||
|
warning:
|
||||||
|
disabled_account: Po to tavo dabartine paskyra nebus galima naudotis visiškai. Tačiau turėsi prieigą prie duomenų eksporto ir pakartotinio aktyvavimo.
|
||||||
moderation:
|
moderation:
|
||||||
title: Prižiūrėjimas
|
title: Prižiūrėjimas
|
||||||
notification_mailer:
|
notification_mailer:
|
||||||
|
@ -1079,6 +1093,7 @@ lt:
|
||||||
export: Duomenų eksportas
|
export: Duomenų eksportas
|
||||||
featured_tags: Rodomi saitažodžiai
|
featured_tags: Rodomi saitažodžiai
|
||||||
import: Importuoti
|
import: Importuoti
|
||||||
|
import_and_export: Importas ir eksportas
|
||||||
migrate: Paskyros migracija
|
migrate: Paskyros migracija
|
||||||
notifications: El. laiško pranešimai
|
notifications: El. laiško pranešimai
|
||||||
preferences: Nuostatos
|
preferences: Nuostatos
|
||||||
|
|
|
@ -461,6 +461,9 @@ lv:
|
||||||
title: Sekošanas ieteikumi
|
title: Sekošanas ieteikumi
|
||||||
unsuppress: Atjaunot sekošanas rekomendāciju
|
unsuppress: Atjaunot sekošanas rekomendāciju
|
||||||
instances:
|
instances:
|
||||||
|
audit_log:
|
||||||
|
title: Nesenie pārbaudes žurnāli
|
||||||
|
view_all: Skatīt pilnus pārbaudes žurnālus
|
||||||
availability:
|
availability:
|
||||||
description_html:
|
description_html:
|
||||||
one: Ja piegāde uz domēnu neizdodas <strong>%{count} dienu</strong> bez panākumiem, turpmāki piegādes mēģinājumi netiks veikti, ja vien netiks saņemta piegāde <em>no</em> domēna.
|
one: Ja piegāde uz domēnu neizdodas <strong>%{count} dienu</strong> bez panākumiem, turpmāki piegādes mēģinājumi netiks veikti, ja vien netiks saņemta piegāde <em>no</em> domēna.
|
||||||
|
@ -591,7 +594,9 @@ lv:
|
||||||
resolve_description_html: Pret norādīto kontu netiks veiktas nekādas darbības, netiks reģistrēts brīdinājums, un ziņojums tiks slēgts.
|
resolve_description_html: Pret norādīto kontu netiks veiktas nekādas darbības, netiks reģistrēts brīdinājums, un ziņojums tiks slēgts.
|
||||||
silence_description_html: Konts būs redzams tikai tiem, kas tam jau seko vai meklē to manuāli, ievērojami ierobežojot tā sasniedzamību. To vienmēr var atgriezt. Tiek aizvērti visi šī konta pārskati.
|
silence_description_html: Konts būs redzams tikai tiem, kas tam jau seko vai meklē to manuāli, ievērojami ierobežojot tā sasniedzamību. To vienmēr var atgriezt. Tiek aizvērti visi šī konta pārskati.
|
||||||
suspend_description_html: Konts un viss tā saturs nebūs pieejams un galu galā tiks izdzēsts, un mijiedarbība ar to nebūs iespējama. Atgriežams 30 dienu laikā. Tiek aizvērti visi šī konta pārskati.
|
suspend_description_html: Konts un viss tā saturs nebūs pieejams un galu galā tiks izdzēsts, un mijiedarbība ar to nebūs iespējama. Atgriežams 30 dienu laikā. Tiek aizvērti visi šī konta pārskati.
|
||||||
|
actions_description_html: Izlem, kādas darbības jāveic, lai atrisinātu šo ziņojumu. Ja tiks pieņemti sodoši mēri pret kontu, par kuru ziņots, tam e-pastā tiks nosūtīts paziņojums, izņemot gadījumus, kad ir atlasīta kategorija <strong>Mēstules</strong>.
|
||||||
actions_description_remote_html: Izlem, kādas darbības jāveic, lai atrisinātu šo ziņojumu. Tas ietekmēs tikai to, kā <strong>tavs</strong> serveris sazinās ar šo attālo kontu un apstrādā tā saturu.
|
actions_description_remote_html: Izlem, kādas darbības jāveic, lai atrisinātu šo ziņojumu. Tas ietekmēs tikai to, kā <strong>tavs</strong> serveris sazinās ar šo attālo kontu un apstrādā tā saturu.
|
||||||
|
actions_no_posts: Šim ziņojumam nav saistītu ierakstu, kurus izdzēst
|
||||||
add_to_report: Pievienot varāk paziņošanai
|
add_to_report: Pievienot varāk paziņošanai
|
||||||
are_you_sure: Vai esi pārliecināts?
|
are_you_sure: Vai esi pārliecināts?
|
||||||
assign_to_self: Piešķirt man
|
assign_to_self: Piešķirt man
|
||||||
|
@ -1120,7 +1125,7 @@ lv:
|
||||||
confirm: Turpināt
|
confirm: Turpināt
|
||||||
hint_html: "<strong>Padoms:</strong> Nākamās stundas laikā mēs tev vairs neprasīsim paroli."
|
hint_html: "<strong>Padoms:</strong> Nākamās stundas laikā mēs tev vairs neprasīsim paroli."
|
||||||
invalid_password: Nepareiza parole
|
invalid_password: Nepareiza parole
|
||||||
prompt: Lai turpinātu, apstiprini paroli
|
prompt: Lai turpinātu, jāapstiprina parole
|
||||||
crypto:
|
crypto:
|
||||||
errors:
|
errors:
|
||||||
invalid_key: nav derīga Ed25519 vai Curve25519 atslēga
|
invalid_key: nav derīga Ed25519 vai Curve25519 atslēga
|
||||||
|
|
|
@ -24,6 +24,7 @@ pt-PT:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Executar acção
|
action: Executar acção
|
||||||
|
already_silenced: Esta conta já foi limitada.
|
||||||
already_suspended: Esta conta já foi suspensa.
|
already_suspended: Esta conta já foi suspensa.
|
||||||
title: Executar ação de moderação em %{acct}
|
title: Executar ação de moderação em %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -272,6 +273,7 @@ pt-PT:
|
||||||
reject_user_html: "%{name} rejeitou a inscrição de %{target}"
|
reject_user_html: "%{name} rejeitou a inscrição de %{target}"
|
||||||
remove_avatar_user_html: "%{name} removeu a imagem de perfil de %{target}"
|
remove_avatar_user_html: "%{name} removeu a imagem de perfil de %{target}"
|
||||||
reopen_report_html: "%{name} reabriu a denúncia %{target}"
|
reopen_report_html: "%{name} reabriu a denúncia %{target}"
|
||||||
|
resend_user_html: "%{name} reenviou e-mail de confirmação para %{target}"
|
||||||
reset_password_user_html: "%{name} restabeleceu a palavra-passe do utilizador %{target}"
|
reset_password_user_html: "%{name} restabeleceu a palavra-passe do utilizador %{target}"
|
||||||
resolve_report_html: "%{name} resolveu a denúncia %{target}"
|
resolve_report_html: "%{name} resolveu a denúncia %{target}"
|
||||||
sensitive_account_html: "%{name} marcou a media de %{target} como sensível"
|
sensitive_account_html: "%{name} marcou a media de %{target} como sensível"
|
||||||
|
@ -432,6 +434,7 @@ pt-PT:
|
||||||
attempts_over_week:
|
attempts_over_week:
|
||||||
one: "%{count} tentativa na última semana"
|
one: "%{count} tentativa na última semana"
|
||||||
other: "%{count} tentativas de inscrição na última semana"
|
other: "%{count} tentativas de inscrição na última semana"
|
||||||
|
created_msg: Domínio de e-mail bloqueado com sucesso
|
||||||
delete: Eliminar
|
delete: Eliminar
|
||||||
dns:
|
dns:
|
||||||
types:
|
types:
|
||||||
|
@ -440,8 +443,12 @@ pt-PT:
|
||||||
new:
|
new:
|
||||||
create: Adicionar domínio
|
create: Adicionar domínio
|
||||||
resolve: Domínio de resolução
|
resolve: Domínio de resolução
|
||||||
|
title: Bloquear novo domínio de e-mail
|
||||||
|
no_email_domain_block_selected: Não foram alterados quaisquer bloqueios de domínios de e-mail, uma vez que nenhum foi selecionado
|
||||||
not_permitted: Não permitido
|
not_permitted: Não permitido
|
||||||
|
resolved_dns_records_hint_html: O nome de domínio resolve para os seguintes domínios MX, que são, em última análise, responsáveis por aceitar o e-mail. Bloquear um domínio MX irá bloquear as inscrições de qualquer endereço de e-mail que use o mesmo domínio MX, mesmo quando o nome de domínio visível é diferente. <strong>Cuidado para não bloquear os principais provedores de e-mail.</strong>
|
||||||
resolved_through_html: Resolvido através de %{domain}
|
resolved_through_html: Resolvido através de %{domain}
|
||||||
|
title: Domínios de e-mail bloqueados
|
||||||
export_domain_allows:
|
export_domain_allows:
|
||||||
new:
|
new:
|
||||||
title: Importar permissões de domínio
|
title: Importar permissões de domínio
|
||||||
|
@ -595,7 +602,9 @@ pt-PT:
|
||||||
resolve_description_html: Nenhuma ação será tomada contra a conta denunciada, não será registada nenhuma reprimenda, e a denúncia será fechada.
|
resolve_description_html: Nenhuma ação será tomada contra a conta denunciada, não será registada nenhuma reprimenda, e a denúncia será fechada.
|
||||||
silence_description_html: O perfil será visível apenas para aqueles que já o seguem ou o procurem manualmente, limitando fortemente o seu alcance. Pode sempre ser revertido. Encerrar todas as denúncias contra esta conta.
|
silence_description_html: O perfil será visível apenas para aqueles que já o seguem ou o procurem manualmente, limitando fortemente o seu alcance. Pode sempre ser revertido. Encerrar todas as denúncias contra esta conta.
|
||||||
suspend_description_html: A conta e todo o seu conteúdo ficará inacessível e, eventualmente apagado, pelo que interagir com ela será impossível. Reversível durante 30 dias. Encerra todas as denúncias contra esta conta.
|
suspend_description_html: A conta e todo o seu conteúdo ficará inacessível e, eventualmente apagado, pelo que interagir com ela será impossível. Reversível durante 30 dias. Encerra todas as denúncias contra esta conta.
|
||||||
|
actions_description_html: Decida a ação a tomar para resolver esta denúncia. Se decidir por uma ação punitiva contra a conta denunciada, um e-mail de notificação será enviado, excetuando quando selecionada a categoria <strong>Spam</strong>.
|
||||||
actions_description_remote_html: Decida quais as medidas a tomar para resolver esta denúncia. Isso apenas afetará como <strong>o seu</strong> servido comunica com esta conta remota e gere o seu conteúdo.
|
actions_description_remote_html: Decida quais as medidas a tomar para resolver esta denúncia. Isso apenas afetará como <strong>o seu</strong> servido comunica com esta conta remota e gere o seu conteúdo.
|
||||||
|
actions_no_posts: Este relatório não tem nenhuma publicação associada para eliminar
|
||||||
add_to_report: Adicionar mais à denúncia
|
add_to_report: Adicionar mais à denúncia
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Já suspenso neste servidor
|
local: Já suspenso neste servidor
|
||||||
|
@ -659,6 +668,7 @@ pt-PT:
|
||||||
delete_data_html: Eliminar o perfil de <strong>@%{acct}</strong> e conteúdos daqui a 30 dias, a menos que entretanto sejam suspensos
|
delete_data_html: Eliminar o perfil de <strong>@%{acct}</strong> e conteúdos daqui a 30 dias, a menos que entretanto sejam suspensos
|
||||||
preview_preamble_html: "<strong>@%{acct}</strong> receberá um aviso com o seguinte conteúdo:"
|
preview_preamble_html: "<strong>@%{acct}</strong> receberá um aviso com o seguinte conteúdo:"
|
||||||
record_strike_html: Registar um ataque contra <strong>@%{acct}</strong> para ajudar a escalar futuras violações desta conta
|
record_strike_html: Registar um ataque contra <strong>@%{acct}</strong> para ajudar a escalar futuras violações desta conta
|
||||||
|
send_email_html: Enviar um e-mail de aviso a <strong>@%{acct}</strong>
|
||||||
warning_placeholder: Argumentos adicionais opcionais para a acção de moderação.
|
warning_placeholder: Argumentos adicionais opcionais para a acção de moderação.
|
||||||
target_origin: Origem da conta denunciada
|
target_origin: Origem da conta denunciada
|
||||||
title: Denúncias
|
title: Denúncias
|
||||||
|
@ -698,6 +708,7 @@ pt-PT:
|
||||||
manage_appeals: Gerir apelos
|
manage_appeals: Gerir apelos
|
||||||
manage_appeals_description: Permite aos utilizadores rever recursos de moderação
|
manage_appeals_description: Permite aos utilizadores rever recursos de moderação
|
||||||
manage_blocks: Gerir bloqueios
|
manage_blocks: Gerir bloqueios
|
||||||
|
manage_blocks_description: Permite aos utilizadores bloquear fornecedores de e-mail e endereços IP
|
||||||
manage_custom_emojis: Gerir emojis personalizados
|
manage_custom_emojis: Gerir emojis personalizados
|
||||||
manage_custom_emojis_description: Permite aos utilizadores gerirem os emojis personalizados do servidor
|
manage_custom_emojis_description: Permite aos utilizadores gerirem os emojis personalizados do servidor
|
||||||
manage_federation: Gerir federação
|
manage_federation: Gerir federação
|
||||||
|
@ -715,6 +726,7 @@ pt-PT:
|
||||||
manage_taxonomies: Gerir taxonomias
|
manage_taxonomies: Gerir taxonomias
|
||||||
manage_taxonomies_description: Permite aos utilizadores rever o conteúdo em tendência e atualizar as configurações de hashtag
|
manage_taxonomies_description: Permite aos utilizadores rever o conteúdo em tendência e atualizar as configurações de hashtag
|
||||||
manage_user_access: Gerir acesso de utilizador
|
manage_user_access: Gerir acesso de utilizador
|
||||||
|
manage_user_access_description: Permite aos utilizadores desativar a autenticação de dois factores de outros utilizadores, alterar o seu e-mail e reiniciar a sua palavra-passe
|
||||||
manage_users: Gerir utilizadores
|
manage_users: Gerir utilizadores
|
||||||
manage_users_description: Permite aos utilizadores ver os detalhes de outros utilizadores e executar ações de moderação contra eles
|
manage_users_description: Permite aos utilizadores ver os detalhes de outros utilizadores e executar ações de moderação contra eles
|
||||||
manage_webhooks: Gerir webhooks
|
manage_webhooks: Gerir webhooks
|
||||||
|
@ -789,6 +801,7 @@ pt-PT:
|
||||||
destroyed_msg: Envio do site eliminado com sucesso!
|
destroyed_msg: Envio do site eliminado com sucesso!
|
||||||
software_updates:
|
software_updates:
|
||||||
critical_update: Crítico — por favor, atualize rapidamente
|
critical_update: Crítico — por favor, atualize rapidamente
|
||||||
|
description: Recomenda-se que mantenha a sua instalação do Mastodon atualizada para beneficiar das últimas correções e funcionalidades. Além disso, é por vezes crítico atualizar o Mastodon de forma atempada para evitar problemas de segurança. Por estas razões, o Mastodon verifica se há actualizações a cada 30 minutos e notifica-o de acordo com as suas preferências de notificação por e-mail.
|
||||||
documentation_link: Saber mais
|
documentation_link: Saber mais
|
||||||
release_notes: Notas de lançamento
|
release_notes: Notas de lançamento
|
||||||
title: Atualizações disponíveis
|
title: Atualizações disponíveis
|
||||||
|
@ -888,6 +901,7 @@ pt-PT:
|
||||||
name: Nome
|
name: Nome
|
||||||
newest: Mais recente
|
newest: Mais recente
|
||||||
oldest: Mais antiga
|
oldest: Mais antiga
|
||||||
|
open: Visualizar Publicamente
|
||||||
reset: Repor
|
reset: Repor
|
||||||
review: Estado da revisão
|
review: Estado da revisão
|
||||||
search: Pesquisar
|
search: Pesquisar
|
||||||
|
@ -897,10 +911,16 @@ pt-PT:
|
||||||
trends:
|
trends:
|
||||||
allow: Permitir
|
allow: Permitir
|
||||||
approved: Aprovado
|
approved: Aprovado
|
||||||
|
confirm_allow: Tem a certeza que pretende permitir as etiquetas selecionadas?
|
||||||
|
confirm_disallow: Tem a certeza que pretende rejeitar as etiquetas selecionadas?
|
||||||
disallow: Não permitir
|
disallow: Não permitir
|
||||||
links:
|
links:
|
||||||
allow: Permitir hiperligação
|
allow: Permitir hiperligação
|
||||||
allow_provider: Permitir editor
|
allow_provider: Permitir editor
|
||||||
|
confirm_allow: Tem a certeza que pretende permitir as hiperligações selecionadas?
|
||||||
|
confirm_allow_provider: Tem a certeza que pretende permitir os fornecedores selecionados?
|
||||||
|
confirm_disallow: Tem a certeza que pretende rejeitar as hiperligações selecionadas?
|
||||||
|
confirm_disallow_provider: Tem a certeza que pretende rejeitar os fornecedores selecionados?
|
||||||
description_html: Estas são as ligações que presentemente estão a ser muito partilhadas por contas visíveis pelo seu servidor. Estas podem ajudar os seus utilizador a descobrir o que está a acontecer no mundo. Nenhuma ligação é exibida publicamente até que o editor a aprove. Também pode permitir ou rejeitar ligações em avulso.
|
description_html: Estas são as ligações que presentemente estão a ser muito partilhadas por contas visíveis pelo seu servidor. Estas podem ajudar os seus utilizador a descobrir o que está a acontecer no mundo. Nenhuma ligação é exibida publicamente até que o editor a aprove. Também pode permitir ou rejeitar ligações em avulso.
|
||||||
disallow: Não permitir ligação
|
disallow: Não permitir ligação
|
||||||
disallow_provider: Não permitir editor
|
disallow_provider: Não permitir editor
|
||||||
|
@ -924,6 +944,10 @@ pt-PT:
|
||||||
statuses:
|
statuses:
|
||||||
allow: Permitir publicação
|
allow: Permitir publicação
|
||||||
allow_account: Permitir autor
|
allow_account: Permitir autor
|
||||||
|
confirm_allow: Tem a certeza que pretende aceitar os estados selecionados?
|
||||||
|
confirm_allow_account: Tem a certeza que pretende aceitar as contas selecionadas?
|
||||||
|
confirm_disallow: Tem a certeza que pretende rejeitar os estados selecionados?
|
||||||
|
confirm_disallow_account: Tem a certeza que pretende rejeitar as contas selecionadas?
|
||||||
description_html: Estas são publicações que o seu servidor conhece e que atualmente estão a ser frequentemente partilhadas e adicionadas aos favoritos. Isto pode ajudar os seus utilizadores, novos e retornados, a encontrar mais pessoas para seguir. Nenhuma publicação será exibida publicamente até que aprove o autor, e o autor permita que a sua conta seja sugerida a outros. Você também pode permitir ou rejeitar publicações individualmente.
|
description_html: Estas são publicações que o seu servidor conhece e que atualmente estão a ser frequentemente partilhadas e adicionadas aos favoritos. Isto pode ajudar os seus utilizadores, novos e retornados, a encontrar mais pessoas para seguir. Nenhuma publicação será exibida publicamente até que aprove o autor, e o autor permita que a sua conta seja sugerida a outros. Você também pode permitir ou rejeitar publicações individualmente.
|
||||||
disallow: Não permitir publicação
|
disallow: Não permitir publicação
|
||||||
disallow_account: Não permitir autor
|
disallow_account: Não permitir autor
|
||||||
|
@ -1041,7 +1065,9 @@ pt-PT:
|
||||||
guide_link_text: Todos podem contribuir.
|
guide_link_text: Todos podem contribuir.
|
||||||
sensitive_content: Conteúdo problemático
|
sensitive_content: Conteúdo problemático
|
||||||
application_mailer:
|
application_mailer:
|
||||||
|
notification_preferences: Alterar preferências de e-mail
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
|
settings: 'Alterar preferências de e-mail: %{link}'
|
||||||
unsubscribe: Cancelar subscrição
|
unsubscribe: Cancelar subscrição
|
||||||
view: 'Ver:'
|
view: 'Ver:'
|
||||||
view_profile: Ver perfil
|
view_profile: Ver perfil
|
||||||
|
@ -1061,6 +1087,7 @@ pt-PT:
|
||||||
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isto para que possamos evitar spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
|
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isto para que possamos evitar spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
|
||||||
title: Verificação de segurança
|
title: Verificação de segurança
|
||||||
confirmations:
|
confirmations:
|
||||||
|
awaiting_review: O seu endereço de e-mail está confirmado! A equipa de %{domain} está agora a analisar a sua inscrição. Receberá um e-mail se a sua conta for aprovada!
|
||||||
awaiting_review_title: A sua inscrição está a ser revista
|
awaiting_review_title: A sua inscrição está a ser revista
|
||||||
clicking_this_link: clicar nesta hiperligação
|
clicking_this_link: clicar nesta hiperligação
|
||||||
login_link: iniciar sessão
|
login_link: iniciar sessão
|
||||||
|
@ -1068,6 +1095,7 @@ pt-PT:
|
||||||
redirect_to_app_html: Devia ter sido reencaminhado para a aplicação <strong>%{app_name}</strong>. Se isso não aconteceu, tente %{clicking_this_link} ou volte manualmente para a aplicação.
|
redirect_to_app_html: Devia ter sido reencaminhado para a aplicação <strong>%{app_name}</strong>. Se isso não aconteceu, tente %{clicking_this_link} ou volte manualmente para a aplicação.
|
||||||
registration_complete: O seu registo sem %{domain} está agora concluído!
|
registration_complete: O seu registo sem %{domain} está agora concluído!
|
||||||
welcome_title: Bem-vindo(a), %{name}!
|
welcome_title: Bem-vindo(a), %{name}!
|
||||||
|
wrong_email_hint: Se este endereço de correio eletrónico não estiver correto, pode alterá-lo nas definições de conta.
|
||||||
delete_account: Eliminar conta
|
delete_account: Eliminar conta
|
||||||
delete_account_html: Se deseja eliminar a sua conta, pode <a href="%{path}">continuar aqui</a>. Uma confirmação será solicitada.
|
delete_account_html: Se deseja eliminar a sua conta, pode <a href="%{path}">continuar aqui</a>. Uma confirmação será solicitada.
|
||||||
description:
|
description:
|
||||||
|
@ -1088,6 +1116,7 @@ pt-PT:
|
||||||
or_log_in_with: Ou iniciar sessão com
|
or_log_in_with: Ou iniciar sessão com
|
||||||
privacy_policy_agreement_html: Eu li e concordo com a <a href="%{privacy_policy_path}" target="_blank">política de privacidade</a>
|
privacy_policy_agreement_html: Eu li e concordo com a <a href="%{privacy_policy_path}" target="_blank">política de privacidade</a>
|
||||||
progress:
|
progress:
|
||||||
|
confirm: Confirmar e-mail
|
||||||
details: Os seus dados
|
details: Os seus dados
|
||||||
review: A nossa avaliação
|
review: A nossa avaliação
|
||||||
rules: Aceitar regras
|
rules: Aceitar regras
|
||||||
|
@ -1109,8 +1138,10 @@ pt-PT:
|
||||||
security: Alterar palavra-passe
|
security: Alterar palavra-passe
|
||||||
set_new_password: Editar palavra-passe
|
set_new_password: Editar palavra-passe
|
||||||
setup:
|
setup:
|
||||||
|
email_below_hint_html: Verifique a sua pasta de spam ou solicite outra. Pode corrigir o seu endereço de e-mail se estiver errado.
|
||||||
email_settings_hint_html: Clique no link que enviamos para verificar %{email}. Esperaremos aqui.
|
email_settings_hint_html: Clique no link que enviamos para verificar %{email}. Esperaremos aqui.
|
||||||
link_not_received: Não recebeu um link?
|
link_not_received: Não recebeu um link?
|
||||||
|
new_confirmation_instructions_sent: Irá receber uma nova mensagem de e-mail com a ligação de confirmação dentro de alguns minutos!
|
||||||
title: Verifique a caixa de entrada do seu e-mail
|
title: Verifique a caixa de entrada do seu e-mail
|
||||||
sign_in:
|
sign_in:
|
||||||
preamble_html: Iniciar sessão com as suas credenciais de <strong>%{domain}</strong>. Se a sua conta estiver hospedada noutro servidor, não poderá iniciar sessão aqui.
|
preamble_html: Iniciar sessão com as suas credenciais de <strong>%{domain}</strong>. Se a sua conta estiver hospedada noutro servidor, não poderá iniciar sessão aqui.
|
||||||
|
@ -1121,12 +1152,20 @@ pt-PT:
|
||||||
title: Vamos lá inscrevê-lo em %{domain}.
|
title: Vamos lá inscrevê-lo em %{domain}.
|
||||||
status:
|
status:
|
||||||
account_status: Estado da conta
|
account_status: Estado da conta
|
||||||
|
confirming: A aguardar a confirmação do e-mail para ser concluída.
|
||||||
functional: A sua conta está totalmente operacional.
|
functional: A sua conta está totalmente operacional.
|
||||||
|
pending: A sua inscrição está a ser analisada pela nossa equipa. Este processo pode demorar algum tempo. Receberá um e-mail se a sua inscrição for aprovada.
|
||||||
redirecting_to: A sua conta está inativa porque está atualmente a ser redirecionada para %{acct}.
|
redirecting_to: A sua conta está inativa porque está atualmente a ser redirecionada para %{acct}.
|
||||||
self_destruct: Como %{domain} vai fechar, só terá acesso limitado à sua conta.
|
self_destruct: Como %{domain} vai fechar, só terá acesso limitado à sua conta.
|
||||||
view_strikes: Veja as reprimendas anteriores sobre a sua conta
|
view_strikes: Veja as reprimendas anteriores sobre a sua conta
|
||||||
too_fast: Formulário enviado demasiado rapidamente, tente novamente.
|
too_fast: Formulário enviado demasiado rapidamente, tente novamente.
|
||||||
use_security_key: Usar chave de segurança
|
use_security_key: Usar chave de segurança
|
||||||
|
author_attribution:
|
||||||
|
example_title: Texto de exemplo
|
||||||
|
hint_html: Controle a forma como é creditado quando as hiperligações são partilhadas no Mastodon.
|
||||||
|
more_from_html: Mais de %{name}
|
||||||
|
s_blog: Blog de %{name}
|
||||||
|
title: Atribuição de autor
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Continuar
|
confirm: Continuar
|
||||||
hint_html: "<strong>Dica:</strong> Não vamos pedir novamente a sua palavra-passe durante a próxima hora."
|
hint_html: "<strong>Dica:</strong> Não vamos pedir novamente a sua palavra-passe durante a próxima hora."
|
||||||
|
@ -1164,6 +1203,9 @@ pt-PT:
|
||||||
before: 'Antes de continuar, por favor leia cuidadosamente estas notas:'
|
before: 'Antes de continuar, por favor leia cuidadosamente estas notas:'
|
||||||
caches: O conteúdo que foi armazenado em cache por outras instâncias pode perdurar
|
caches: O conteúdo que foi armazenado em cache por outras instâncias pode perdurar
|
||||||
data_removal: As suas publicações e outros dados serão eliminados permanentemente
|
data_removal: As suas publicações e outros dados serão eliminados permanentemente
|
||||||
|
email_change_html: Pode <a href="%{path}">alterar o seu e-mail</a> sem eliminar a sua conta
|
||||||
|
email_contact_html: Se ainda assim não o recebeu, pode enviar um e-mail para <a href="mailto:%{email}">%{email}</a> para obter ajuda
|
||||||
|
email_reconfirmation_html: Se não recebeu a mensagem de e-mail de confirmação, pode <a href="%{path}">solicitá-la novamente</a>
|
||||||
irreversible: Não será possível restaurar ou reativar sua conta
|
irreversible: Não será possível restaurar ou reativar sua conta
|
||||||
more_details_html: Para mais pormenores, leia a <a href="%{terms_path}">política de privacidade</a>.
|
more_details_html: Para mais pormenores, leia a <a href="%{terms_path}">política de privacidade</a>.
|
||||||
username_available: O seu nome de utilizador ficará novamente disponível
|
username_available: O seu nome de utilizador ficará novamente disponível
|
||||||
|
@ -1394,6 +1436,7 @@ pt-PT:
|
||||||
authentication_methods:
|
authentication_methods:
|
||||||
otp: aplicação de autenticação em duas etapas
|
otp: aplicação de autenticação em duas etapas
|
||||||
password: palavra-passe
|
password: palavra-passe
|
||||||
|
sign_in_token: código de segurança de e-mail
|
||||||
webauthn: chaves de segurança
|
webauthn: chaves de segurança
|
||||||
description_html: Se vê atividade que não reconhece, considere alterar a sua palavra-passe e ativar a autenticação em duas etapas.
|
description_html: Se vê atividade que não reconhece, considere alterar a sua palavra-passe e ativar a autenticação em duas etapas.
|
||||||
empty: Sem histórico de autenticação disponível
|
empty: Sem histórico de autenticação disponível
|
||||||
|
|
|
@ -3,6 +3,7 @@ et:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Kaitseb valede omistuste eest.
|
||||||
discoverable: Su profiili ja avalikke postitusi võidakse Mastodoni erinevates piirkondades esile tõsta või soovitada ning su profiili soovitada teistele kasutajatele.
|
discoverable: Su profiili ja avalikke postitusi võidakse Mastodoni erinevates piirkondades esile tõsta või soovitada ning su profiili soovitada teistele kasutajatele.
|
||||||
display_name: Su täisnimi või naljanimi.
|
display_name: Su täisnimi või naljanimi.
|
||||||
fields: Su koduleht, sugu, vanus. Mistahes, mida soovid.
|
fields: Su koduleht, sugu, vanus. Mistahes, mida soovid.
|
||||||
|
@ -143,6 +144,7 @@ et:
|
||||||
url: Kuhu sündmused saadetakse
|
url: Kuhu sündmused saadetakse
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Luba vaid kindlad veebilehed
|
||||||
discoverable: Tõsta postitused ja profiil avastamise algoritmides esile
|
discoverable: Tõsta postitused ja profiil avastamise algoritmides esile
|
||||||
fields:
|
fields:
|
||||||
name: Nimetus
|
name: Nimetus
|
||||||
|
|
|
@ -78,9 +78,11 @@ fr-CA:
|
||||||
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire
|
activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire
|
||||||
|
app_icon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
||||||
backups_retention_period: Les utilisateur·rice·s ont la possibilité de générer des archives de leurs messages pour les télécharger plus tard. Lorsqu'elles sont définies à une valeur positive, ces archives seront automatiquement supprimées de votre stockage après le nombre de jours spécifié.
|
backups_retention_period: Les utilisateur·rice·s ont la possibilité de générer des archives de leurs messages pour les télécharger plus tard. Lorsqu'elles sont définies à une valeur positive, ces archives seront automatiquement supprimées de votre stockage après le nombre de jours spécifié.
|
||||||
bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs.
|
bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs.
|
||||||
closed_registrations_message: Affiché lorsque les inscriptions sont fermées
|
closed_registrations_message: Affiché lorsque les inscriptions sont fermées
|
||||||
|
content_cache_retention_period: Tous les messages provenant d'autres serveurs (y compris les partages et les réponses) seront supprimés passé le nombre de jours spécifié, sans tenir compte de l'interaction de l'utilisateur·rice local·e avec ces messages. Cela inclut les messages qu'un·e utilisateur·rice aurait marqué comme signets ou comme favoris. Les mentions privées entre utilisateur·rice·s de différentes instances seront également perdues et impossibles à restaurer. L'utilisation de ce paramètre est destinée à des instances spécifiques et contrevient à de nombreuses attentes des utilisateurs lorsqu'elle est appliquée à des fins d'utilisation ordinaires.
|
||||||
custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon.
|
custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon.
|
||||||
favicon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
favicon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
||||||
mascot: Remplace l'illustration dans l'interface Web avancée.
|
mascot: Remplace l'illustration dans l'interface Web avancée.
|
||||||
|
|
|
@ -78,9 +78,11 @@ fr:
|
||||||
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire
|
activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire
|
||||||
|
app_icon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
||||||
backups_retention_period: Les utilisateur·rice·s ont la possibilité de générer des archives de leurs messages pour les télécharger plus tard. Lorsqu'elles sont définies à une valeur positive, ces archives seront automatiquement supprimées de votre stockage après le nombre de jours spécifié.
|
backups_retention_period: Les utilisateur·rice·s ont la possibilité de générer des archives de leurs messages pour les télécharger plus tard. Lorsqu'elles sont définies à une valeur positive, ces archives seront automatiquement supprimées de votre stockage après le nombre de jours spécifié.
|
||||||
bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs.
|
bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs.
|
||||||
closed_registrations_message: Affiché lorsque les inscriptions sont fermées
|
closed_registrations_message: Affiché lorsque les inscriptions sont fermées
|
||||||
|
content_cache_retention_period: Tous les messages provenant d'autres serveurs (y compris les partages et les réponses) seront supprimés passé le nombre de jours spécifié, sans tenir compte de l'interaction de l'utilisateur·rice local·e avec ces messages. Cela inclut les messages qu'un·e utilisateur·rice aurait marqué comme signets ou comme favoris. Les mentions privées entre utilisateur·rice·s de différentes instances seront également perdues et impossibles à restaurer. L'utilisation de ce paramètre est destinée à des instances spécifiques et contrevient à de nombreuses attentes des utilisateurs lorsqu'elle est appliquée à des fins d'utilisation ordinaires.
|
||||||
custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon.
|
custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon.
|
||||||
favicon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
favicon: WEBP, PNG, GIF ou JPG. Remplace la favicon Mastodon par défaut avec une icône personnalisée.
|
||||||
mascot: Remplace l'illustration dans l'interface Web avancée.
|
mascot: Remplace l'illustration dans l'interface Web avancée.
|
||||||
|
|
|
@ -3,6 +3,7 @@ ga:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Cosnaíonn sé ó sannadh bréagach.
|
||||||
discoverable: Seans go mbeidh do phostálacha poiblí agus do phróifíl le feiceáil nó molta i réimsí éagsúla de Mastodon agus is féidir do phróifíl a mholadh d’úsáideoirí eile.
|
discoverable: Seans go mbeidh do phostálacha poiblí agus do phróifíl le feiceáil nó molta i réimsí éagsúla de Mastodon agus is féidir do phróifíl a mholadh d’úsáideoirí eile.
|
||||||
display_name: D'ainm iomlán nó d'ainm spraoi.
|
display_name: D'ainm iomlán nó d'ainm spraoi.
|
||||||
fields: Do leathanach baile, forainmneacha, aois, rud ar bith is mian leat.
|
fields: Do leathanach baile, forainmneacha, aois, rud ar bith is mian leat.
|
||||||
|
@ -143,6 +144,7 @@ ga:
|
||||||
url: An áit a seolfar imeachtaí chuig
|
url: An áit a seolfar imeachtaí chuig
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Ná ceadaigh ach láithreáin ghréasáin ar leith
|
||||||
discoverable: Próifíl gné agus postálacha in halgartaim fionnachtana
|
discoverable: Próifíl gné agus postálacha in halgartaim fionnachtana
|
||||||
fields:
|
fields:
|
||||||
name: Lipéad
|
name: Lipéad
|
||||||
|
|
|
@ -3,6 +3,7 @@ gd:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Dìonadh seo o bhuaidh-aithrisean cearra.
|
||||||
discoverable: Dh’fhaoidte gun dèid na postaichean poblach ’s a’ phròifil agad a bhrosnachadh no a mholadh ann an caochladh roinnean de Mhastodon agus gun dèid a’ phròifil agad a mholadh do chàch.
|
discoverable: Dh’fhaoidte gun dèid na postaichean poblach ’s a’ phròifil agad a bhrosnachadh no a mholadh ann an caochladh roinnean de Mhastodon agus gun dèid a’ phròifil agad a mholadh do chàch.
|
||||||
display_name: D’ ainm slàn no spòrsail.
|
display_name: D’ ainm slàn no spòrsail.
|
||||||
fields: An duilleag-dhachaigh agad, roimhearan, aois, rud sam bith a thogras tu.
|
fields: An duilleag-dhachaigh agad, roimhearan, aois, rud sam bith a thogras tu.
|
||||||
|
@ -143,6 +144,7 @@ gd:
|
||||||
url: Far an dèid na tachartasan a chur
|
url: Far an dèid na tachartasan a chur
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Na ceadaich ach làraichean-lìnn sònraichte
|
||||||
discoverable: Brosnaich a’ phròifil is postaichean agad sna h-algairimean rùrachaidh
|
discoverable: Brosnaich a’ phròifil is postaichean agad sna h-algairimean rùrachaidh
|
||||||
fields:
|
fields:
|
||||||
name: Leubail
|
name: Leubail
|
||||||
|
|
|
@ -90,6 +90,8 @@ lt:
|
||||||
timeline_preview: Atsijungę lankytojai galės naršyti naujausius viešus įrašus, esančius serveryje.
|
timeline_preview: Atsijungę lankytojai galės naršyti naujausius viešus įrašus, esančius serveryje.
|
||||||
trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo.
|
trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo.
|
||||||
trends_as_landing_page: Rodyti tendencingą turinį atsijungusiems naudotojams ir lankytojams vietoj šio serverio aprašymo. Reikia, kad tendencijos būtų įjungtos.
|
trends_as_landing_page: Rodyti tendencingą turinį atsijungusiems naudotojams ir lankytojams vietoj šio serverio aprašymo. Reikia, kad tendencijos būtų įjungtos.
|
||||||
|
imports:
|
||||||
|
data: CSV failas, eksportuotas iš kito „Mastodon“ serverio.
|
||||||
invite_request:
|
invite_request:
|
||||||
text: Tai padės mums peržiūrėti tavo paraišką
|
text: Tai padės mums peržiūrėti tavo paraišką
|
||||||
rule:
|
rule:
|
||||||
|
|
|
@ -3,6 +3,7 @@ lv:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Aizsargā no nepatiesas piedēvēšanas.
|
||||||
discoverable: Tavas publiskās ziņas un profils var tikt piedāvāti vai ieteikti dažādās Mastodon vietās, un tavs profils var tikt ieteikts citiem lietotājiem.
|
discoverable: Tavas publiskās ziņas un profils var tikt piedāvāti vai ieteikti dažādās Mastodon vietās, un tavs profils var tikt ieteikts citiem lietotājiem.
|
||||||
display_name: Tavs pilnais vārds vai tavs joku vārds.
|
display_name: Tavs pilnais vārds vai tavs joku vārds.
|
||||||
fields: Tava mājas lapa, vietniekvārdi, vecums, viss, ko vēlies.
|
fields: Tava mājas lapa, vietniekvārdi, vecums, viss, ko vēlies.
|
||||||
|
@ -128,6 +129,7 @@ lv:
|
||||||
name: Tu vari mainīt tikai burtu lielumu, piemēram, lai tie būtu vieglāk lasāmi
|
name: Tu vari mainīt tikai burtu lielumu, piemēram, lai tie būtu vieglāk lasāmi
|
||||||
user:
|
user:
|
||||||
chosen_languages: Ja ieķeksēts, publiskos laika grafikos tiks parādītas tikai ziņas noteiktajās valodās
|
chosen_languages: Ja ieķeksēts, publiskos laika grafikos tiks parādītas tikai ziņas noteiktajās valodās
|
||||||
|
role: Loma nosaka, kādas lietotājam ir atļaujas.
|
||||||
user_role:
|
user_role:
|
||||||
color: Krāsa, kas jāizmanto lomai visā lietotāja saskarnē, kā RGB hex formātā
|
color: Krāsa, kas jāizmanto lomai visā lietotāja saskarnē, kā RGB hex formātā
|
||||||
highlighted: Tas padara lomu publiski redzamu
|
highlighted: Tas padara lomu publiski redzamu
|
||||||
|
@ -140,6 +142,7 @@ lv:
|
||||||
url: Kur notikumi tiks nosūtīti
|
url: Kur notikumi tiks nosūtīti
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Ļaut tikai noteiktas tīmekļvietnes
|
||||||
discoverable: Funkcijas profils un ziņas atklāšanas algoritmos
|
discoverable: Funkcijas profils un ziņas atklāšanas algoritmos
|
||||||
fields:
|
fields:
|
||||||
name: Marķējums
|
name: Marķējums
|
||||||
|
@ -208,6 +211,7 @@ lv:
|
||||||
setting_default_privacy: Publicēšanas privātums
|
setting_default_privacy: Publicēšanas privātums
|
||||||
setting_default_sensitive: Atļaut atzīmēt multividi kā sensitīvu
|
setting_default_sensitive: Atļaut atzīmēt multividi kā sensitīvu
|
||||||
setting_delete_modal: Parādīt apstiprinājuma dialogu pirms ziņas dzēšanas
|
setting_delete_modal: Parādīt apstiprinājuma dialogu pirms ziņas dzēšanas
|
||||||
|
setting_disable_hover_cards: Atspējot profila priekšskatījumu pēc kursora novietošanas
|
||||||
setting_disable_swiping: Atspējot vilkšanas kustības
|
setting_disable_swiping: Atspējot vilkšanas kustības
|
||||||
setting_display_media: Multivides rādīšana
|
setting_display_media: Multivides rādīšana
|
||||||
setting_display_media_default: Noklusējums
|
setting_display_media_default: Noklusējums
|
||||||
|
@ -239,11 +243,13 @@ lv:
|
||||||
warn: Paslēpt ar brīdinājumu
|
warn: Paslēpt ar brīdinājumu
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
activity_api_enabled: Publicējiet apkopotu statistiku par lietotāju darbībām API
|
activity_api_enabled: Publicējiet apkopotu statistiku par lietotāju darbībām API
|
||||||
|
app_icon: Lietotnes ikona
|
||||||
backups_retention_period: Lietotāja arhīva glabāšanas periods
|
backups_retention_period: Lietotāja arhīva glabāšanas periods
|
||||||
bootstrap_timeline_accounts: Vienmēr iesaki šos kontus jaunajiem lietotājiem
|
bootstrap_timeline_accounts: Vienmēr iesaki šos kontus jaunajiem lietotājiem
|
||||||
closed_registrations_message: Pielāgots ziņojums, ja reģistrēšanās nav pieejama
|
closed_registrations_message: Pielāgots ziņojums, ja reģistrēšanās nav pieejama
|
||||||
content_cache_retention_period: Attālā satura paturēšanas laika posms
|
content_cache_retention_period: Attālā satura paturēšanas laika posms
|
||||||
custom_css: Pielāgots CSS
|
custom_css: Pielāgots CSS
|
||||||
|
favicon: Favikona
|
||||||
mascot: Pielāgots talismans (mantots)
|
mascot: Pielāgots talismans (mantots)
|
||||||
media_cache_retention_period: Multivides kešatmiņas saglabāšanas periods
|
media_cache_retention_period: Multivides kešatmiņas saglabāšanas periods
|
||||||
peers_api_enabled: Publicēt API atklāto serveru sarakstu
|
peers_api_enabled: Publicēt API atklāto serveru sarakstu
|
||||||
|
@ -308,6 +314,7 @@ lv:
|
||||||
listable: Atļaut šim tēmturim parādīties meklējumos un ieteikumos
|
listable: Atļaut šim tēmturim parādīties meklējumos un ieteikumos
|
||||||
name: Tēmturis
|
name: Tēmturis
|
||||||
trendable: Atļaut šim tēmturim parādīties zem tendencēm
|
trendable: Atļaut šim tēmturim parādīties zem tendencēm
|
||||||
|
usable: Ļaut ierakstos vietēji izmantot šo tēmturi
|
||||||
user:
|
user:
|
||||||
role: Loma
|
role: Loma
|
||||||
time_zone: Laika josla
|
time_zone: Laika josla
|
||||||
|
|
|
@ -3,6 +3,7 @@ th:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: ปกป้องจากการระบุแหล่งที่มาที่ผิด
|
||||||
discoverable: อาจแสดงหรือแนะนำโพสต์และโปรไฟล์สาธารณะของคุณในพื้นที่ต่าง ๆ ของ Mastodon และอาจเสนอแนะโปรไฟล์ของคุณให้กับผู้ใช้อื่น ๆ
|
discoverable: อาจแสดงหรือแนะนำโพสต์และโปรไฟล์สาธารณะของคุณในพื้นที่ต่าง ๆ ของ Mastodon และอาจเสนอแนะโปรไฟล์ของคุณให้กับผู้ใช้อื่น ๆ
|
||||||
display_name: ชื่อเต็มของคุณหรือชื่อแบบสนุกสนานของคุณ
|
display_name: ชื่อเต็มของคุณหรือชื่อแบบสนุกสนานของคุณ
|
||||||
fields: หน้าแรก, สรรพนาม, อายุของคุณ สิ่งใดก็ตามที่คุณต้องการ
|
fields: หน้าแรก, สรรพนาม, อายุของคุณ สิ่งใดก็ตามที่คุณต้องการ
|
||||||
|
@ -143,6 +144,7 @@ th:
|
||||||
url: ที่ซึ่งจะส่งเหตุการณ์ไปยัง
|
url: ที่ซึ่งจะส่งเหตุการณ์ไปยัง
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: อนุญาตเฉพาะเว็บไซต์ที่เฉพาะเจาะจงเท่านั้น
|
||||||
discoverable: แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ
|
discoverable: แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ
|
||||||
fields:
|
fields:
|
||||||
name: ป้ายชื่อ
|
name: ป้ายชื่อ
|
||||||
|
|
|
@ -3,6 +3,7 @@ vi:
|
||||||
simple_form:
|
simple_form:
|
||||||
hints:
|
hints:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Bảo vệ khỏi những sự gán ghép sai.
|
||||||
discoverable: Các tút và hồ sơ công khai của bạn có thể được giới thiệu hoặc đề xuất ở nhiều khu vực khác nhau của Mastodon và hồ sơ của bạn có thể được đề xuất cho những người dùng khác.
|
discoverable: Các tút và hồ sơ công khai của bạn có thể được giới thiệu hoặc đề xuất ở nhiều khu vực khác nhau của Mastodon và hồ sơ của bạn có thể được đề xuất cho những người dùng khác.
|
||||||
display_name: Tên đầy đủ hoặc biệt danh đều được.
|
display_name: Tên đầy đủ hoặc biệt danh đều được.
|
||||||
fields: Trang blog của bạn, nghề nghiệp, tuổi hoặc bất cứ thứ gì.
|
fields: Trang blog của bạn, nghề nghiệp, tuổi hoặc bất cứ thứ gì.
|
||||||
|
@ -143,6 +144,7 @@ vi:
|
||||||
url: Nơi những sự kiện được gửi đến
|
url: Nơi những sự kiện được gửi đến
|
||||||
labels:
|
labels:
|
||||||
account:
|
account:
|
||||||
|
attribution_domains_as_text: Chỉ cho phép các website đặc biệt
|
||||||
discoverable: Cho phép khám phá hồ sơ
|
discoverable: Cho phép khám phá hồ sơ
|
||||||
fields:
|
fields:
|
||||||
name: Nhãn
|
name: Nhãn
|
||||||
|
|
|
@ -22,6 +22,7 @@ th:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: ทำการกระทำ
|
action: ทำการกระทำ
|
||||||
|
already_silenced: มีการจำกัดบัญชีนี้ไปแล้ว
|
||||||
already_suspended: มีการระงับบัญชีนี้ไปแล้ว
|
already_suspended: มีการระงับบัญชีนี้ไปแล้ว
|
||||||
title: ทำการกระทำการกลั่นกรองต่อ %{acct}
|
title: ทำการกระทำการกลั่นกรองต่อ %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -1141,6 +1142,12 @@ th:
|
||||||
view_strikes: ดูการดำเนินการที่ผ่านมาต่อบัญชีของคุณ
|
view_strikes: ดูการดำเนินการที่ผ่านมาต่อบัญชีของคุณ
|
||||||
too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง
|
too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง
|
||||||
use_security_key: ใช้กุญแจความปลอดภัย
|
use_security_key: ใช้กุญแจความปลอดภัย
|
||||||
|
author_attribution:
|
||||||
|
example_title: ข้อความตัวอย่าง
|
||||||
|
hint_html: ควบคุมวิธีที่ให้เครดิตแก่คุณเมื่อมีการแบ่งปันลิงก์ใน Mastodon
|
||||||
|
more_from_html: เพิ่มเติมจาก %{name}
|
||||||
|
s_blog: บล็อกของ %{name}
|
||||||
|
title: การระบุแหล่งที่มาผู้สร้าง
|
||||||
challenge:
|
challenge:
|
||||||
confirm: ดำเนินการต่อ
|
confirm: ดำเนินการต่อ
|
||||||
hint_html: "<strong>เคล็ดลับ:</strong> เราจะไม่ถามรหัสผ่านของคุณกับคุณสำหรับชั่วโมงถัดไป"
|
hint_html: "<strong>เคล็ดลับ:</strong> เราจะไม่ถามรหัสผ่านของคุณกับคุณสำหรับชั่วโมงถัดไป"
|
||||||
|
@ -1905,6 +1912,7 @@ th:
|
||||||
instructions_html: คัดลอกแล้ววางโค้ดด้านล่างลงใน HTML ของเว็บไซต์ของคุณ จากนั้นเพิ่มที่อยู่ของเว็บไซต์ของคุณลงในหนึ่งในช่องพิเศษในโปรไฟล์ของคุณจากแท็บ "แก้ไขโปรไฟล์" และบันทึกการเปลี่ยนแปลง
|
instructions_html: คัดลอกแล้ววางโค้ดด้านล่างลงใน HTML ของเว็บไซต์ของคุณ จากนั้นเพิ่มที่อยู่ของเว็บไซต์ของคุณลงในหนึ่งในช่องพิเศษในโปรไฟล์ของคุณจากแท็บ "แก้ไขโปรไฟล์" และบันทึกการเปลี่ยนแปลง
|
||||||
verification: การตรวจสอบ
|
verification: การตรวจสอบ
|
||||||
verified_links: ลิงก์ที่ยืนยันแล้วของคุณ
|
verified_links: ลิงก์ที่ยืนยันแล้วของคุณ
|
||||||
|
website_verification: การตรวจสอบเว็บไซต์
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: เพิ่มกุญแจความปลอดภัยใหม่
|
add: เพิ่มกุญแจความปลอดภัยใหม่
|
||||||
create:
|
create:
|
||||||
|
|
|
@ -22,6 +22,7 @@ vi:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Thực hiện hành động
|
action: Thực hiện hành động
|
||||||
|
already_silenced: Tài khoản này đã bị hạn chế.
|
||||||
already_suspended: Tài khoản này đã bị vô hiệu hóa.
|
already_suspended: Tài khoản này đã bị vô hiệu hóa.
|
||||||
title: Áp đặt kiểm duyệt với %{acct}
|
title: Áp đặt kiểm duyệt với %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
|
@ -1141,6 +1142,12 @@ vi:
|
||||||
view_strikes: Xem những lần cảnh cáo cũ
|
view_strikes: Xem những lần cảnh cáo cũ
|
||||||
too_fast: Nghi vấn đăng ký spam, xin thử lại.
|
too_fast: Nghi vấn đăng ký spam, xin thử lại.
|
||||||
use_security_key: Dùng khóa bảo mật
|
use_security_key: Dùng khóa bảo mật
|
||||||
|
author_attribution:
|
||||||
|
example_title: Văn bản mẫu
|
||||||
|
hint_html: Kiểm soát cách bạn được ghi nhận khi chia sẻ liên kết trên Mastodon.
|
||||||
|
more_from_html: Thêm từ %{name}
|
||||||
|
s_blog: "%{name}'s Blog"
|
||||||
|
title: Ghi nhận tác giả
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Tiếp tục
|
confirm: Tiếp tục
|
||||||
hint_html: "<strong>Mẹo:</strong> Chúng tôi sẽ không hỏi lại mật khẩu của bạn sau này."
|
hint_html: "<strong>Mẹo:</strong> Chúng tôi sẽ không hỏi lại mật khẩu của bạn sau này."
|
||||||
|
@ -1905,6 +1912,7 @@ vi:
|
||||||
instructions_html: Sao chép và dán mã bên dưới vào mã nguồn trang web của bạn. Sau đó, thêm địa chỉ trang web của bạn vào một trong các trường metadata trên hồ sơ của bạn từ tab "Sửa hồ sơ" và lưu thay đổi.
|
instructions_html: Sao chép và dán mã bên dưới vào mã nguồn trang web của bạn. Sau đó, thêm địa chỉ trang web của bạn vào một trong các trường metadata trên hồ sơ của bạn từ tab "Sửa hồ sơ" và lưu thay đổi.
|
||||||
verification: Xác minh
|
verification: Xác minh
|
||||||
verified_links: Những liên kết bạn đã xác minh
|
verified_links: Những liên kết bạn đã xác minh
|
||||||
|
website_verification: Xác minh website
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Thêm khóa bảo mật mới
|
add: Thêm khóa bảo mật mới
|
||||||
create:
|
create:
|
||||||
|
|
|
@ -318,6 +318,21 @@ namespace :api, format: false do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
concern :grouped_notifications do
|
||||||
|
resources :notifications, param: :group_key, only: [:index, :show] do
|
||||||
|
collection do
|
||||||
|
post :clear
|
||||||
|
get :unread_count
|
||||||
|
end
|
||||||
|
|
||||||
|
member do
|
||||||
|
post :dismiss
|
||||||
|
end
|
||||||
|
|
||||||
|
resources :accounts, only: [:index], module: :notifications
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
namespace :v2 do
|
namespace :v2 do
|
||||||
get '/search', to: 'search#index', as: :search
|
get '/search', to: 'search#index', as: :search
|
||||||
|
|
||||||
|
@ -343,21 +358,12 @@ namespace :api, format: false do
|
||||||
namespace :notifications do
|
namespace :notifications do
|
||||||
resource :policy, only: [:show, :update]
|
resource :policy, only: [:show, :update]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
concerns :grouped_notifications
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :v2_alpha do
|
namespace :v2_alpha, module: 'v2' do
|
||||||
resources :notifications, param: :group_key, only: [:index, :show] do
|
concerns :grouped_notifications
|
||||||
collection do
|
|
||||||
post :clear
|
|
||||||
get :unread_count
|
|
||||||
end
|
|
||||||
|
|
||||||
member do
|
|
||||||
post :dismiss
|
|
||||||
end
|
|
||||||
|
|
||||||
resources :accounts, only: [:index], module: :notifications
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :web do
|
namespace :web do
|
||||||
|
|
|
@ -43,6 +43,12 @@ module Mastodon
|
||||||
@gem_version ||= Gem::Version.new(to_s.split('+')[0])
|
@gem_version ||= Gem::Version.new(to_s.split('+')[0])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_versions
|
||||||
|
{
|
||||||
|
mastodon: 2,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def repository
|
def repository
|
||||||
ENV.fetch('GITHUB_REPOSITORY', 'glitch-soc/mastodon')
|
ENV.fetch('GITHUB_REPOSITORY', 'glitch-soc/mastodon')
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
Fabricator(:list_account) do
|
Fabricator(:list_account) do
|
||||||
list
|
list
|
||||||
account
|
|
||||||
before_create { |list_account, _| list_account.list.account.follow!(account) }
|
initialize_with do
|
||||||
|
resolved_class.new(list: list, account: list.account)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
43
spec/models/bookmark_spec.rb
Normal file
43
spec/models/bookmark_spec.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Bookmark do
|
||||||
|
describe 'Associations' do
|
||||||
|
it { is_expected.to belong_to(:account).required }
|
||||||
|
it { is_expected.to belong_to(:status).required }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Validations' do
|
||||||
|
subject { Fabricate.build :bookmark }
|
||||||
|
|
||||||
|
it { is_expected.to validate_uniqueness_of(:status_id).scoped_to(:account_id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Callbacks' do
|
||||||
|
describe 'reblog statuses' do
|
||||||
|
context 'when status is not a reblog' do
|
||||||
|
let(:status) { Fabricate :status }
|
||||||
|
|
||||||
|
it 'keeps status set to assigned value' do
|
||||||
|
bookmark = Fabricate.build :bookmark, status: status
|
||||||
|
|
||||||
|
expect { bookmark.valid? }
|
||||||
|
.to_not change(bookmark, :status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when status is a reblog' do
|
||||||
|
let(:original) { Fabricate :status }
|
||||||
|
let(:status) { Fabricate :status, reblog: original }
|
||||||
|
|
||||||
|
it 'keeps status set to assigned value' do
|
||||||
|
bookmark = Fabricate.build :bookmark, status: status
|
||||||
|
|
||||||
|
expect { bookmark.valid? }
|
||||||
|
.to change(bookmark, :status).to(original)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -84,4 +84,13 @@ RSpec.describe CustomEmoji, :attachment_processing do
|
||||||
it { is_expected.to normalize(:domain).from(nil).to(nil) }
|
it { is_expected.to normalize(:domain).from(nil).to(nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Validations' do
|
||||||
|
subject { Fabricate.build :custom_emoji }
|
||||||
|
|
||||||
|
it { is_expected.to validate_uniqueness_of(:shortcode).scoped_to(:domain) }
|
||||||
|
it { is_expected.to validate_length_of(:shortcode).is_at_least(described_class::MINIMUM_SHORTCODE_SIZE) }
|
||||||
|
it { is_expected.to allow_values('cats').for(:shortcode) }
|
||||||
|
it { is_expected.to_not allow_values('@#$@#$', 'X').for(:shortcode) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ RSpec.describe ListAccount do
|
||||||
let(:list) { Fabricate :list, account: follow.account }
|
let(:list) { Fabricate :list, account: follow.account }
|
||||||
|
|
||||||
it 'finds and sets the follow with the list account' do
|
it 'finds and sets the follow with the list account' do
|
||||||
list_account = described_class.create list: list, account: follow.target_account
|
list_account = Fabricate :list_account, list: list, account: follow.target_account
|
||||||
expect(list_account)
|
expect(list_account)
|
||||||
.to have_attributes(
|
.to have_attributes(
|
||||||
follow: eq(follow),
|
follow: eq(follow),
|
||||||
|
@ -23,7 +23,7 @@ RSpec.describe ListAccount do
|
||||||
let(:list) { Fabricate :list, account: follow_request.account }
|
let(:list) { Fabricate :list, account: follow_request.account }
|
||||||
|
|
||||||
it 'finds and sets the follow request with the list account' do
|
it 'finds and sets the follow request with the list account' do
|
||||||
list_account = described_class.create list: list, account: follow_request.target_account
|
list_account = Fabricate :list_account, list: list, account: follow_request.target_account
|
||||||
expect(list_account)
|
expect(list_account)
|
||||||
.to have_attributes(
|
.to have_attributes(
|
||||||
follow: be_nil,
|
follow: be_nil,
|
||||||
|
@ -33,10 +33,8 @@ RSpec.describe ListAccount do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when list owner is the account' do
|
context 'when list owner is the account' do
|
||||||
let(:list) { Fabricate :list }
|
|
||||||
|
|
||||||
it 'does not set follow or follow request' do
|
it 'does not set follow or follow request' do
|
||||||
list_account = described_class.create list: list, account: list.account
|
list_account = Fabricate :list_account
|
||||||
expect(list_account)
|
expect(list_account)
|
||||||
.to have_attributes(
|
.to have_attributes(
|
||||||
follow: be_nil,
|
follow: be_nil,
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe PreviewCard do
|
RSpec.describe PreviewCard do
|
||||||
|
describe 'file size limit', :attachment_processing do
|
||||||
|
it 'is set differently whether vips is enabled or not' do
|
||||||
|
expect(described_class::LIMIT).to eq(Rails.configuration.x.use_vips ? 8.megabytes : 2.megabytes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'validations' do
|
describe 'validations' do
|
||||||
describe 'urls' do
|
describe 'urls' do
|
||||||
it 'allows http schemes' do
|
it 'allows http schemes' do
|
||||||
|
|
|
@ -8,9 +8,9 @@ RSpec.describe 'Accounts in grouped notifications' do
|
||||||
let(:scopes) { 'read:notifications write:notifications' }
|
let(:scopes) { 'read:notifications write:notifications' }
|
||||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||||
|
|
||||||
describe 'GET /api/v2_alpha/notifications/:group_key/accounts', :inline_jobs do
|
describe 'GET /api/v2/notifications/:group_key/accounts', :inline_jobs do
|
||||||
subject do
|
subject do
|
||||||
get "/api/v2_alpha/notifications/#{user.account.notifications.first.group_key}/accounts", headers: headers, params: params
|
get "/api/v2/notifications/#{user.account.notifications.first.group_key}/accounts", headers: headers, params: params
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:params) { {} }
|
let(:params) { {} }
|
||||||
|
@ -71,8 +71,8 @@ RSpec.describe 'Accounts in grouped notifications' do
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to include_pagination_headers(
|
.to include_pagination_headers(
|
||||||
prev: api_v2_alpha_notification_accounts_url(limit: params[:limit], min_id: notifications.first.id),
|
prev: api_v2_notification_accounts_url(limit: params[:limit], min_id: notifications.first.id),
|
||||||
next: api_v2_alpha_notification_accounts_url(limit: params[:limit], max_id: notifications.second.id)
|
next: api_v2_notification_accounts_url(limit: params[:limit], max_id: notifications.second.id)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
343
spec/requests/api/v2/notifications_spec.rb
Normal file
343
spec/requests/api/v2/notifications_spec.rb
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Notifications' do
|
||||||
|
let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||||
|
let(:scopes) { 'read:notifications write:notifications' }
|
||||||
|
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||||
|
|
||||||
|
describe 'GET /api/v2/notifications/unread_count', :inline_jobs do
|
||||||
|
subject do
|
||||||
|
get '/api/v2/notifications/unread_count', headers: headers, params: params
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:params) { {} }
|
||||||
|
|
||||||
|
before do
|
||||||
|
first_status = PostStatusService.new.call(user.account, text: 'Test')
|
||||||
|
ReblogService.new.call(Fabricate(:account), first_status)
|
||||||
|
PostStatusService.new.call(Fabricate(:account), text: 'Hello @alice')
|
||||||
|
FavouriteService.new.call(Fabricate(:account), first_status)
|
||||||
|
FavouriteService.new.call(Fabricate(:account), first_status)
|
||||||
|
FollowService.new.call(Fabricate(:account), user.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'forbidden for wrong scope', 'write write:notifications'
|
||||||
|
|
||||||
|
context 'with no options' do
|
||||||
|
it 'returns expected notifications count' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with grouped_types parameter' do
|
||||||
|
let(:params) { { grouped_types: %w(reblog) } }
|
||||||
|
|
||||||
|
it 'returns expected notifications count' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a read marker' do
|
||||||
|
before do
|
||||||
|
id = user.account.notifications.browserable.order(id: :desc).offset(2).first.id
|
||||||
|
user.markers.create!(timeline: 'notifications', last_read_id: id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns expected notifications count' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with exclude_types param' do
|
||||||
|
let(:params) { { exclude_types: %w(mention) } }
|
||||||
|
|
||||||
|
it 'returns expected notifications count' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a user-provided limit' do
|
||||||
|
let(:params) { { limit: 2 } }
|
||||||
|
|
||||||
|
it 'returns a capped value' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there are more notifications than the limit' do
|
||||||
|
before do
|
||||||
|
stub_const('Api::V2::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT', 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a capped value' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:count]).to eq Api::V2::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v2/notifications', :inline_jobs do
|
||||||
|
subject do
|
||||||
|
get '/api/v2/notifications', headers: headers, params: params
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:bob) { Fabricate(:user) }
|
||||||
|
let(:tom) { Fabricate(:user) }
|
||||||
|
let(:params) { {} }
|
||||||
|
|
||||||
|
before do
|
||||||
|
first_status = PostStatusService.new.call(user.account, text: 'Test')
|
||||||
|
ReblogService.new.call(bob.account, first_status)
|
||||||
|
PostStatusService.new.call(bob.account, text: 'Hello @alice')
|
||||||
|
FavouriteService.new.call(bob.account, first_status)
|
||||||
|
FavouriteService.new.call(tom.account, first_status)
|
||||||
|
FollowService.new.call(bob.account, user.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'forbidden for wrong scope', 'write write:notifications'
|
||||||
|
|
||||||
|
context 'when there are no notifications' do
|
||||||
|
before do
|
||||||
|
user.account.notifications.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 0 notifications' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:notification_groups]).to eq []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with no options' do
|
||||||
|
it 'returns expected notification types', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(body_json_types).to include('reblog', 'mention', 'favourite', 'follow')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with grouped_types param' do
|
||||||
|
let(:params) { { grouped_types: %w(reblog) } }
|
||||||
|
|
||||||
|
it 'returns everything, but does not group favourites' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:notification_groups]).to contain_exactly(
|
||||||
|
a_hash_including(
|
||||||
|
type: 'reblog',
|
||||||
|
sample_account_ids: [bob.account_id.to_s]
|
||||||
|
),
|
||||||
|
a_hash_including(
|
||||||
|
type: 'mention',
|
||||||
|
sample_account_ids: [bob.account_id.to_s]
|
||||||
|
),
|
||||||
|
a_hash_including(
|
||||||
|
type: 'favourite',
|
||||||
|
sample_account_ids: [bob.account_id.to_s]
|
||||||
|
),
|
||||||
|
a_hash_including(
|
||||||
|
type: 'favourite',
|
||||||
|
sample_account_ids: [tom.account_id.to_s]
|
||||||
|
),
|
||||||
|
a_hash_including(
|
||||||
|
type: 'follow',
|
||||||
|
sample_account_ids: [bob.account_id.to_s]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with exclude_types param' do
|
||||||
|
let(:params) { { exclude_types: %w(mention) } }
|
||||||
|
|
||||||
|
it 'returns everything but excluded type', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body.size).to_not eq 0
|
||||||
|
expect(body_json_types.uniq).to_not include 'mention'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with types param' do
|
||||||
|
let(:params) { { types: %w(mention) } }
|
||||||
|
|
||||||
|
it 'returns only requested type', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(body_json_types.uniq).to eq ['mention']
|
||||||
|
expect(response.parsed_body.dig(:notification_groups, 0, :page_min_id)).to_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with limit param' do
|
||||||
|
let(:params) { { limit: 3 } }
|
||||||
|
let(:notifications) { user.account.notifications.reorder(id: :desc) }
|
||||||
|
|
||||||
|
it 'returns the requested number of notifications paginated', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response.parsed_body[:notification_groups].size)
|
||||||
|
.to eq(params[:limit])
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to include_pagination_headers(
|
||||||
|
prev: api_v2_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
||||||
|
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
||||||
|
# not the last that has been skipped, so pagination is very likely to give overlap
|
||||||
|
next: api_v2_notifications_url(limit: params[:limit], max_id: notifications[3].id)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with since_id param' do
|
||||||
|
let(:params) { { since_id: notifications[2].id } }
|
||||||
|
let(:notifications) { user.account.notifications.reorder(id: :desc) }
|
||||||
|
|
||||||
|
it 'returns the requested number of notifications paginated', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response.parsed_body[:notification_groups].size)
|
||||||
|
.to eq(2)
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to include_pagination_headers(
|
||||||
|
prev: api_v2_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
||||||
|
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
||||||
|
# not the last that has been skipped, so pagination is very likely to give overlap
|
||||||
|
next: api_v2_notifications_url(limit: params[:limit], max_id: notifications[1].id)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when requesting stripped-down accounts' do
|
||||||
|
let(:params) { { expand_accounts: 'partial_avatars' } }
|
||||||
|
|
||||||
|
let(:recent_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
FavouriteService.new.call(recent_account, user.account.statuses.first)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns an account in "partial_accounts", with the expected keys', :aggregate_failures do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.parsed_body[:partial_accounts].size).to be > 0
|
||||||
|
expect(response.parsed_body[:partial_accounts][0].keys.map(&:to_sym)).to contain_exactly(:acct, :avatar, :avatar_static, :bot, :id, :locked, :url)
|
||||||
|
expect(response.parsed_body[:partial_accounts].pluck(:id)).to_not include(recent_account.id.to_s)
|
||||||
|
expect(response.parsed_body[:accounts].pluck(:id)).to include(recent_account.id.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when passing an invalid value for "expand_accounts"' do
|
||||||
|
let(:params) { { expand_accounts: 'unknown_foobar' } }
|
||||||
|
|
||||||
|
it 'returns http bad request' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def body_json_types
|
||||||
|
response.parsed_body[:notification_groups].pluck(:type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v2/notifications/:id' do
|
||||||
|
subject do
|
||||||
|
get "/api/v2/notifications/#{notification.group_key}", headers: headers
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:notification) { Fabricate(:notification, account: user.account, group_key: 'foobar') }
|
||||||
|
|
||||||
|
it_behaves_like 'forbidden for wrong scope', 'write write:notifications'
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when notification belongs to someone else' do
|
||||||
|
let(:notification) { Fabricate(:notification, group_key: 'foobar') }
|
||||||
|
|
||||||
|
it 'returns http not found' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /api/v2/notifications/:id/dismiss' do
|
||||||
|
subject do
|
||||||
|
post "/api/v2/notifications/#{notification.group_key}/dismiss", headers: headers
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:notification) { Fabricate(:notification, account: user.account, group_key: 'foobar') }
|
||||||
|
|
||||||
|
it_behaves_like 'forbidden for wrong scope', 'read read:notifications'
|
||||||
|
|
||||||
|
it 'destroys the notification' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when notification belongs to someone else' do
|
||||||
|
let(:notification) { Fabricate(:notification) }
|
||||||
|
|
||||||
|
it 'returns http not found' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /api/v2/notifications/clear' do
|
||||||
|
subject do
|
||||||
|
post '/api/v2/notifications/clear', headers: headers
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate(:notification, account: user.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'forbidden for wrong scope', 'read read:notifications'
|
||||||
|
|
||||||
|
it 'clears notifications for the account' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(user.account.reload.notifications).to be_empty
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# TODO: remove this before 4.3.0-rc1
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe 'Notifications' do
|
RSpec.describe 'Notifications' do
|
||||||
|
@ -84,14 +86,14 @@ RSpec.describe 'Notifications' do
|
||||||
|
|
||||||
context 'when there are more notifications than the limit' do
|
context 'when there are more notifications than the limit' do
|
||||||
before do
|
before do
|
||||||
stub_const('Api::V2Alpha::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT', 2)
|
stub_const('Api::V2::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT', 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a capped value' do
|
it 'returns a capped value' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(response.parsed_body[:count]).to eq Api::V2Alpha::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT
|
expect(response.parsed_body[:count]).to eq Api::V2::NotificationsController::DEFAULT_NOTIFICATIONS_COUNT_LIMIT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -206,10 +208,10 @@ RSpec.describe 'Notifications' do
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to include_pagination_headers(
|
.to include_pagination_headers(
|
||||||
prev: api_v2_alpha_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
prev: api_v2_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
||||||
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
||||||
# not the last that has been skipped, so pagination is very likely to give overlap
|
# not the last that has been skipped, so pagination is very likely to give overlap
|
||||||
next: api_v2_alpha_notifications_url(limit: params[:limit], max_id: notifications[3].id)
|
next: api_v2_notifications_url(limit: params[:limit], max_id: notifications[3].id)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -226,10 +228,10 @@ RSpec.describe 'Notifications' do
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to include_pagination_headers(
|
.to include_pagination_headers(
|
||||||
prev: api_v2_alpha_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
prev: api_v2_notifications_url(limit: params[:limit], min_id: notifications.first.id),
|
||||||
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
# TODO: one downside of the current approach is that we return the first ID matching the group,
|
||||||
# not the last that has been skipped, so pagination is very likely to give overlap
|
# not the last that has been skipped, so pagination is very likely to give overlap
|
||||||
next: api_v2_alpha_notifications_url(limit: params[:limit], max_id: notifications[1].id)
|
next: api_v2_notifications_url(limit: params[:limit], max_id: notifications[1].id)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
44
yarn.lock
44
yarn.lock
|
@ -3664,12 +3664,12 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/jest@npm:^29.5.2":
|
"@types/jest@npm:^29.5.2":
|
||||||
version: 29.5.12
|
version: 29.5.13
|
||||||
resolution: "@types/jest@npm:29.5.12"
|
resolution: "@types/jest@npm:29.5.13"
|
||||||
dependencies:
|
dependencies:
|
||||||
expect: "npm:^29.0.0"
|
expect: "npm:^29.0.0"
|
||||||
pretty-format: "npm:^29.0.0"
|
pretty-format: "npm:^29.0.0"
|
||||||
checksum: 10c0/25fc8e4c611fa6c4421e631432e9f0a6865a8cb07c9815ec9ac90d630271cad773b2ee5fe08066f7b95bebd18bb967f8ce05d018ee9ab0430f9dfd1d84665b6f
|
checksum: 10c0/9c31af0b155387b9860908830de63c6b79011d7c87c8b61b39da124e26e55423dd51b006749aafe4f0ef3a065016619a1f93ef4b055157d43727f448e67824b7
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -3771,13 +3771,13 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/pg@npm:^8.6.6":
|
"@types/pg@npm:^8.6.6":
|
||||||
version: 8.11.8
|
version: 8.11.10
|
||||||
resolution: "@types/pg@npm:8.11.8"
|
resolution: "@types/pg@npm:8.11.10"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node": "npm:*"
|
"@types/node": "npm:*"
|
||||||
pg-protocol: "npm:*"
|
pg-protocol: "npm:*"
|
||||||
pg-types: "npm:^4.0.1"
|
pg-types: "npm:^4.0.1"
|
||||||
checksum: 10c0/040eb04edda338a13dccee47585b4479549fd54561e1bc3768690545adb8708a089b178e04fab9241935d7bad361314fc57af3ad87b391cfb9dc0895dd049763
|
checksum: 10c0/c8800d0ab2c6424308e6c6b40c73f19583ee1aed758462bd07694844b0a551b5841442205a4ee05207b80109ba502f33f20241b1bd9b4902e713611fb9e08f6c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -9559,11 +9559,11 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"husky@npm:^9.0.11":
|
"husky@npm:^9.0.11":
|
||||||
version: 9.1.5
|
version: 9.1.6
|
||||||
resolution: "husky@npm:9.1.5"
|
resolution: "husky@npm:9.1.6"
|
||||||
bin:
|
bin:
|
||||||
husky: bin.js
|
husky: bin.js
|
||||||
checksum: 10c0/f42efb95a026303eb880898760f802d88409780dd72f17781d2dfc302177d4f80b641cf1f1694f53f6d97c536c7397684133d8c8fe4a4426f7460186a7d1c6b8
|
checksum: 10c0/705673db4a247c1febd9c5df5f6a3519106cf0335845027bb50a15fba9b1f542cb2610932ede96fd08008f6d9f49db0f15560509861808b0031cdc0e7c798bac
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -13112,10 +13112,10 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1":
|
"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.0":
|
||||||
version: 1.0.1
|
version: 1.1.0
|
||||||
resolution: "picocolors@npm:1.0.1"
|
resolution: "picocolors@npm:1.1.0"
|
||||||
checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400
|
checksum: 10c0/86946f6032148801ef09c051c6fb13b5cf942eaf147e30ea79edb91dd32d700934edebe782a1078ff859fb2b816792e97ef4dab03d7f0b804f6b01a0df35e023
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -14074,13 +14074,13 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.41":
|
"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.41":
|
||||||
version: 8.4.45
|
version: 8.4.47
|
||||||
resolution: "postcss@npm:8.4.45"
|
resolution: "postcss@npm:8.4.47"
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: "npm:^3.3.7"
|
nanoid: "npm:^3.3.7"
|
||||||
picocolors: "npm:^1.0.1"
|
picocolors: "npm:^1.1.0"
|
||||||
source-map-js: "npm:^1.2.0"
|
source-map-js: "npm:^1.2.1"
|
||||||
checksum: 10c0/ad6f8b9b1157d678560373696109745ab97a947d449f8a997acac41c7f1e4c0f3ca4b092d6df1387f430f2c9a319987b1780dbdc27e35800a88cde9b606c1e8f
|
checksum: 10c0/929f68b5081b7202709456532cee2a145c1843d391508c5a09de2517e8c4791638f71dd63b1898dba6712f8839d7a6da046c72a5e44c162e908f5911f57b5f44
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -16005,10 +16005,10 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.0":
|
"source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.1":
|
||||||
version: 1.2.0
|
version: 1.2.1
|
||||||
resolution: "source-map-js@npm:1.2.0"
|
resolution: "source-map-js@npm:1.2.1"
|
||||||
checksum: 10c0/7e5f896ac10a3a50fe2898e5009c58ff0dc102dcb056ed27a354623a0ece8954d4b2649e1a1b2b52ef2e161d26f8859c7710350930751640e71e374fe2d321a4
|
checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue