Merge pull request #2213 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes
pull/59/head^2
Claire 2023-05-08 17:59:28 +02:00 committed by GitHub
commit 61f3e0e95e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
227 changed files with 1108 additions and 1226 deletions

View File

@ -26,7 +26,6 @@ services:
ports:
- '127.0.0.1:3000:3000'
- '127.0.0.1:4000:4000'
- '127.0.0.1:80:3000'
networks:
- external_network
- internal_network

View File

@ -7,6 +7,7 @@ module.exports = {
'plugin:jsx-a11y/recommended',
'plugin:import/recommended',
'plugin:promise/recommended',
'plugin:jsdoc/recommended',
],
env: {
@ -238,6 +239,14 @@ module.exports = {
'formatjs/no-useless-message': 'error',
'formatjs/prefer-formatted-message': 'error',
'formatjs/prefer-pound-in-plural': 'error',
'jsdoc/check-types': 'off',
'jsdoc/no-undefined-types': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-param-description': 'off',
'jsdoc/require-property-description': 'off',
'jsdoc/require-returns-description': 'off',
'jsdoc/require-returns': 'off',
},
overrides: [
@ -270,10 +279,13 @@ module.exports = {
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:promise/recommended',
'plugin:jsdoc/recommended',
],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'jsdoc/require-jsdoc': 'off',
},
},
{

View File

@ -428,10 +428,6 @@ RSpec/AnyInstance:
- 'spec/workers/activitypub/delivery_worker_spec.rb'
- 'spec/workers/web/push_notification_worker_spec.rb'
RSpec/BeforeAfterAll:
Exclude:
- 'spec/requests/localization_spec.rb'
# Configuration parameters: Prefixes, AllowedPatterns.
# Prefixes: when, with, without
RSpec/ContextWording:
@ -861,7 +857,6 @@ RSpec/PendingWithoutReason:
Exclude:
- 'spec/controllers/statuses_controller_spec.rb'
- 'spec/models/account_spec.rb'
- 'spec/models/user_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers.
@ -1153,32 +1148,6 @@ RSpec/VerifiedDoubles:
- 'spec/workers/feed_insert_worker_spec.rb'
- 'spec/workers/regeneration_worker_spec.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: ExpectedOrder, Include.
# ExpectedOrder: index, show, new, edit, create, update, destroy
# Include: app/controllers/**/*.rb
Rails/ActionOrder:
Exclude:
- 'app/controllers/admin/announcements_controller.rb'
- 'app/controllers/admin/roles_controller.rb'
- 'app/controllers/admin/rules_controller.rb'
- 'app/controllers/admin/warning_presets_controller.rb'
- 'app/controllers/admin/webhooks_controller.rb'
- 'app/controllers/api/v1/admin/domain_allows_controller.rb'
- 'app/controllers/api/v1/admin/domain_blocks_controller.rb'
- 'app/controllers/api/v1/admin/email_domain_blocks_controller.rb'
- 'app/controllers/api/v1/admin/ip_blocks_controller.rb'
- 'app/controllers/api/v1/filters_controller.rb'
- 'app/controllers/api/v1/media_controller.rb'
- 'app/controllers/api/v1/push/subscriptions_controller.rb'
- 'app/controllers/api/v2/filters/keywords_controller.rb'
- 'app/controllers/api/v2/filters/statuses_controller.rb'
- 'app/controllers/api/v2/filters_controller.rb'
- 'app/controllers/auth/registrations_controller.rb'
- 'app/controllers/filters_controller.rb'
- 'app/controllers/settings/applications_controller.rb'
- 'app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Include.
# Include: app/models/**/*.rb
@ -1234,22 +1203,6 @@ Rails/BulkChangeTable:
- 'db/migrate/20220303000827_add_ordered_media_attachment_ids_to_status_edits.rb'
- 'db/migrate/20220824164433_add_human_identifier_to_admin_action_logs.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/CompactBlank:
Exclude:
- 'app/helpers/application_helper.rb'
- 'app/helpers/statuses_helper.rb'
- 'app/models/concerns/attachmentable.rb'
- 'app/models/poll.rb'
- 'app/services/import_service.rb'
- 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
Rails/ContentTag:
Exclude:
- 'app/helpers/application_helper.rb'
- 'app/helpers/branding_helper.rb'
# Configuration parameters: Include.
# Include: db/migrate/*.rb
Rails/CreateTableWithTimestamps:
@ -1373,39 +1326,11 @@ Rails/HasManyOrHasOneDependent:
- 'app/models/user.rb'
- 'app/models/web/push_subscription.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Include.
# Include: spec/**/*, test/**/*
Rails/HttpPositionalArguments:
Exclude:
- 'spec/config/initializers/rack_attack_spec.rb'
# Configuration parameters: Include.
# Include: spec/**/*.rb, test/**/*.rb
Rails/I18nLocaleAssignment:
Exclude:
- 'spec/controllers/auth/registrations_controller_spec.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/requests/localization_spec.rb'
Rails/I18nLocaleTexts:
Exclude:
- 'lib/tasks/mastodon.rake'
- 'spec/helpers/flashes_helper_spec.rb'
# Configuration parameters: IgnoreScopes, Include.
# Include: app/models/**/*.rb
Rails/InverseOf:
Exclude:
- 'app/models/appeal.rb'
- 'app/models/concerns/account_interactions.rb'
- 'app/models/custom_emoji.rb'
- 'app/models/domain_block.rb'
- 'app/models/follow_recommendation.rb'
- 'app/models/instance.rb'
- 'app/models/notification.rb'
- 'app/models/status.rb'
# Configuration parameters: Include.
# Include: app/controllers/**/*.rb, app/mailers/**/*.rb
Rails/LexicallyScopedActionFilter:
@ -1433,23 +1358,10 @@ Rails/NegateInclude:
- 'app/workers/web/push_notification_worker.rb'
- 'lib/paperclip/color_extractor.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: app/**/*.rb, config/**/*.rb, db/**/*.rb, lib/**/*.rb
Rails/Output:
Exclude:
- 'lib/mastodon/ip_blocks_cli.rb'
Rails/OutputSafety:
Exclude:
- 'config/initializers/simple_form.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: NotNilAndNotEmpty, NotBlank, UnlessBlank.
Rails/Present:
Exclude:
- 'config/initializers/content_security_policy.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: **/Rakefile, **/*.rake
@ -1533,15 +1445,6 @@ Rails/SkipsModelValidations:
- 'spec/services/follow_service_spec.rb'
- 'spec/services/update_account_service_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/SquishedSQLHeredocs:
Exclude:
- 'db/migrate/20170920024819_status_ids_to_timestamp_ids.rb'
- 'db/migrate/20180608213548_reject_following_blocked_users.rb'
- 'db/post_migrate/20190519130537_remove_boosts_widening_audience.rb'
- 'lib/mastodon/snowflake.rb'
- 'lib/tasks/tests.rake'
Rails/TransactionExitStatement:
Exclude:
- 'app/lib/activitypub/activity/announce.rb'

View File

@ -14,6 +14,10 @@ class Admin::AnnouncementsController < Admin::BaseController
@announcement = Announcement.new
end
def edit
authorize :announcement, :update?
end
def create
authorize :announcement, :create?
@ -28,10 +32,6 @@ class Admin::AnnouncementsController < Admin::BaseController
end
end
def edit
authorize :announcement, :update?
end
def update
authorize :announcement, :update?

View File

@ -16,6 +16,10 @@ module Admin
@role = UserRole.new
end
def edit
authorize @role, :update?
end
def create
authorize :user_role, :create?
@ -30,10 +34,6 @@ module Admin
end
end
def edit
authorize @role, :update?
end
def update
authorize @role, :update?

View File

@ -11,6 +11,10 @@ module Admin
@rule = Rule.new
end
def edit
authorize @rule, :update?
end
def create
authorize :rule, :create?
@ -24,10 +28,6 @@ module Admin
end
end
def edit
authorize @rule, :update?
end
def update
authorize @rule, :update?

View File

@ -11,6 +11,10 @@ module Admin
@warning_preset = AccountWarningPreset.new
end
def edit
authorize @warning_preset, :update?
end
def create
authorize :account_warning_preset, :create?
@ -24,10 +28,6 @@ module Admin
end
end
def edit
authorize @warning_preset, :update?
end
def update
authorize @warning_preset, :update?

View File

@ -10,12 +10,20 @@ module Admin
@webhooks = Webhook.page(params[:page])
end
def show
authorize @webhook, :show?
end
def new
authorize :webhook, :create?
@webhook = Webhook.new
end
def edit
authorize @webhook, :update?
end
def create
authorize :webhook, :create?
@ -28,14 +36,6 @@ module Admin
end
end
def show
authorize @webhook, :show?
end
def edit
authorize @webhook, :update?
end
def update
authorize @webhook, :update?

View File

@ -16,6 +16,16 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
PAGINATION_PARAMS = %i(limit).freeze
def index
authorize :domain_allow, :index?
render json: @domain_allows, each_serializer: REST::Admin::DomainAllowSerializer
end
def show
authorize @domain_allow, :show?
render json: @domain_allow, serializer: REST::Admin::DomainAllowSerializer
end
def create
authorize :domain_allow, :create?
@ -29,16 +39,6 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
render json: @domain_allow, serializer: REST::Admin::DomainAllowSerializer
end
def index
authorize :domain_allow, :index?
render json: @domain_allows, each_serializer: REST::Admin::DomainAllowSerializer
end
def show
authorize @domain_allow, :show?
render json: @domain_allow, serializer: REST::Admin::DomainAllowSerializer
end
def destroy
authorize @domain_allow, :destroy?
UnallowDomainService.new.call(@domain_allow)

View File

@ -16,6 +16,16 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
PAGINATION_PARAMS = %i(limit).freeze
def index
authorize :domain_block, :index?
render json: @domain_blocks, each_serializer: REST::Admin::DomainBlockSerializer
end
def show
authorize @domain_block, :show?
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
end
def create
authorize :domain_block, :create?
@ -28,16 +38,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
end
def index
authorize :domain_block, :index?
render json: @domain_blocks, each_serializer: REST::Admin::DomainBlockSerializer
end
def show
authorize @domain_block, :show?
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
end
def update
authorize @domain_block, :update?
@domain_block.update!(domain_block_params)

View File

@ -18,15 +18,6 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
limit
).freeze
def create
authorize :email_domain_block, :create?
@email_domain_block = EmailDomainBlock.create!(resource_params)
log_action :create, @email_domain_block
render json: @email_domain_block, serializer: REST::Admin::EmailDomainBlockSerializer
end
def index
authorize :email_domain_block, :index?
render json: @email_domain_blocks, each_serializer: REST::Admin::EmailDomainBlockSerializer
@ -37,6 +28,15 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
render json: @email_domain_block, serializer: REST::Admin::EmailDomainBlockSerializer
end
def create
authorize :email_domain_block, :create?
@email_domain_block = EmailDomainBlock.create!(resource_params)
log_action :create, @email_domain_block
render json: @email_domain_block, serializer: REST::Admin::EmailDomainBlockSerializer
end
def destroy
authorize @email_domain_block, :destroy?
@email_domain_block.destroy!

