add akkoma setup
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

set url to repo

use same image as target

we have to sudo on this image

copy masto file

use our builder

bundle install

include rake

install rake

just use their conifg

re-lock deps

update service worker

build prod

ignore ruby deps

make sure we have zip

yeet SW

stream out to the right places

fix URL in reactions

add sounds to build

fix serviceworker

stop circles erroring us out

fix onclick

fix lookup

revert changes to gemfile

fix notification display

don't fetch unsupported stuff

yeet most of SW

fix reply references

fixes #2

fix emoji_reaction type

fix public timeline
This commit is contained in:
FloatingGhost 2023-03-08 18:03:09 +00:00
parent eb03a78993
commit bad0b9ac7f
25 changed files with 134 additions and 143 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@
# Ignore bundler config and downloaded libraries. # Ignore bundler config and downloaded libraries.
/.bundle /.bundle
/vendor/bundle /vendor/bundle
distribution
# Ignore the default SQLite database. # Ignore the default SQLite database.
/db/*.sqlite3 /db/*.sqlite3

28
.woodpecker.yml Normal file
View file

@ -0,0 +1,28 @@
pipeline:
build:
when:
event:
- tag
- push
image: node:16
commands:
- apt-get update && apt-get install -y zip
- yarn install --frozen-lockfile
- TARGET=distribution ./build.sh
- zip mastofe.zip -r distribution
release:
image: akkoma/releaser
when:
event:
- tag
- push
secrets:
- SCW_ACCESS_KEY
- SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID
commands:
- export SOURCE=mastofe.zip
- export DEST=scaleway:akkoma-updates/frontend/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/fedibird-fe.zip
- /bin/sh /entrypoint.sh

View file

@ -50,6 +50,7 @@ export const CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS = 'CIRCLE_ADDER_CIRCLES_FETCH_SU
export const CIRCLE_ADDER_CIRCLES_FETCH_FAIL = 'CIRCLE_ADDER_CIRCLES_FETCH_FAIL'; export const CIRCLE_ADDER_CIRCLES_FETCH_FAIL = 'CIRCLE_ADDER_CIRCLES_FETCH_FAIL';
export const fetchCircle = id => (dispatch, getState) => { export const fetchCircle = id => (dispatch, getState) => {
return;
if (getState().getIn(['circles', id])) { if (getState().getIn(['circles', id])) {
return; return;
} }
@ -77,12 +78,8 @@ export const fetchCircleFail = (id, error) => ({
error, error,
}); });
export const fetchCircles = () => (dispatch, getState) => { export const fetchCircles = () => () => {
dispatch(fetchCirclesRequest()); return;
api(getState).get('/api/v1/circles')
.then(({ data }) => dispatch(fetchCirclesSuccess(data)))
.catch(err => dispatch(fetchCirclesFail(err)));
}; };
export const fetchCirclesRequest = () => ({ export const fetchCirclesRequest = () => ({

View file

@ -112,9 +112,8 @@ export const getContextReference = (getState, status) => {
return ImmutableSet(); return ImmutableSet();
} }
const references = status.get('status_reference_ids').toSet();
const replyStatus = status.get('in_reply_to_id') ? getState().getIn(['statuses', status.get('in_reply_to_id')]) : null; const replyStatus = status.get('in_reply_to_id') ? getState().getIn(['statuses', status.get('in_reply_to_id')]) : null;
return references.concat(getContextReference(getState, replyStatus)); return getContextReference(getState, replyStatus);
}; };
export function changeCompose(text) { export function changeCompose(text) {

View file

@ -8,16 +8,8 @@ export const FAVOURITE_DOMAINS_FETCH_REQUEST = 'FAVOURITE_DOMAINS_FETCH_REQUEST'
export const FAVOURITE_DOMAINS_FETCH_SUCCESS = 'FAVOURITE_DOMAINS_FETCH_SUCCESS'; export const FAVOURITE_DOMAINS_FETCH_SUCCESS = 'FAVOURITE_DOMAINS_FETCH_SUCCESS';
export const FAVOURITE_DOMAINS_FETCH_FAIL = 'FAVOURITE_DOMAINS_FETCH_FAIL'; export const FAVOURITE_DOMAINS_FETCH_FAIL = 'FAVOURITE_DOMAINS_FETCH_FAIL';
export const fetchFavouriteDomain = id => (dispatch, getState) => { export const fetchFavouriteDomain = () => () => {
if (getState().getIn(['favourite_domains', id])) { return;
return;
}
dispatch(fetchFavouriteDomainRequest(id));
api(getState).get(`/api/v1/favourite_domains/${id}`)
.then(({ data }) => dispatch(fetchFavouriteDomainSuccess(data)))
.catch(err => dispatch(fetchFavouriteDomainFail(id, err)));
}; };
export const fetchFavouriteDomainRequest = id => ({ export const fetchFavouriteDomainRequest = id => ({
@ -37,6 +29,7 @@ export const fetchFavouriteDomainFail = (id, error) => ({
}); });
export const fetchFavouriteDomains = () => (dispatch, getState) => { export const fetchFavouriteDomains = () => (dispatch, getState) => {
return;
dispatch(fetchFavouriteDomainsRequest()); dispatch(fetchFavouriteDomainsRequest());
api(getState).get('/api/v1/favourite_domains') api(getState).get('/api/v1/favourite_domains')

View file

@ -8,16 +8,8 @@ export const FAVOURITE_TAGS_FETCH_REQUEST = 'FAVOURITE_TAGS_FETCH_REQUEST';
export const FAVOURITE_TAGS_FETCH_SUCCESS = 'FAVOURITE_TAGS_FETCH_SUCCESS'; export const FAVOURITE_TAGS_FETCH_SUCCESS = 'FAVOURITE_TAGS_FETCH_SUCCESS';
export const FAVOURITE_TAGS_FETCH_FAIL = 'FAVOURITE_TAGS_FETCH_FAIL'; export const FAVOURITE_TAGS_FETCH_FAIL = 'FAVOURITE_TAGS_FETCH_FAIL';
export const fetchFavouriteTag = id => (dispatch, getState) => { export const fetchFavouriteTag = () => () => {
if (getState().getIn(['favourite_tags', id])) { return;
return;
}
dispatch(fetchFavouriteTagRequest(id));
api(getState).get(`/api/v1/favourite_tags/${id}`)
.then(({ data }) => dispatch(fetchFavouriteTagSuccess(data)))
.catch(err => dispatch(fetchFavouriteTagFail(id, err)));
}; };
export const fetchFavouriteTagRequest = id => ({ export const fetchFavouriteTagRequest = id => ({
@ -37,6 +29,7 @@ export const fetchFavouriteTagFail = (id, error) => ({
}); });
export const fetchFavouriteTags = () => (dispatch, getState) => { export const fetchFavouriteTags = () => (dispatch, getState) => {
return;
dispatch(fetchFavouriteTagsRequest()); dispatch(fetchFavouriteTagsRequest());
api(getState).get('/api/v1/favourite_tags') api(getState).get('/api/v1/favourite_tags')

View file

@ -120,7 +120,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS(); const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', enableReaction ? 'emoji_reaction' : null, enableStatusReference ? 'status_reference' : null].filter(x => !!x)) const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', enableReaction ? 'pleroma:emoji_reaction' : null, enableStatusReference ? 'status_reference' : null].filter(x => !!x))
const excludeTypesFromFilter = filter => { const excludeTypesFromFilter = filter => {
return allTypes.filterNot(item => item === filter).toJS(); return allTypes.filterNot(item => item === filter).toJS();
@ -141,9 +141,9 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
const params = { const params = {
max_id: maxId, max_id: maxId,
exclude_types: activeFilter === 'all' exclude_types: (activeFilter === 'all'
? excludeTypesFromSettings(getState()) ? excludeTypesFromSettings(getState())
: excludeTypesFromFilter(activeFilter), : excludeTypesFromFilter(activeFilter)).filter(x => x !== 'status_reference'),
}; };
if (!params.max_id && (notifications.get('items', ImmutableList()).size + notifications.get('pendingItems', ImmutableList()).size) > 0) { if (!params.max_id && (notifications.get('items', ImmutableList()).size + notifications.get('pendingItems', ImmutableList()).size) > 0) {

View file

@ -148,8 +148,6 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
} }
} }
params.compact = true;
const isLoadingRecent = !!params.since_id; const isLoadingRecent = !!params.since_id;
dispatch(expandTimelineRequest(timelineId, isLoadingMore)); dispatch(expandTimelineRequest(timelineId, isLoadingMore));
@ -181,11 +179,11 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
}; };
}; };
export const expandHomeTimeline = ({ maxId, visibilities } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId, visibilities: visibilities }, done); export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
export const expandLimitedTimeline = ({ maxId, visibilities } = {}, done = noOp) => expandTimeline('limited', '/api/v1/timelines/home', { max_id: maxId, visibilities: visibilities }, done); export const expandLimitedTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('limited', '/api/v1/timelines/home', { max_id: maxId }, done);
export const expandPersonalTimeline = ({ maxId, onlyMedia, withoutMedia } = {}, done = noOp) => expandTimeline(`personal${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/personal', { max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia }, done); export const expandPersonalTimeline = ({ maxId, onlyMedia, withoutMedia } = {}, done = noOp) => expandTimeline(`personal${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/personal', { max_id: maxId, only_media: !!onlyMedia }, done);
export const expandPublicTimeline = ({ maxId, onlyMedia, withoutMedia, withoutBot, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, without_bot: !!withoutBot }, done); export const expandPublicTimeline = ({ maxId, onlyMedia, withoutMedia, onlyRemote } = {}, done = noOp) => expandTimeline('public', '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
export const expandDomainTimeline = (domain, { maxId, onlyMedia, withoutMedia, withoutBot } = {}, done = noOp) => expandTimeline(`domain${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}:${domain}`, '/api/v1/timelines/public', { local: false, domain: domain, max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, without_bot: !!withoutBot }, done); export const expandDomainTimeline = (domain, { maxId, onlyMedia, withoutMedia, withoutBot } = {}, done = noOp) => expandTimeline(`domain${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}:${domain}`, '/api/v1/timelines/public', { local: false, domain: domain, max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia }, done);
export const expandGroupTimeline = (id, { maxId, onlyMedia, withoutMedia, tagged } = {}, done = noOp) => expandTimeline(`group:${id}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/timelines/group/${id}`, { max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, tagged: tagged }, done); export const expandGroupTimeline = (id, { maxId, onlyMedia, withoutMedia, tagged } = {}, done = noOp) => expandTimeline(`group:${id}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/timelines/group/${id}`, { max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, tagged: tagged }, done);
export const expandAccountTimeline = (accountId, { maxId, withReplies, withoutReblogs, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${withoutReblogs ? ':without_reblogs' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withoutReblogs, tagged, max_id: maxId }); export const expandAccountTimeline = (accountId, { maxId, withReplies, withoutReblogs, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${withoutReblogs ? ':without_reblogs' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withoutReblogs, tagged, max_id: maxId });
export const expandAccountCoversations = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:conversations`, `/api/v1/accounts/${accountId}/conversations`, { max_id: maxId }); export const expandAccountCoversations = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:conversations`, `/api/v1/accounts/${accountId}/conversations`, { max_id: maxId });

View file

@ -164,7 +164,7 @@ class Account extends ImmutablePureComponent {
return ( return (
<div className='account'> <div className='account'>
<div className='account__wrapper'> <div className='account__wrapper'>
<Permalink key={account.get('id')} className='account__display-name' title={account.get('acct')} href={account.get('url')} to={`${(account.get('group', false)) ? '/timelines/groups/' : '/accounts/'}${account.get('id')}`}> <Permalink key={account.get('id')} className='account__display-name' title={account.get('acct')} href={account.get('url')} to={`/accounts/${account.get('id')}`}>
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div> <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
{mute_expires_at} {mute_expires_at}
<DisplayName account={account} /> <DisplayName account={account} />

View file

@ -56,39 +56,6 @@ const Hashtag = ({ hashtag }) => (
> >
#<span>{hashtag.get('name')}</span> #<span>{hashtag.get('name')}</span>
</Permalink> </Permalink>
<ShortNumber
value={
hashtag.getIn(['history', 0, 'accounts']) * 1 +
hashtag.getIn(['history', 1, 'accounts']) * 1
}
renderer={accountsCountRenderer}
/>
</div>
<div className='trends__item__current'>
<ShortNumber
value={
hashtag.getIn(['history', 0, 'uses']) * 1 +
hashtag.getIn(['history', 1, 'uses']) * 1
}
/>
</div>
<div className='trends__item__sparkline'>
<SilentErrorBoundary>
<Sparklines
width={50}
height={28}
data={hashtag
.get('history')
.reverse()
.map((day) => day.get('uses'))
.toArray()}
>
<SparklinesCurve style={{ fill: 'none' }} />
</Sparklines>
</SilentErrorBoundary>
</div> </div>
</div> </div>
); );

View file

@ -255,14 +255,10 @@ class Status extends ImmutablePureComponent {
handleAccountClick = (e) => { handleAccountClick = (e) => {
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
const id = e.currentTarget.getAttribute('data-id');
const group = e.currentTarget.getAttribute('data-group') !== 'false';
e.preventDefault(); e.preventDefault();
if (group) { const { status } = this.props;
this.context.router.history.push(`/timelines/groups/${id}`); const id = status.getIn(['account', 'id']);
} else { this.context.router.history.push(`/accounts/${id}`);
this.context.router.history.push(`/accounts/${id}`);
}
} }
} }
@ -434,6 +430,7 @@ class Status extends ImmutablePureComponent {
'limited': { icon: 'user-circle', text: intl.formatMessage(messages.limited_short) }, 'limited': { icon: 'user-circle', text: intl.formatMessage(messages.limited_short) },
'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) }, 'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) },
'personal': { icon: 'book', text: intl.formatMessage(messages.personal_short) }, 'personal': { icon: 'book', text: intl.formatMessage(messages.personal_short) },
'local': { icon: 'lock', text: 'local' },
}; };
if (hidden) { if (hidden) {

View file

@ -304,7 +304,7 @@ class AccountCard extends ImmutablePureComponent {
<Permalink <Permalink
className='directory__card__bar__name' className='directory__card__bar__name'
href={account.get('url')} href={account.get('url')}
to={`/timelines/groups/${account.get('id')}`} to={`/accounts/${account.get('id')}`}
> >
<Avatar account={account} size={48} /> <Avatar account={account} size={48} />
<DisplayName account={account} /> <DisplayName account={account} />

View file

@ -23,16 +23,14 @@ const mapStateToProps = (state, { columnId }) => {
const index = columns.findIndex(c => c.get('uuid') === uuid); const index = columns.findIndex(c => c.get('uuid') === uuid);
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'public', 'other', 'onlyMedia']); const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'public', 'other', 'onlyMedia']);
const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'public', 'other', 'withoutMedia']); const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'public', 'other', 'withoutMedia']);
const withoutBot = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutBot']) : state.getIn(['settings', 'public', 'other', 'withoutBot']);
const onlyRemote = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyRemote']) : state.getIn(['settings', 'public', 'other', 'onlyRemote']); const onlyRemote = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyRemote']) : state.getIn(['settings', 'public', 'other', 'onlyRemote']);
const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'public', 'columnWidth']); const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'public', 'columnWidth']);
const timelineState = state.getIn(['timelines', `public${onlyRemote ? ':remote' : ''}${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`]); const timelineState = state.getIn(['timelines', 'public']);
return { return {
hasUnread: !!timelineState && timelineState.get('unread') > 0, hasUnread: !!timelineState && timelineState.get('unread') > 0,
onlyMedia, onlyMedia,
withoutMedia, withoutMedia,
withoutBot,
onlyRemote, onlyRemote,
columnWidth: columnWidth ?? defaultColumnWidth, columnWidth: columnWidth ?? defaultColumnWidth,
}; };
@ -49,7 +47,6 @@ class PublicTimeline extends React.PureComponent {
static defaultProps = { static defaultProps = {
onlyMedia: false, onlyMedia: false,
withoutMedia: false, withoutMedia: false,
withoutBot: false,
onlyRemote: false, onlyRemote: false,
}; };
@ -62,17 +59,16 @@ class PublicTimeline extends React.PureComponent {
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
onlyMedia: PropTypes.bool, onlyMedia: PropTypes.bool,
withoutMedia: PropTypes.bool, withoutMedia: PropTypes.bool,
withoutBot: PropTypes.bool,
onlyRemote: PropTypes.bool, onlyRemote: PropTypes.bool,
}; };
handlePin = () => { handlePin = () => {
const { columnId, dispatch, onlyMedia, withoutMedia, withoutBot, onlyRemote } = this.props; const { columnId, dispatch, onlyMedia, withoutMedia, onlyRemote } = this.props;
if (columnId) { if (columnId) {
dispatch(removeColumn(columnId)); dispatch(removeColumn(columnId));
} else { } else {
dispatch(addColumn(onlyRemote ? 'REMOTE' : 'PUBLIC', { other: { onlyMedia, withoutMedia, withoutBot, onlyRemote } })); dispatch(addColumn(onlyRemote ? 'REMOTE' : 'PUBLIC', { other: { onlyMedia, withoutMedia, onlyRemote } }));
} }
} }
@ -96,19 +92,19 @@ class PublicTimeline extends React.PureComponent {
} }
componentDidMount () { componentDidMount () {
const { dispatch, onlyMedia, withoutMedia, withoutBot, onlyRemote } = this.props; const { dispatch, onlyMedia, withoutMedia, onlyRemote } = this.props;
dispatch(expandPublicTimeline({ onlyMedia, withoutMedia, withoutBot, onlyRemote })); dispatch(expandPublicTimeline({ onlyMedia, withoutMedia, onlyRemote }));
this.disconnect = dispatch(connectPublicStream({ onlyMedia, withoutMedia, withoutBot, onlyRemote })); this.disconnect = dispatch(connectPublicStream({ onlyMedia, withoutMedia, onlyRemote }));
} }
componentDidUpdate (prevProps) { componentDidUpdate (prevProps) {
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.withoutMedia !== this.props.withoutMedia || prevProps.withoutBot !== this.props.withoutBot || prevProps.onlyRemote !== this.props.onlyRemote) { if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.withoutMedia !== this.props.withoutMedia || prevProps.onlyRemote !== this.props.onlyRemote) {
const { dispatch, onlyMedia, withoutMedia, withoutBot, onlyRemote } = this.props; const { dispatch, onlyMedia, withoutMedia, onlyRemote } = this.props;
this.disconnect(); this.disconnect();
dispatch(expandPublicTimeline({ onlyMedia, withoutMedia, withoutBot, onlyRemote })); dispatch(expandPublicTimeline({ onlyMedia, withoutMedia, onlyRemote }));
this.disconnect = dispatch(connectPublicStream({ onlyMedia, withoutMedia, withoutBot, onlyRemote })); this.disconnect = dispatch(connectPublicStream({ onlyMedia, withoutMedia, onlyRemote }));
} }
} }
@ -124,13 +120,13 @@ class PublicTimeline extends React.PureComponent {
} }
handleLoadMore = maxId => { handleLoadMore = maxId => {
const { dispatch, onlyMedia, withoutMedia, withoutBot, onlyRemote } = this.props; const { dispatch, onlyMedia, withoutMedia, onlyRemote } = this.props;
dispatch(expandPublicTimeline({ maxId, onlyMedia, withoutMedia, withoutBot, onlyRemote })); dispatch(expandPublicTimeline({ maxId, onlyMedia, withoutMedia, onlyRemote }));
} }
render () { render () {
const { intl, columnId, hasUnread, multiColumn, onlyMedia, withoutMedia, withoutBot, onlyRemote, columnWidth } = this.props; const { intl, columnId, hasUnread, multiColumn, onlyMedia, withoutMedia, onlyRemote, columnWidth } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
return ( return (
@ -151,7 +147,7 @@ class PublicTimeline extends React.PureComponent {
</ColumnHeader> </ColumnHeader>
<StatusListContainer <StatusListContainer
timelineId={`public${onlyRemote ? ':remote' : ''}${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`} timelineId={'public'}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
trackScroll={!pinned} trackScroll={!pinned}
scrollKey={`public_timeline-${columnId}`} scrollKey={`public_timeline-${columnId}`}

View file

@ -29,6 +29,7 @@ const messages = defineMessages({
personal_short: { id: 'privacy.personal.short', defaultMessage: 'Personal' }, personal_short: { id: 'privacy.personal.short', defaultMessage: 'Personal' },
limited_short: { id: 'privacy.limited.short', defaultMessage: 'Circle' }, limited_short: { id: 'privacy.limited.short', defaultMessage: 'Circle' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
local_short: { id: 'privacy.local.short', defaultMessage: 'Local' },
}); });
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
@ -359,6 +360,7 @@ class DetailedStatus extends ImmutablePureComponent {
'limited': { icon: 'user-circle', text: intl.formatMessage(messages.limited_short) }, 'limited': { icon: 'user-circle', text: intl.formatMessage(messages.limited_short) },
'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) }, 'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) },
'personal': { icon: 'book', text: intl.formatMessage(messages.personal_short) }, 'personal': { icon: 'book', text: intl.formatMessage(messages.personal_short) },
'local': { icon: 'local', text: 'local' },
}; };
const visibilityIcon = visibilityIconInfo[status.get('visibility')]; const visibilityIcon = visibilityIconInfo[status.get('visibility')];

View file

@ -40,8 +40,8 @@ export const getLinks = memoize((favouriteLists = null) => {
return [ return [
link_home, link_home,
enableLimitedTimeline ? link_limited : null, null, // enableLimitedTimeline ? link_limited : null,
enablePersonalTimeline ? link_personal : null, null, // enablePersonalTimeline ? link_personal : null,
link_favourite_lists, link_favourite_lists,
link_notifications, link_notifications,
enableLocalTimeline ? link_local : null, enableLocalTimeline ? link_local : null,

View file

@ -178,15 +178,12 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} /> <WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} /> <WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} />
<WrappedRoute path='/timelines/public/domain/:domain' exact component={DomainTimeline} content={children} />
<WrappedRoute path='/timelines/groups/:id/:tagged?' exact component={GroupTimeline} content={children} />
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} /> <WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
<WrappedRoute path='/timelines/limited' component={LimitedTimeline} content={children} /> <WrappedRoute path='/timelines/limited' component={LimitedTimeline} content={children} />
<WrappedRoute path='/timelines/personal' component={PersonalTimeline} content={children} /> <WrappedRoute path='/timelines/personal' component={PersonalTimeline} content={children} />
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} /> <WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} /> <WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/timelines/public' component={PublicTimeline} content={children} />
<WrappedRoute path='/notifications' component={Notifications} content={children} /> <WrappedRoute path='/notifications' component={Notifications} content={children} />
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} /> <WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />

View file

@ -10,7 +10,7 @@ function openWebCache() {
} }
function fetchRoot() { function fetchRoot() {
return fetch('/', { credentials: 'include', redirect: 'manual' }); return fetch('/web', { credentials: 'include', redirect: 'manual' });
} }
// const firefox = navigator.userAgent.match(/Firefox\/(\d+)/); // const firefox = navigator.userAgent.match(/Firefox\/(\d+)/);
@ -19,7 +19,7 @@ function fetchRoot() {
// Cause a new version of a registered Service Worker to replace an existing one // Cause a new version of a registered Service Worker to replace an existing one
// that is already installed, and replace the currently active worker on open pages. // that is already installed, and replace the currently active worker on open pages.
self.addEventListener('install', function(event) { self.addEventListener('install', function(event) {
event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/', root))); event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/web', root)));
}); });
self.addEventListener('activate', function(event) { self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); event.waitUntil(self.clients.claim());
@ -27,31 +27,8 @@ self.addEventListener('activate', function(event) {
self.addEventListener('fetch', function(event) { self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url); const url = new URL(event.request.url);
if (url.pathname.startsWith('/web/')) { if (url.pathname.startsWith('/web')) {
const asyncResponse = fetchRoot(); return;
const asyncCache = openWebCache();
event.respondWith(asyncResponse.then(
response => {
const clonedResponse = response.clone();
asyncCache.then(cache => cache.put('/', clonedResponse)).catch();
return response;
},
() => asyncCache.then(cache => cache.match('/'))));
} else if (url.pathname === '/auth/sign_out') {
const asyncResponse = fetch(event.request);
const asyncCache = openWebCache();
event.respondWith(asyncResponse.then(response => {
if (response.ok || response.type === 'opaqueredirect') {
return Promise.all([
asyncCache.then(cache => cache.delete('/')),
indexedDB.deleteDatabase('mastodon'),
]).then(() => response);
}
return response;
}));
} /* else if (storageFreeable && (ATTACHMENT_HOST ? url.host === ATTACHMENT_HOST : url.pathname.startsWith('/system/'))) { } /* else if (storageFreeable && (ATTACHMENT_HOST ? url.host === ATTACHMENT_HOST : url.pathname.startsWith('/system/'))) {
event.respondWith(openSystemCache().then(cache => { event.respondWith(openSystemCache().then(cache => {
return cache.match(event.request.url).then(cached => { return cache.match(event.request.url).then(cached => {

View file

@ -88,7 +88,8 @@ const sharedCallbacks = {
}, },
received (data) { received (data) {
const { stream } = data; const { stream: streamFull } = data;
const stream = streamFull.map((name) => name.split(':')[0]);
subscriptions.filter(({ channelName, params }) => { subscriptions.filter(({ channelName, params }) => {
const streamChannelName = stream[0]; const streamChannelName = stream[0];

20
build.sh Executable file
View file

@ -0,0 +1,20 @@
TARGET="${TARGET:-./distribution}" # Where pleromas repository is sitting
mkdir -p $TARGET/emoji
die() {
echo "Die: $@"
exit 1
}
[ -d "${TARGET}" ] || die "${TARGET} directory is missing, are you sure TARGET is set to a pleroma repository? (Info: TARGET=${TARGET} )"
yarn install -D || die "Installing dependencies via yarn failed"
rm -rf public/packs public/assets
env -i "PATH=$PATH" yarn build:production || die "Building the frontend failed"
cp public/assets/sw.js "${TARGET}/sw.js" || die "installing sw.js (service-worker) failed"
rm -rf "${TARGET}/packs" || die "Removing old assets in priv/static/packs failed"
cp -r public/packs "${TARGET}/packs" || die "Copying new assets in priv/static/packs failed"
cp -r public/sounds "${TARGET}/sounds" || die "Copying sounds failed"
rm -rf "${TARGET}/emoji/*.svg" || die "Removing the old emoji assets failed"
cp -r public/emoji/* "${TARGET}/emoji" || die "Installing the new emoji assets failed"

2
ci-builder/Dockerfile Normal file
View file

@ -0,0 +1,2 @@
FROM circleci/ruby:2.7-buster-node
USER root

View file

@ -34,9 +34,7 @@ module.exports = {
), ),
output: { output: {
filename: 'js/[name]-[chunkhash].js', filename: 'js/[name].js',
chunkFilename: 'js/[name]-[chunkhash].chunk.js',
hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
path: output.path, path: output.path,
publicPath: output.publicPath, publicPath: output.publicPath,
}, },
@ -75,8 +73,7 @@ module.exports = {
}, },
), ),
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'css/[name]-[contenthash:8].css', filename: 'css/[name].css',
chunkFilename: 'css/[name]-[contenthash:8].chunk.css',
}), }),
new AssetsManifestPlugin({ new AssetsManifestPlugin({
integrity: true, integrity: true,

18
dev.sh Executable file
View file

@ -0,0 +1,18 @@
TARGET="${TARGET:-./distribution}" # Where pleromas repository is sitting
mkdir -p $TARGET/emoji
die() {
echo "Die: $@"
exit 1
}
[ -d "${TARGET}" ] || die "${TARGET} directory is missing, are you sure TARGET is set to a pleroma repository? (Info: TARGET=${TARGET} )"
yarn install -D || die "Installing dependencies via yarn failed"
rm -rf public/packs public/assets
env -i "PATH=$PATH" bundle exec yarn build:development || die "Building the frontend failed"
rm -rf "${TARGET}/packs" || die "Removing old assets in priv/static/packs failed"
cp -r public/packs "${TARGET}/packs" || die "Copying new assets in priv/static/packs failed"
rm -rf "${TARGET}/emoji/*.svg" || die "Removing the old emoji assets failed"

View file

@ -6,8 +6,8 @@
}, },
"scripts": { "scripts": {
"postversion": "git push --tags", "postversion": "git push --tags",
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack", "build:development": "cross-env NODE_ENV=development webpack --config config/webpack/development.js",
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack", "build:production": "cross-env NODE_ENV=production webpack --config config/webpack/production.js",
"manage:translations": "node ./config/webpack/translationRunner.js", "manage:translations": "node ./config/webpack/translationRunner.js",
"start": "node ./streaming/index.js", "start": "node ./streaming/index.js",
"test": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:jest", "test": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:jest",
@ -18,7 +18,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/mastodon/mastodon.git" "url": "https://akkoma.dev/AkkomaGang/fedibird-fe"
}, },
"browserslist": [ "browserslist": [
"last 2 versions", "last 2 versions",

8
package.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
TARGET="${TARGET:-./distribution}"
rm -rf "${TARGET}/packs" || die "Removing old assets in priv/static/packs failed"
cp -r public/packs "${TARGET}/packs" || die "Copying new assets in priv/static/packs failed"
rm -rf "${TARGET}/emoji/*.svg" || die "Removing the old emoji assets failed"
cp -r public/emoji/* "${TARGET}/emoji" || die "Installing the new emoji assets failed"

View file

@ -2946,9 +2946,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219:
version "1.0.30001228" version "1.0.30001462"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz"
integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== integrity sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==
capture-exit@^2.0.0: capture-exit@^2.0.0:
version "2.0.0" version "2.0.0"