View File

@ -18,13 +18,6 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
limit
).freeze
def create
authorize :ip_block, :create?
@ip_block = IpBlock.create!(resource_params)
log_action :create, @ip_block
render json: @ip_block, serializer: REST::Admin::IpBlockSerializer
end
def index
authorize :ip_block, :index?
render json: @ip_blocks, each_serializer: REST::Admin::IpBlockSerializer
@ -35,6 +28,13 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
render json: @ip_block, serializer: REST::Admin::IpBlockSerializer
end
def create
authorize :ip_block, :create?
@ip_block = IpBlock.create!(resource_params)
log_action :create, @ip_block
render json: @ip_block, serializer: REST::Admin::IpBlockSerializer
end
def update
authorize @ip_block, :update?
@ip_block.update(resource_params)

View File

@ -11,6 +11,10 @@ class Api::V1::FiltersController < Api::BaseController
render json: @filters, each_serializer: REST::V1::FilterSerializer
end
def show
render json: @filter, serializer: REST::V1::FilterSerializer
end
def create
ApplicationRecord.transaction do
filter_category = current_account.custom_filters.create!(filter_params)
@ -20,10 +24,6 @@ class Api::V1::FiltersController < Api::BaseController
render json: @filter, serializer: REST::V1::FilterSerializer
end
def show
render json: @filter, serializer: REST::V1::FilterSerializer
end
def update
ApplicationRecord.transaction do
@filter.update!(keyword_params)

View File

@ -6,6 +6,10 @@ class Api::V1::MediaController < Api::BaseController
before_action :set_media_attachment, except: [:create]
before_action :check_processing, except: [:create]
def show
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
end
def create
@media_attachment = current_account.media_attachments.create!(media_attachment_params)
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer
@ -15,10 +19,6 @@ class Api::V1::MediaController < Api::BaseController
render json: processing_error, status: 500
end
def show
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
end
def update
@media_attachment.update!(updateable_media_attachment_params)
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment

View File

@ -6,6 +6,10 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
before_action :set_push_subscription
before_action :check_push_subscription, only: [:show, :update]
def show
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def create
@push_subscription&.destroy!
@ -21,10 +25,6 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def show
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def update
@push_subscription.update!(data: data_params)
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer

View File

@ -12,13 +12,13 @@ class Api::V2::Filters::KeywordsController < Api::BaseController
render json: @keywords, each_serializer: REST::FilterKeywordSerializer
end
def create
@keyword = current_account.custom_filters.find(params[:filter_id]).keywords.create!(resource_params)
def show
render json: @keyword, serializer: REST::FilterKeywordSerializer
end
def show
def create
@keyword = current_account.custom_filters.find(params[:filter_id]).keywords.create!(resource_params)
render json: @keyword, serializer: REST::FilterKeywordSerializer
end

View File

@ -12,13 +12,13 @@ class Api::V2::Filters::StatusesController < Api::BaseController
render json: @status_filters, each_serializer: REST::FilterStatusSerializer
end
def create
@status_filter = current_account.custom_filters.find(params[:filter_id]).statuses.create!(resource_params)
def show
render json: @status_filter, serializer: REST::FilterStatusSerializer
end
def show
def create
@status_filter = current_account.custom_filters.find(params[:filter_id]).statuses.create!(resource_params)
render json: @status_filter, serializer: REST::FilterStatusSerializer
end

View File

@ -11,13 +11,13 @@ class Api::V2::FiltersController < Api::BaseController
render json: @filters, each_serializer: REST::FilterSerializer, rules_requested: true
end
def create
@filter = current_account.custom_filters.create!(resource_params)
def show
render json: @filter, serializer: REST::FilterSerializer, rules_requested: true
end
def show
def create
@filter = current_account.custom_filters.create!(resource_params)
render json: @filter, serializer: REST::FilterSerializer, rules_requested: true
end

View File

@ -25,16 +25,16 @@ class Auth::RegistrationsController < Devise::RegistrationsController
super(&:build_invite_request)
end
def destroy
not_found
end
def update
super do |resource|
resource.clear_other_sessions(current_session.session_id) if resource.saved_change_to_encrypted_password?
end
end
def destroy
not_found
end
protected
def update_resource(resource, params)

View File

@ -18,6 +18,8 @@ class FiltersController < ApplicationController
@filter.keywords.build
end
def edit; end
def create
@filter = current_account.custom_filters.build(resource_params)
@ -28,8 +30,6 @@ class FiltersController < ApplicationController
end
end
def edit; end
def update
if @filter.update(resource_params)
redirect_to filters_path

View File

@ -8,6 +8,8 @@ class Settings::ApplicationsController < Settings::BaseController
@applications = current_user.applications.order(id: :desc).page(params[:page])
end
def show; end
def new
@application = Doorkeeper::Application.new(
redirect_uri: Doorkeeper.configuration.native_redirect_uri,
@ -15,8 +17,6 @@ class Settings::ApplicationsController < Settings::BaseController
)
end
def show; end
def create
@application = current_user.applications.build(application_params)

View File

@ -8,9 +8,8 @@ module Settings
before_action :require_otp_enabled
before_action :require_webauthn_enabled, only: [:index, :destroy]
def new; end
def index; end
def new; end
def options
current_user.update(webauthn_id: WebAuthn.generate_user_id) unless current_user.webauthn_id

View File

@ -118,7 +118,7 @@ module ApplicationHelper
end
def check_icon
content_tag(:svg, tag(:path, 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
content_tag(:svg, tag.path('fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
end
def visibility_icon(status)
@ -152,7 +152,7 @@ module ApplicationHelper
end
def opengraph(property, content)
tag(:meta, content: content, property: property)
tag.meta(content: content, property: property)
end
def body_classes
@ -162,7 +162,7 @@ module ApplicationHelper
output << 'system-font' if current_account&.user&.setting_system_font_ui
output << (current_account&.user&.setting_reduce_motion ? 'reduce-motion' : 'no-reduce-motion')
output << 'rtl' if locale_direction == 'rtl'
output.reject(&:blank?).join(' ')
output.compact_blank.join(' ')
end
def cdn_host

View File

@ -11,11 +11,11 @@ module BrandingHelper
end
def _logo_as_symbol_wordmark
content_tag(:svg, tag(:use, href: '#logo-symbol-wordmark'), viewBox: '0 0 261 66', class: 'logo logo--wordmark')
content_tag(:svg, tag.use(href: '#logo-symbol-wordmark'), viewBox: '0 0 261 66', class: 'logo logo--wordmark')
end
def _logo_as_symbol_icon
content_tag(:svg, tag(:use, href: '#logo-symbol-icon'), viewBox: '0 0 79 79', class: 'logo logo--icon')
content_tag(:svg, tag.use(href: '#logo-symbol-icon'), viewBox: '0 0 79 79', class: 'logo logo--icon')
end
def render_logo

View File

@ -51,14 +51,14 @@ module StatusesHelper
end
def status_description(status)
components = [[media_summary(status), status_text_summary(status)].reject(&:blank?).join(' · ')]
components = [[media_summary(status), status_text_summary(status)].compact_blank.join(' · ')]
if status.spoiler_text.blank?
components << status.text
components << poll_summary(status)
end
components.reject(&:blank?).join("\n\n")
components.compact_blank.join("\n\n")
end
def stream_link_target

View File

@ -441,16 +441,12 @@ export function changeUploadCompose(id, params) {
// Editing already-attached media is deferred to editing the post itself.
// For simplicity's sake, fake an API reply.
if (media && !media.get('unattached')) {
let { description, focus } = params;
const data = media.toJS();
if (description) {
data.description = description;
}
const { focus, ...other } = params;
const data = { ...media.toJS(), ...other };
if (focus) {
focus = focus.split(',');
data.meta = { focus: { x: parseFloat(focus[0]), y: parseFloat(focus[1]) } };
const [x, y] = focus.split(',');
data.meta = { focus: { x: parseFloat(x), y: parseFloat(y) } };
}
dispatch(changeUploadComposeSuccess(data, true));

View File

@ -20,7 +20,7 @@ export const PICTURE_IN_PICTURE_REMOVE = 'PICTURE_IN_PICTURE_REMOVE';
* @param {string} accountId
* @param {string} playerType
* @param {MediaProps} props
* @return {object}
* @returns {object}
*/
export const deployPictureInPicture = (statusId, accountId, playerType, props) => {
// @ts-expect-error

View File

@ -27,7 +27,7 @@ const { messages } = getLocale();
/**
* @param {number} max
* @return {number}
* @returns {number}
*/
const randomUpTo = max =>
Math.floor(Math.random() * Math.floor(max));
@ -40,7 +40,7 @@ const randomUpTo = max =>
* @param {function(Function, Function): void} [options.fallback]
* @param {function(): void} [options.fillGaps]
* @param {function(object): boolean} [options.accept]
* @return {function(): void}
* @returns {function(): void}
*/
export const connectTimelineStream = (timelineId, channelName, params = {}, options = {}) =>
connectStream(channelName, params, (dispatch, getState) => {
@ -132,7 +132,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
};
/**
* @return {function(): void}
* @returns {function(): void}
*/
export const connectUserStream = () =>
// @ts-expect-error
@ -141,7 +141,7 @@ export const connectUserStream = () =>
/**
* @param {Object} options
* @param {boolean} [options.onlyMedia]
* @return {function(): void}
* @returns {function(): void}
*/
export const connectCommunityStream = ({ onlyMedia } = {}) =>
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
@ -151,7 +151,7 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
* @param {boolean} [options.onlyMedia]
* @param {boolean} [options.onlyRemote]
* @param {boolean} [options.allowLocalOnly]
* @return {function(): void}
* @returns {function(): void}
*/
export const connectPublicStream = ({ onlyMedia, onlyRemote, allowLocalOnly } = {}) =>
connectTimelineStream(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote, allowLocalOnly }) });
@ -161,20 +161,20 @@ export const connectPublicStream = ({ onlyMedia, onlyRemote, allowLocalOnly } =
* @param {string} tagName
* @param {boolean} onlyLocal
* @param {function(object): boolean} accept
* @return {function(): void}
* @returns {function(): void}
*/
export const connectHashtagStream = (columnId, tagName, onlyLocal, accept) =>
connectTimelineStream(`hashtag:${columnId}${onlyLocal ? ':local' : ''}`, `hashtag${onlyLocal ? ':local' : ''}`, { tag: tagName }, { accept });
/**
* @return {function(): void}
* @returns {function(): void}
*/
export const connectDirectStream = () =>
connectTimelineStream('direct', 'direct');
/**
* @param {string} listId
* @return {function(): void}
* @returns {function(): void}
*/
export const connectListStream = listId =>
connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });

View File

@ -20,9 +20,8 @@ import PropTypes from 'prop-types';
/**
* Component that is used to render blurred of blurhash string
*
* @param {BlurhashProps} param1 Props of the component
* @returns Canvas which will render blurred region element to embed
* @returns {JSX.Element} Canvas which will render blurred region element to embed
*/
function Blurhash({
hash,

View File

@ -4,7 +4,6 @@ import { FormattedMessage } from 'react-intl';
/**
* Returns custom renderer for one of the common counter types
*
* @param {"statuses" | "following" | "followers"} counterType
* Type of the counter
* @param {boolean} isBold Whether display number must be displayed in bold

View File

@ -35,7 +35,6 @@ class SilentErrorBoundary extends React.Component {
/**
* Used to render counter of how much people are talking about hashtag
*
* @type {(displayNumber: JSX.Element, pluralReady: number) => JSX.Element}
*/
export const accountsCountRenderer = (displayNumber, pluralReady) => (

View File

@ -1,21 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export default class Icon extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
className: PropTypes.string,
fixedWidth: PropTypes.bool,
};
render () {
const { id, className, fixedWidth, ...other } = this.props;
return (
<i role='img' className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />
);
}
}

View File

@ -0,0 +1,14 @@
import React from 'react';
import classNames from 'classnames';
type Props = {
id: string;
className?: string;
fixedWidth?: boolean;
children?: never;
[key: string]: any;
}
export const Icon: React.FC<Props> = ({ id, className, fixedWidth, ...other }) =>
<i className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />;
export default Icon;

View File

@ -1,22 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'flavours/glitch/components/icon';
const formatNumber = num => num > 40 ? '40+' : num;
const IconWithBadge = ({ id, count, issueBadge, className }) => (
<i className='icon-with-badge'>
<Icon id={id} fixedWidth className={className} />
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
{issueBadge && <i className='icon-with-badge__issue-badge' />}
</i>
);
IconWithBadge.propTypes = {
id: PropTypes.string.isRequired,
count: PropTypes.number.isRequired,
issueBadge: PropTypes.bool,
className: PropTypes.string,
};
export default IconWithBadge;

View File

@ -0,0 +1,20 @@
import React from 'react';
import { Icon } from './icon';
const formatNumber = (num: number): number | string => num > 40 ? '40+' : num;
type Props = {
id: string;
count: number;
issueBadge: boolean;
className: string;
}
const IconWithBadge: React.FC<Props> = ({ id, count, issueBadge, className }) => (
<i className='icon-with-badge'>
<Icon id={id} fixedWidth className={className} />
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
{issueBadge && <i className='icon-with-badge__issue-badge' />}
</i>
);
export default IconWithBadge;

View File

@ -1,6 +1,5 @@
import React from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages, InjectedIntl } from 'react-intl';
const messages = defineMessages({
today: { id: 'relative_time.today', defaultMessage: 'today' },
@ -28,12 +27,12 @@ const dateFormatOptions = {
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
};
} as const;
const shortDateFormatOptions = {
month: 'short',
day: 'numeric',
};
} as const;
const SECOND = 1000;
const MINUTE = 1000 * 60;
@ -42,7 +41,7 @@ const DAY = 1000 * 60 * 60 * 24;
const MAX_DELAY = 2147483647;
const selectUnits = delta => {
const selectUnits = (delta: number) => {
const absDelta = Math.abs(delta);
if (absDelta < MINUTE) {
@ -56,7 +55,7 @@ const selectUnits = delta => {
return 'day';
};
const getUnitDelay = units => {
const getUnitDelay = (units: string) => {
switch (units) {
case 'second':
return SECOND;
@ -71,7 +70,7 @@ const getUnitDelay = units => {
}
};
export const timeAgoString = (intl, date, now, year, timeGiven, short) => {
export const timeAgoString = (intl: InjectedIntl, date: Date, now: number, year: number, timeGiven: boolean, short?: boolean) => {
const delta = now - date.getTime();
let relativeTime;
@ -99,7 +98,7 @@ export const timeAgoString = (intl, date, now, year, timeGiven, short) => {
return relativeTime;
};
const timeRemainingString = (intl, date, now, timeGiven = true) => {
const timeRemainingString = (intl: InjectedIntl, date: Date, now: number, timeGiven = true) => {
const delta = date.getTime() - now;
let relativeTime;
@ -121,15 +120,17 @@ const timeRemainingString = (intl, date, now, timeGiven = true) => {
return relativeTime;
};
class RelativeTimestamp extends React.Component {
static propTypes = {
intl: PropTypes.object.isRequired,
timestamp: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
futureDate: PropTypes.bool,
short: PropTypes.bool,
};
type Props = {
intl: InjectedIntl;
timestamp: string;
year: number;
futureDate?: boolean;
short?: boolean;
}
type States = {
now: number;
}
class RelativeTimestamp extends React.Component<Props, States> {
state = {
now: this.props.intl.now(),
@ -140,7 +141,9 @@ class RelativeTimestamp extends React.Component {
short: true,
};
shouldComponentUpdate (nextProps, nextState) {
_timer: number | undefined;
shouldComponentUpdate (nextProps: Props, nextState: States) {
// As of right now the locale doesn't change without a new page load,
// but we might as well check in case that ever changes.
return this.props.timestamp !== nextProps.timestamp ||
@ -148,7 +151,7 @@ class RelativeTimestamp extends React.Component {
this.state.now !== nextState.now;
}
componentWillReceiveProps (nextProps) {
UNSAFE_componentWillReceiveProps (nextProps: Props) {
if (this.props.timestamp !== nextProps.timestamp) {
this.setState({ now: this.props.intl.now() });
}
@ -158,16 +161,16 @@ class RelativeTimestamp extends React.Component {
this._scheduleNextUpdate(this.props, this.state);
}
componentWillUpdate (nextProps, nextState) {
UNSAFE_componentWillUpdate (nextProps: Props, nextState: States) {
this._scheduleNextUpdate(nextProps, nextState);
}
componentWillUnmount () {
clearTimeout(this._timer);
window.clearTimeout(this._timer);
}
_scheduleNextUpdate (props, state) {
clearTimeout(this._timer);
_scheduleNextUpdate (props: Props, state: States) {
window.clearTimeout(this._timer);
const { timestamp } = props;
const delta = (new Date(timestamp)).getTime() - state.now;
@ -176,7 +179,7 @@ class RelativeTimestamp extends React.Component {
const updateInterval = 1000 * 10;
const delay = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder);
this._timer = setTimeout(() => {
this._timer = window.setTimeout(() => {
this.setState({ now: this.props.intl.now() });
}, delay);
}

View File

@ -24,7 +24,6 @@ import { FormattedMessage, FormattedNumber } from 'react-intl';
/**
* Component that renders short big number to a shorter version
*
* @param {ShortNumberProps} param0 Props for the component
* @returns {JSX.Element} Rendered number
*/
@ -58,7 +57,6 @@ ShortNumber.propTypes = {
/**
* Renders short number into corresponding localizable react fragment
*
* @param {ShortNumberCounterProps} param0 Props for the component
* @returns {JSX.Element} FormattedMessage ready to be embedded in code
*/

View File

@ -476,7 +476,7 @@ class Audio extends React.PureComponent {
}
return (
<div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
<div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
<Blurhash
hash={blurhash}

View File

@ -125,9 +125,15 @@ const mapStateToProps = state => ({
});
const mapDispatchToProps = dispatch => ({
/** Set options in the redux store */
/**
* Set options in the redux store
* @param opts
*/
setOpt: (opts) => dispatch(doodleSet(opts)),
/** Submit doodle for upload */
/**
* Submit doodle for upload
* @param file
*/
submit: (file) => dispatch(uploadCompose([file])),
});
@ -230,7 +236,10 @@ class DoodleModal extends ImmutablePureComponent {
//endregion
/** Key up handler */
/**
* Key up handler
* @param e
*/
handleKeyUp = (e) => {
if (e.target.nodeName === 'INPUT') return;
@ -256,7 +265,10 @@ class DoodleModal extends ImmutablePureComponent {
}
};
/** Key down handler */
/**
* Key down handler
* @param e
*/
handleKeyDown = (e) => {
if (e.key === 'Control' || e.key === 'Meta') {
this.controlHeld = true;
@ -292,7 +304,6 @@ class DoodleModal extends ImmutablePureComponent {
/**
* Set reference to the canvas element.
* This is called during component init
*
* @param elem - canvas element
*/
setCanvasRef = (elem) => {
@ -334,7 +345,6 @@ class DoodleModal extends ImmutablePureComponent {
/**