Merge branch 'chapril' of ssh://forge.april.org:222/Chapril/mobilizon.chapril.org-mobilizon into chapril
This commit is contained in:
commit
6198507117
66
.devcontainer/Dockerfile
Normal file
66
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,66 @@
|
||||
# Update the VARIANT arg in docker-compose.yml to pick an Elixir version: 1.9, 1.10, 1.10.4
|
||||
ARG VARIANT="1.12.3"
|
||||
FROM elixir:${VARIANT}
|
||||
|
||||
# This Dockerfile adds a non-root user with sudo access. Update the “remoteUser” property in
|
||||
# devcontainer.json to use it. More info: https://aka.ms/vscode-remote/containers/non-root-user.
|
||||
ARG USERNAME=vscode
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Options for common package install script
|
||||
ARG INSTALL_ZSH="true"
|
||||
ARG UPGRADE_PACKAGES="true"
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.209.6/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="d35dd1711454156c9a59cc41ebe04fbff681ca0bd304f10fd5b13285d0de13b2"
|
||||
|
||||
# Optional Settings for Phoenix
|
||||
ARG PHOENIX_VERSION="1.6.2"
|
||||
|
||||
# [Optional] Setup nodejs
|
||||
ARG NODE_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/node-debian.sh"
|
||||
ARG NODE_SCRIPT_SHA="dev-mode"
|
||||
ARG NODE_VERSION="none"
|
||||
ENV NVM_DIR=/usr/local/share/nvm
|
||||
ENV NVM_SYMLINK_CURRENT=true
|
||||
ENV PATH=${NVM_DIR}/current/bin:${PATH}
|
||||
|
||||
# [Optional, Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
||||
ARG NODE_VERSION="none"
|
||||
|
||||
# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies.
|
||||
RUN apt-get update \
|
||||
&& export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install --no-install-recommends curl ca-certificates 2>&1 \
|
||||
&& curl -sSL ${COMMON_SCRIPT_SOURCE} -o /tmp/common-setup.sh \
|
||||
&& ([ "${COMMON_SCRIPT_SHA}" = "dev-mode" ] || (echo "${COMMON_SCRIPT_SHA} */tmp/common-setup.sh" | sha256sum -c -)) \
|
||||
&& /bin/bash /tmp/common-setup.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" \
|
||||
#
|
||||
# [Optional] Install Node.js for use with web applications
|
||||
&& if [ "$NODE_VERSION" != "none" ]; then \
|
||||
curl -sSL ${NODE_SCRIPT_SOURCE} -o /tmp/node-setup.sh \
|
||||
&& ([ "${NODE_SCRIPT_SHA}" = "dev-mode" ] || (echo "${NODE_SCRIPT_SHA} */tmp/node-setup.sh" | sha256sum -c -)) \
|
||||
&& /bin/bash /tmp/node-setup.sh "${NVM_DIR}" "${NODE_VERSION}" "${USERNAME}"; \
|
||||
fi \
|
||||
#
|
||||
# Install dependencies
|
||||
&& apt-get install -y build-essential \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/common-setup.sh /tmp/node-setup.sh
|
||||
|
||||
RUN su ${USERNAME} -c "mix local.hex --force \
|
||||
&& mix local.rebar --force \
|
||||
&& mix archive.install --force hex phx_new ${PHOENIX_VERSION}"
|
||||
|
||||
RUN apt-get update \
|
||||
&& export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install --no-install-recommends cmake webp bash libncurses6 git python3 inotify-tools \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# [Optional] Uncomment this line to install additional package.
|
||||
# RUN mix ...
|
44
.devcontainer/devcontainer.json
Normal file
44
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,44 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/elixir-phoenix-postgres
|
||||
{
|
||||
"name": "Elixir, Phoenix, Node.js & PostgresSQL (Community)",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "elixir",
|
||||
"workspaceFolder": "/workspace",
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"sqltools.connections": [{
|
||||
"name": "Container database",
|
||||
"driver": "PostgreSQL",
|
||||
"previewLimit": 50,
|
||||
"server": "localhost",
|
||||
"port": 5432,
|
||||
"database": "postgres",
|
||||
"username": "postgres",
|
||||
"password": "postgres"
|
||||
}]
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"jakebecker.elixir-ls",
|
||||
"mtxr.sqltools",
|
||||
"mtxr.sqltools-driver-pg"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [4000, 4001, 5432],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "mix deps.get",
|
||||
// "runArgs": ["--userns=keep-id", "--privileged"],
|
||||
// "containerUser": "vscode",
|
||||
// "containerEnv": {
|
||||
// "HOME": "/home/vscode",
|
||||
// },
|
||||
// "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,Z",
|
||||
|
||||
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode"
|
||||
}
|
46
.devcontainer/docker-compose.yml
Normal file
46
.devcontainer/docker-compose.yml
Normal file
@ -0,0 +1,46 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
elixir:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
# Elixir Version: 1.9, 1.10, 1.10.4, ...
|
||||
VARIANT: "1.13.1"
|
||||
# Phoenix Version: 1.4.17, 1.5.4, ...
|
||||
PHOENIX_VERSION: "1.6.6"
|
||||
# Node Version: 10, 11, ...
|
||||
NODE_VERSION: "16"
|
||||
|
||||
volumes:
|
||||
- ..:/workspace:z
|
||||
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
|
||||
network_mode: service:db
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
command: sleep infinity
|
||||
environment:
|
||||
MOBILIZON_INSTANCE_NAME: My Mobilizon Instance
|
||||
MOBILIZON_INSTANCE_HOST: localhost
|
||||
MOBILIZON_INSTANCE_HOST_PORT: 4000
|
||||
MOBILIZON_INSTANCE_PORT: 4000
|
||||
MOBILIZON_INSTANCE_EMAIL: noreply@mobilizon.me
|
||||
MOBILIZON_INSTANCE_REGISTRATIONS_OPEN: "true"
|
||||
MOBILIZON_DATABASE_PASSWORD: postgres
|
||||
MOBILIZON_DATABASE_USERNAME: postgres
|
||||
MOBILIZON_DATABASE_DBNAME: mobilizon
|
||||
MOBILIZON_DATABASE_HOST: db
|
||||
|
||||
db:
|
||||
image: postgis/postgis:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: app
|
||||
|
||||
volumes:
|
||||
postgres-data: null
|
@ -19,7 +19,6 @@ MOBILIZON_REPLY_EMAIL=contact@mobilizon.lan
|
||||
# Email settings
|
||||
MOBILIZON_SMTP_SERVER=localhost
|
||||
MOBILIZON_SMTP_PORT=25
|
||||
MOBILIZON_SMTP_HOSTNAME=localhost
|
||||
MOBILIZON_SMTP_USERNAME=noreply@mobilizon.lan
|
||||
MOBILIZON_SMTP_PASSWORD=password
|
||||
MOBILIZON_SMTP_SSL=false
|
||||
|
@ -1,3 +1,4 @@
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test,priv}/**/*.{ex,exs}"]
|
||||
plugins: [Phoenix.LiveView.HTMLFormatter],
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test,priv}/**/*.{ex,exs,heex}"]
|
||||
]
|
||||
|
@ -59,8 +59,11 @@ lint-elixir:
|
||||
- mix deps.get
|
||||
script:
|
||||
- export EXITVALUE=0
|
||||
- git fetch origin ${CI_DEFAULT_BRANCH}
|
||||
- TARGET_SHA1=$(git show-ref -s ${CI_DEFAULT_BRANCH})
|
||||
- echo "$TARGET_SHA1"
|
||||
- mix format --check-formatted --dry-run || export EXITVALUE=1
|
||||
- mix credo --strict -a || export EXITVALUE=1
|
||||
- mix credo diff --from-git-merge-base $TARGET_SHA1 --strict -a || export EXITVALUE=1
|
||||
- mix sobelow --config || export EXITVALUE=1
|
||||
- exit $EXITVALUE
|
||||
|
||||
@ -107,7 +110,7 @@ deps:
|
||||
exunit:
|
||||
stage: test
|
||||
services:
|
||||
- name: postgis/postgis:13-3.1
|
||||
- name: postgis/postgis:14-3.2
|
||||
alias: postgres
|
||||
variables:
|
||||
MIX_ENV: test
|
||||
@ -180,7 +183,7 @@ pages:
|
||||
|
||||
.docker: &docker
|
||||
stage: docker
|
||||
image: docker:stable
|
||||
image: docker:20.10.12
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
@ -188,13 +191,13 @@ pages:
|
||||
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
|
||||
DOCKER_DRIVER: overlay2
|
||||
services:
|
||||
- docker:stable-dind
|
||||
- docker:20.10.12-dind
|
||||
cache: {}
|
||||
before_script:
|
||||
# Install buildx
|
||||
- wget https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
|
||||
- wget https://github.com/docker/buildx/releases/download/v0.8.1/buildx-v0.8.1.linux-amd64
|
||||
- mkdir -p ~/.docker/cli-plugins/
|
||||
- mv buildx-v0.6.3.linux-amd64 ~/.docker/cli-plugins/docker-buildx
|
||||
- mv buildx-v0.8.1.linux-amd64 ~/.docker/cli-plugins/docker-buildx
|
||||
- chmod a+x ~/.docker/cli-plugins/docker-buildx
|
||||
# Create env
|
||||
- docker context create tls-environment
|
||||
@ -205,16 +208,8 @@ pages:
|
||||
# Login to DockerHub
|
||||
- mkdir -p ~/.docker
|
||||
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$CI_REGISTRY_AUTH\",\"email\":\"$CI_REGISTRY_EMAIL\"}}}" > ~/.docker/config.json
|
||||
script:
|
||||
- >
|
||||
docker buildx build
|
||||
--push
|
||||
--platform linux/amd64,linux/arm64,linux/arm
|
||||
-t $DOCKER_IMAGE_NAME
|
||||
-f docker/production/Dockerfile .
|
||||
tags:
|
||||
- "privileged"
|
||||
timeout: 3 hours
|
||||
|
||||
build-docker-main:
|
||||
<<: *docker
|
||||
@ -222,8 +217,8 @@ build-docker-main:
|
||||
- if: '$CI_PROJECT_NAMESPACE != "framasoft"'
|
||||
when: never
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
variables:
|
||||
DOCKER_IMAGE_NAME: framasoft/mobilizon:main
|
||||
script:
|
||||
- docker buildx build --push --platform linux/amd64 -t framasoft/mobilizon:main -f docker/production/Dockerfile .
|
||||
|
||||
build-docker-tag:
|
||||
<<: *docker
|
||||
@ -231,14 +226,25 @@ build-docker-tag:
|
||||
- if: '$CI_PROJECT_NAMESPACE != "framasoft"'
|
||||
when: never
|
||||
- if: $CI_COMMIT_TAG
|
||||
variables:
|
||||
DOCKER_IMAGE_NAME: framasoft/mobilizon:$CI_COMMIT_TAG
|
||||
timeout: 3 hours
|
||||
script:
|
||||
- >
|
||||
docker buildx build
|
||||
--push
|
||||
--platform linux/amd64,linux/arm64,linux/arm
|
||||
-t framasoft/mobilizon:$CI_COMMIT_TAG
|
||||
-t framasoft/mobilizon:latest
|
||||
-f docker/production/Dockerfile .
|
||||
|
||||
# Packaging app for amd64
|
||||
package-app:
|
||||
image: mobilizon/buildpack:1.13.4-erlang-24.3.3-debian-buster
|
||||
stage: package
|
||||
variables: &release-variables
|
||||
MIX_ENV: "prod"
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
TZ: Etc/UTC
|
||||
APP_ASSET: "${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${ARCH}.tar.gz"
|
||||
script: &release-script
|
||||
- mix local.hex --force
|
||||
- mix local.rebar --force
|
||||
@ -254,7 +260,7 @@ package-app:
|
||||
only:
|
||||
- tags@framasoft/mobilizon
|
||||
artifacts:
|
||||
expire_in: 30 days
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- ${APP_ASSET}
|
||||
|
||||
@ -272,7 +278,7 @@ package-app-dev:
|
||||
# Packaging app for multi-arch
|
||||
multi-arch-release:
|
||||
stage: package
|
||||
image: docker:stable
|
||||
image: docker:20.10.12
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
@ -280,14 +286,15 @@ multi-arch-release:
|
||||
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
|
||||
DOCKER_DRIVER: overlay2
|
||||
APP_ASSET: "${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${ARCH}.tar.gz"
|
||||
OS: debian-buster
|
||||
services:
|
||||
- docker:stable-dind
|
||||
- docker:20.10.12-dind
|
||||
cache: {}
|
||||
before_script:
|
||||
# Install buildx
|
||||
- wget https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
|
||||
- wget https://github.com/docker/buildx/releases/download/v0.8.1/buildx-v0.8.1.linux-amd64
|
||||
- mkdir -p ~/.docker/cli-plugins/
|
||||
- mv buildx-v0.6.3.linux-amd64 ~/.docker/cli-plugins/docker-buildx
|
||||
- mv buildx-v0.8.1.linux-amd64 ~/.docker/cli-plugins/docker-buildx
|
||||
- chmod a+x ~/.docker/cli-plugins/docker-buildx
|
||||
# Create env
|
||||
- docker context create tls-environment
|
||||
@ -303,7 +310,7 @@ multi-arch-release:
|
||||
tags:
|
||||
- "privileged"
|
||||
artifacts:
|
||||
expire_in: 30 days
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- ${APP_ASSET}
|
||||
parallel:
|
||||
@ -319,7 +326,7 @@ multi-arch-release:
|
||||
# Release
|
||||
release-upload:
|
||||
stage: upload
|
||||
image: framasoft/yakforms-assets-deploy:latest
|
||||
image: framasoft/upload-packages:latest
|
||||
variables:
|
||||
APP_ASSET: "${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${ARCH}.tar.gz"
|
||||
rules: *tag-rules
|
||||
|
@ -8,5 +8,5 @@
|
||||
out: "",
|
||||
threshold: "medium",
|
||||
ignore: ["Config.HTTPS", "Config.CSP"],
|
||||
ignore_files: ["config/dev.1.secret.exs", "config/dev.2.secret.exs", "config/dev.3.secret.exs", "config/dev.secret.exs", "config/e2e.secret.exs", "config/prod.secret.exs", "config/test.secret.exs", "config/runtime.1.secret.exs", "config/runtime.2.secret.exs", "config/runtime.3.secret.exs", "config/runtime.exs"]
|
||||
ignore_files: ["config/runtime.exs"]
|
||||
]
|
||||
|
@ -1,12 +1,16 @@
|
||||
|
||||
5048AE33D6269B15E21CF28C6F545AB6
|
||||
|
||||
752C0E897CA81ACD81F4BB215FA5F8E4
|
||||
23412CF16549E4E88366DC9DECF39071
|
||||
81C1F600C5809C7029EE32DE4818CD7D
|
||||
02CE4963DFD1B0D6D5C567357CAFFE97
|
||||
155A1FB53DE39EC8EFCFD7FB94EA823D
|
||||
73B351E4CB3AF715AD450A085F5E6304
|
||||
BBACD7F0BACD4A6D3010C26604671692
|
||||
6D4D4A4821B93BCFAC9CDBB367B34C4B
|
||||
5674F0D127852889ED0132DC2F442AAB
|
||||
1600B7206E47F630D94AB54C360906F0
|
||||
2262742E5C8944D5BF6698EC61F5DE50
|
||||
25BEE162A99754480967216281E9EF33
|
||||
2A6F71CD6F1246F0B152C2376E2E398A
|
||||
30552A09D485A6AA73401C1D54F63C21
|
||||
52900CE4EE3598F6F178A651FB256770
|
||||
6151F44368FC19F2394274F513C29151
|
||||
765526195D4C6D770EAF4DC944A8CBF4
|
||||
B2FF1A12F13B873507C85091688C1D6D
|
||||
B9AF8A342CD7FF39E10CC10A408C28E1
|
||||
C042E87389F7BDCFF4E076E95731AE69
|
||||
C42BFAEF7100F57BED75998B217C857A
|
||||
D11958E86F1B6D37EF656B63405CA8A4
|
||||
F16F054F2628609A726B9FF2F089D484
|
2
.tool-versions
Normal file
2
.tool-versions
Normal file
@ -0,0 +1,2 @@
|
||||
elixir 1.13.4-otp-24
|
||||
erlang 24.3.3
|
445
CHANGELOG.md
445
CHANGELOG.md
@ -1,9 +1,373 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 2.1.0 - 2022-05-16
|
||||
|
||||
### Added
|
||||
|
||||
- Added an event category field. Administrators can extend the pre-configured list of categories through configuration.
|
||||
- Added possibility for administrators to have analytics (Matomo, Plausible supported) and error handling (Sentry supported) on front-end.
|
||||
- Redesigned federation admin section with dedicated instance pages
|
||||
- Allow to filter moderation reports by domain
|
||||
- Added a button to go to past events of a group if it has no upcoming events
|
||||
- Add Überauth CAS Strategy
|
||||
- Add a CLI command to delete actors
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed mailer library from Bamboo to Swoosh, should fix emails being considered spam. **Some configuration changes are required, see below.**
|
||||
- Expose some fields to ActivityStreams event representation: `isOnline`, `remainingAttendeeCapacity` and `participantCount`
|
||||
- Expose a new field to ActivityStreams group representation: `memberCount`
|
||||
- Improve group creation errors feedback
|
||||
- Only display locality in event card
|
||||
- Stale groups are now excluded from group search
|
||||
- Event default visibility is now set according to group privacy setting
|
||||
- Remove Koena Connect button
|
||||
- Hide the whole metadata block if group has no description
|
||||
- Increase task timeout in Refresher to 60 seconds
|
||||
- Allow webfinger to be fetched over http (not https) in dev mode
|
||||
- Improve reactions when approving/rejecting an instance follow
|
||||
- Improve instance admin view for mobile
|
||||
- Allow to reject instance following
|
||||
- Allow instance to have non-standard ports
|
||||
- Add pagination to the instances list
|
||||
- Eventually fetch actors in mentions
|
||||
- Improve IdentityPicker, JoinGroupWithAccount and ActorInline components
|
||||
- Various group and posts improvements
|
||||
- Update schema.graphql file
|
||||
- Add "Accept-Language" header to sentry request metadata
|
||||
- Hide address blocks when address has no real data
|
||||
- Remove obsolete attribute type="text/css" from <style> tags
|
||||
- Improve actor cards integration
|
||||
- Use upstream dependencies for Ueberauth providers
|
||||
- Include ongoing events in search
|
||||
- Send push notification into own task
|
||||
- Add appropriate timeouts for Repo.transactions
|
||||
- Add a proper error message when adding an instance follow that doesn't respond
|
||||
- Allow the instance to be followed from Mastodon (through relays)
|
||||
- Remove unused fragment from FETCH_PERSON GraphQL query
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed actor refreshment being impossible
|
||||
- Fixed ical export for undefined datetimes
|
||||
- Fixed parsing links with hashtag characters
|
||||
- Fixed fetching link details from Twitter
|
||||
- Fixed Thunderbird accessing ICS feed endpoint with special `Accept` HTTP header
|
||||
- Make sure every ICS/Feed caches are emptied when modifying entities
|
||||
- Fixed time issues with DST changes
|
||||
- Fixed group preview card not truncating description
|
||||
- Fixed redirection after login
|
||||
- Fixed user admin section showing button to confirm user when the user is already confirmed
|
||||
- Fixed creating event from group view not always setting the group as organizer
|
||||
- Fixed invalid addresses blocking event metadata preview rendering
|
||||
- Fixed group deletion with comments that caused foreign key issues
|
||||
- Fixed incoming Accept activities from participations we don't already have
|
||||
- Fixed resources that didn't have metadata size limits
|
||||
- Properly fallback to UTC when sending notifications and the user doesn't have a timezone setting set
|
||||
- Fix posts creation
|
||||
- Fix rejecting instance follow
|
||||
- Fix pagination of group events
|
||||
- Add proper fallback for when a TZ isn't registered
|
||||
- Hide side of report modal on low width screens
|
||||
- Fix Telegram Logo being replaced with Mastodon logo in ShareGroupModal
|
||||
- Change URL for Mastodon Share Manager
|
||||
- Fix receiving Flag activities on federated events
|
||||
- Fix activity notifications by preloading user.activity_settings
|
||||
- Fix text overflow on group card description
|
||||
- Exclude tags with more than 40 characters from being extracted
|
||||
- Avoid duplicate tags with different casing
|
||||
- Fix invalid HTML (<div> inside <label>)
|
||||
- Fix latest group not refreshing in admin section
|
||||
- Add missing "relay@" part of federated address to follow
|
||||
- Fix Ueberauth use of CSRF with session
|
||||
- Fix being an administrator when using 3rd-party auth provider
|
||||
- Make sure activity recipient can't be nil
|
||||
- Make sure users can't create profiles or groups with non-valid patterns
|
||||
- Add description field to address representation
|
||||
- Make sure prompt show the correct message and not just "Continue?" in mix mode
|
||||
- Make sure activity notification recaps can't be sent multiple times
|
||||
- Fix group notification of new event being sent multiple times
|
||||
- Fix links to group page in group membership emails and participation
|
||||
- Fix clicking on map crashing the app
|
||||
|
||||
### Translations
|
||||
|
||||
- Arabic
|
||||
- Basque
|
||||
- Belarusian
|
||||
- Bengali
|
||||
- Catalan
|
||||
- Chinese (Traditional)
|
||||
- Croatian
|
||||
- Czech
|
||||
- Danish
|
||||
- Dutch
|
||||
- Esperanto
|
||||
- Finnish
|
||||
- French
|
||||
- Gaelic
|
||||
- Galician
|
||||
- German
|
||||
- Hebrew
|
||||
- Hungarian
|
||||
- Indonesian
|
||||
- Italian
|
||||
- Japanese
|
||||
- Kabyle
|
||||
- Kannada
|
||||
- Norwegian Nynorsk
|
||||
- Occitan
|
||||
- Persian
|
||||
- Polish
|
||||
- Portuguese
|
||||
- Portuguese (Brazil)
|
||||
- Russian
|
||||
- Slovenian
|
||||
- Spanish
|
||||
- Swedish
|
||||
- Welsh
|
||||
|
||||
## 2.1.0-rc.6 - 2022-05-11
|
||||
|
||||
Changes since rc.5:
|
||||
|
||||
- Allow the instance to be followed from Mastodon (through relays)
|
||||
- Make sure activity recipient can't be nil
|
||||
- Make sure users can't create profiles or groups with non-valid patterns
|
||||
- Add description field to address representation
|
||||
- Make sure prompt show the correct message and not just "Continue?" in mix mode
|
||||
- Add a CLI command to delete actors
|
||||
- Make sure activity notification recaps can't be sent multiple times
|
||||
- Fix group notification of new event being sent multiple times
|
||||
- Fix links to group page in group membership emails and participation
|
||||
- Fix clicking on map crashing the app
|
||||
- Remove unused fragment from FETCH_PERSON GraphQL query
|
||||
|
||||
## 2.1.0-rc.5 - 2022-05-06
|
||||
|
||||
Changes since rc.4:
|
||||
|
||||
- Add appropriate timeouts for Repo.transactions
|
||||
- Remove OS-specific packages
|
||||
- Remove refresh instance triggers
|
||||
- Add a proper error message when adding an instance follow that doesn't respond
|
||||
|
||||
## 2.1.0-rc.4 - 2022-05-03
|
||||
|
||||
Changes since rc.3:
|
||||
|
||||
- Use upstream dependencies for Ueberauth providers
|
||||
- Fix Ueberauth use of CSRF with session
|
||||
- Fix being an administrator when using 3rd-party auth provider
|
||||
- Include ongoing events in search
|
||||
- Send push notification into own task
|
||||
- Add Überauth CAS Strategy
|
||||
|
||||
## 2.1.0-rc.3 - 2022-04-24
|
||||
|
||||
Changes since rc.2:
|
||||
|
||||
- Fix activity notifications by preloading user.activity_settings
|
||||
- Add "Accept-Language" header to sentry request metadata
|
||||
- Hide address blocks when address has no real data
|
||||
- Fix text overflow on group card description
|
||||
- Exclude tags with more than 40 characters from being extracted
|
||||
- Avoid duplicate tags with different casing
|
||||
- Fix invalid HTML (<div> inside <label>)
|
||||
- Remove attribute type="text/css" from <style> tags
|
||||
- Improve actor cards integration
|
||||
- Fix latest group not refreshing in admin section
|
||||
- Add missing "relay@" part of federated address to follow
|
||||
|
||||
## 2.1.0-rc.2 - 2022-04-20
|
||||
|
||||
Changes since rc.1:
|
||||
|
||||
- Hide the whole metadata block if group has no description
|
||||
- Increase task timeout in Refresher to 60 seconds
|
||||
- Allow webfinger to be fetched over http (not https) in dev mode
|
||||
- Fix rejecting instance follow
|
||||
- Allow instance to have non-standard ports
|
||||
- Improve reactions when approving/rejecting an instance follow
|
||||
- Improve instance admin view for mobile
|
||||
- Allow to reject instance following
|
||||
- Fix pagination of group events
|
||||
- Add pagination to the instances list
|
||||
- Upgrade deps
|
||||
- Eventually fetch actors in mentions
|
||||
- Add proper fallback for when a TZ isn't registered
|
||||
- Improve IdentityPicker
|
||||
- Hide side of report modal on low width screens
|
||||
- Improve JoinGroupWithAccount component
|
||||
- Various group and posts improvements
|
||||
- Fix Telegram Logo being replaced with Mastodon logo in ShareGroupModal
|
||||
- Change URL to Mastodon Share Manager
|
||||
- Improve ActorInline component
|
||||
- Avoid assuming we're on Debian-based in release build
|
||||
- Fix receiving Flag activities on federated events
|
||||
- Update schema.graphql file
|
||||
|
||||
## 2.1.0-rc.1 - 2022-04-18
|
||||
|
||||
Changes since beta.3:
|
||||
|
||||
- Fix posts creation
|
||||
- Fix some typespecs
|
||||
- Remove Koena Connect button
|
||||
- Update dependencies
|
||||
|
||||
## 2.1.0-beta.3 - 2022-04-09
|
||||
|
||||
Changes since beta.2:
|
||||
|
||||
- Add Fedora and Alpine builds
|
||||
|
||||
## 2.1.0-beta.2 - 2022-04-08
|
||||
|
||||
Changes since beta.1 :
|
||||
|
||||
- Build release packages for several distributions (Debian Bullseye, Debian Buster, Ubuntu Focal, Ubuntu Bionic) because of libc version changes
|
||||
|
||||
## 2.1.0-beta.1 - 2022-04-07
|
||||
|
||||
### Added
|
||||
|
||||
- Added an event category field. Administrators can extend the pre-configured list of categories through configuration.
|
||||
- Added possibility for administrators to have analytics (Matomo, Plausible supported) and error handling (Sentry supported) on front-end.
|
||||
- Redesigned federation admin section with dedicated instance pages
|
||||
- Allow to filter moderation reports by domain
|
||||
- Added a button to go to past events of a group if it has no upcoming events
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed mailer library from Bamboo to Swoosh, should fix emails being considered spam. **Some configuration changes are required, see below.**
|
||||
- Expose some fields to ActivityStreams event representation: `isOnline`, `remainingAttendeeCapacity` and `participantCount`
|
||||
- Expose a new field to ActivityStreams group representation: `memberCount`
|
||||
- Improve group creation errors feedback
|
||||
- Only display locality in event card
|
||||
- Stale groups are now excluded from group search
|
||||
- Event default visibility is now set according to group privacy setting
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed actor refreshment being impossible
|
||||
- Fixed ical export for undefined datetimes
|
||||
- Fixed parsing links with hashtag characters
|
||||
- Fixed fetching link details from Twitter
|
||||
- Fixed Thunderbird accessing ICS feed endpoint with special `Accept` HTTP header
|
||||
- Make sure every ICS/Feed caches are emptied when modifying entities
|
||||
- Fixed time issues with DST changes
|
||||
- Fixed group preview card not truncating description
|
||||
- Fixed redirection after login
|
||||
- Fixed user admin section showing button to confirm user when the user is already confirmed
|
||||
- Fixed creating event from group view not always setting the group as organizer
|
||||
- Fixed invalid addresses blocking event metadata preview rendering
|
||||
- Fixed group deletion with comments that caused foreign key issues
|
||||
- Fixed incoming Accept activities from participations we don't already have
|
||||
- Fixed resources that didn't have metadata size limits
|
||||
- Properly fallback to UTC when sending notifications and the user doesn't have a timezone setting set
|
||||
|
||||
### Translations
|
||||
|
||||
- Arabic
|
||||
- Basque
|
||||
- Belarusian
|
||||
- Bengali
|
||||
- Catalan
|
||||
- Chinese (Traditional)
|
||||
- Croatian
|
||||
- Czech
|
||||
- Danish
|
||||
- Dutch
|
||||
- Esperanto
|
||||
- Finnish
|
||||
- French
|
||||
- Gaelic
|
||||
- Galician
|
||||
- German
|
||||
- Hebrew
|
||||
- Hungarian
|
||||
- Indonesian
|
||||
- Italian
|
||||
- Japanese
|
||||
- Kabyle
|
||||
- Kannada
|
||||
- Norwegian Nynorsk
|
||||
- Occitan
|
||||
- Persian
|
||||
- Polish
|
||||
- Portuguese
|
||||
- Portuguese (Brazil)
|
||||
- Russian
|
||||
- Slovenian
|
||||
- Spanish
|
||||
- Swedish
|
||||
- Welsh
|
||||
|
||||
## 2.0.2 - 2021-12-22
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved handling of media file deletion
|
||||
- Releases and Docker image are now using Elixir 1.13
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed position of tentative tag on event cards
|
||||
- Fixed text overflow when a link is too long in event mobile view
|
||||
- Fixed filtering user own memberships and group members in event organizer & contacts picker
|
||||
- Fixed first day of week not depending on locale in the datetime picker
|
||||
- Fixed the admin page when a group/profile/user was not found
|
||||
- Fixed group members pagination on admin group profile view
|
||||
- Fixed admin edition of the instance's language
|
||||
|
||||
### Translations
|
||||
|
||||
- Croatian
|
||||
- Czech
|
||||
- Esperanto
|
||||
- German
|
||||
- Hebrew
|
||||
- Occitan
|
||||
- Persian
|
||||
- Russian
|
||||
- Spanish
|
||||
|
||||
## 2.0.1 - 2021-11-26
|
||||
|
||||
### Changed
|
||||
|
||||
- Remove litepub context
|
||||
|
||||
### Fixed
|
||||
|
||||
- Make sure my group upcoming events are ordered by their start date
|
||||
- Fix event participants pagination
|
||||
- Always focus the search field after results have been fetched
|
||||
- Don't sign fetches to instance actor when refreshing their keys
|
||||
- Fix reject of already following instances
|
||||
- Added missing timezone data to the Docker image
|
||||
- Replace @tiptap/starter-kit with indidual extensions, removing unneeded extensions that caused issues on old Firefox versions
|
||||
- Better handling of Friendica Update activities without actor information
|
||||
- Always show pending/cancelled status on event cards
|
||||
- Fixed nightly docker build
|
||||
- Refresh loggeduser information before the final step of onboarding, avoiding loop when finishing onboarding
|
||||
- Handle tz_world data being absent
|
||||
|
||||
### Translations
|
||||
|
||||
- Croatian (New !)
|
||||
- Czech
|
||||
- Gaelic
|
||||
- Hungarian
|
||||
- Indonesian
|
||||
- Welsh (New !)
|
||||
|
||||
## 2.0.0 - 2021-11-23
|
||||
|
||||
Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||
@ -134,7 +498,6 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- Slovenian
|
||||
- Spanish
|
||||
|
||||
|
||||
## 2.0.0-rc.3 - 2021-11-22
|
||||
|
||||
This lists changes since 2.0.0-rc.3. Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||
@ -155,11 +518,13 @@ This lists changes since 2.0.0-rc.1. Please read the [UPGRADE.md](https://framag
|
||||
- Improve MyEvents page description text
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix spacing in organizer picker
|
||||
- Increase number of close events and follow group events
|
||||
- Fix accessing user profile in admin section
|
||||
- Set initial values for some EventMetadata elements, fixing submitting them right away with no value
|
||||
- Avoid giving an error page if the apollo futureParticipations query is undefined
|
||||
|
||||
### Translations
|
||||
|
||||
- German
|
||||
@ -180,6 +545,7 @@ This lists changes since 2.0.0-beta.2. Please read the [UPGRADE.md](https://fram
|
||||
- Add "formerType" and "delete" attributes on Tombstones ActivityPub objects representation
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed creating group activities when creating events with some fields
|
||||
- Move release package at correct path for CI upload
|
||||
- Fixed event contacts that were not exposed and fetched over federation
|
||||
@ -198,6 +564,7 @@ This lists changes since 2.0.0-beta.2. Please read the [UPGRADE.md](https://fram
|
||||
## 2.0.0-beta.2 - 2021-11-15
|
||||
|
||||
This lists changes since 2.0.0-beta.1. Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||
|
||||
### Added
|
||||
|
||||
- Group followers and members get an notification email by default when a group publishes a new event (subject to activity notification settings)
|
||||
@ -234,6 +601,7 @@ This lists changes since 2.0.0-beta.1. Please read the [UPGRADE.md](https://fram
|
||||
## 2.0.0-beta.1 - 2021-11-09
|
||||
|
||||
Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||
|
||||
### Added
|
||||
|
||||
- Added possibility to follow groups and be notified from new upcoming events
|
||||
@ -298,6 +666,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
### Security
|
||||
|
||||
- Fixed private messages sent as event replies from Mastodon that were shown publically as public comments. They are now discarded.
|
||||
|
||||
### Translations
|
||||
|
||||
- Czech
|
||||
@ -365,7 +734,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
### Fixed
|
||||
|
||||
- Fixed links contained in event & post description that didn't open in new tabs
|
||||
- Add back missing RSS/ical links on public group pages
|
||||
- Add back missing RSS/ical links on public group pages
|
||||
- Fixed links to Framacolibri forum
|
||||
- Fixed drafts and restricted visibility events & posts listed on group page
|
||||
- Fixed notification page on Safari
|
||||
@ -387,7 +756,6 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- Fixed token refreshment issues
|
||||
- Fixed search from 404 page
|
||||
|
||||
|
||||
### Translations
|
||||
|
||||
- Catalan
|
||||
@ -413,9 +781,10 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- Fixed group discussions with deleted comments
|
||||
|
||||
## 1.2.2 - 2021-07-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved UI for participations when message is too long
|
||||
- Improved UI for participations when message is too long
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -423,7 +792,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- Fixed crash when trying to notify activities not from groups
|
||||
- Fixed imagemagick missing from Dockerfile
|
||||
- Fixed push notifications for group, members & post activities
|
||||
- Fixed ellipsis in DiscussionListView
|
||||
- Fixed ellipsis in DiscussionListView
|
||||
- Fixed submission button for posts not visible on mobile
|
||||
- Fixed remote profile suspension
|
||||
|
||||
@ -439,6 +808,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- Fixed compatibility check in Notification section for service workers
|
||||
|
||||
## 1.2.0 - 2021-06-29
|
||||
|
||||
### Added
|
||||
|
||||
- **Notifications for various group and event activity, both by email and browser push notifications. Daily and weekly digests are also available.**
|
||||
@ -453,7 +823,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
- **Various improvements to mobile views**
|
||||
- Make JWT access tokens short-lived
|
||||
- Disabled Cldr warning that the `Cldr.Plug.AcceptLanguage` plug didn't many any known locale
|
||||
- Replaced GraphiQL web interface with graphql-playground
|
||||
- Replaced GraphiQL web interface with graphql-playground
|
||||
|
||||
### Removed
|
||||
|
||||
@ -613,7 +983,7 @@ Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/mai
|
||||
### Changed
|
||||
|
||||
- Added an unique index on the addresses url
|
||||
- Added org.opencontainers.image.source annotation to the Docker image
|
||||
- Added org.opencontainers.image.source annotation to the Docker image
|
||||
- Improved the moderation action logs interface
|
||||
|
||||
### Fixes
|
||||
@ -734,7 +1104,7 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
- Fixed getting metadata from tweets when creating a resource
|
||||
- Fixed bad handling of duplicate usernames
|
||||
- Fixed handling of bad URIs to proxify
|
||||
- Fixed creating discussion with title containing only spaces
|
||||
- Fixed creating discussion with title containing only spaces
|
||||
- Fixed registering new user account with same email as unconfirmed
|
||||
- Fixed handling changing default actor unlogged
|
||||
- Fixed handling getting organized events from an actor when not authorized
|
||||
@ -806,6 +1176,7 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
- Hungarian
|
||||
- Russian
|
||||
- Spanish
|
||||
|
||||
## 1.1.0-rc.1 - 2021-03-29
|
||||
|
||||
### Added
|
||||
@ -831,7 +1202,7 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
- Fixed getting metadata from tweets when creating a resource
|
||||
- Fixed bad handling of duplicate usernames
|
||||
- Fixed handling of bad URIs to proxify
|
||||
- Fixed creating discussion with title containing only spaces
|
||||
- Fixed creating discussion with title containing only spaces
|
||||
- Fixed registering new user account with same email as unconfirmed
|
||||
- Fixed handling changing default actor unlogged
|
||||
- Fixed handling getting organized events from an actor when not authorized
|
||||
@ -853,11 +1224,13 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
## 1.1.0-beta.6 - 2021-03-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a typo in range/radius showing the wrong radius for close events on homepage
|
||||
|
||||
## 1.1.0-beta.5 - 2021-03-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a typo in range/radius preventing close events from showing up
|
||||
|
||||
## 1.1.0-beta.4 - 2021-03-17
|
||||
@ -871,15 +1244,18 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
## 1.1.0-beta.3 - 2021-03-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- Handle ActivityPub Fetcher returning text that's not JSON
|
||||
- Fix accessing a group profile when not a member
|
||||
|
||||
## 1.1.0-beta.2 - 2021-03-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed geospatial configuration only being evaluated at compile-time, not at runtime
|
||||
|
||||
### Translations
|
||||
|
||||
- Slovenian
|
||||
|
||||
## 1.1.0-beta.1 - 2021-03-10
|
||||
@ -1021,23 +1397,23 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
|
||||
### Special operations
|
||||
|
||||
* **Reattach media files to their entity.**
|
||||
- **Reattach media files to their entity.**
|
||||
When media files were uploaded and added in events and posts bodies, they were only attached to the profile that uploaded them, not to the event or post. This task attaches them back to their entity so that the command to clean orphan media files doesn't remove them.
|
||||
|
||||
* Source install
|
||||
- Source install
|
||||
`MIX_ENV=prod mix mobilizon.maintenance.fix_unattached_media_in_body`
|
||||
* Docker
|
||||
- Docker
|
||||
`docker-compose exec mobilizon mobilizon_ctl maintenance.fix_unattached_media_in_body`
|
||||
|
||||
* **Refresh remote profiles to save avatars locally**
|
||||
- **Refresh remote profiles to save avatars locally**
|
||||
Profile avatars and banners were previously only proxified and cached. Now we save them locally. Refreshing all remote actors will save profile media locally instead.
|
||||
|
||||
* Source install
|
||||
- Source install
|
||||
`MIX_ENV=prod mix mobilizon.actors.refresh --all`
|
||||
* Docker
|
||||
- Docker
|
||||
`docker-compose exec mobilizon mobilizon_ctl actors.refresh --all`
|
||||
|
||||
* **imagemagick and webp are now a required dependency** to build Mobilizon.
|
||||
- **imagemagick and webp are now a required dependency** to build Mobilizon.
|
||||
Optimized versions of Mobilizon's pictures are now produced during front-end build.
|
||||
See [the documentation](https://docs.joinmobilizon.org/administration/dependencies/#misc) to make sure these dependencies are installed.
|
||||
|
||||
@ -1080,7 +1456,7 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
- Fixed error message not showing up when you are already an anonymous participant for an event
|
||||
- Fixed error message not showing up when you pick an username already in user for a new profile or a group
|
||||
- Fixed translations not fallbacking properly to english when not found
|
||||
-
|
||||
-
|
||||
|
||||
### Security
|
||||
|
||||
@ -1089,6 +1465,7 @@ This version introduces a new way to install and host Mobilizon : Elixir releas
|
||||
### Translations
|
||||
|
||||
Updated translations:
|
||||
|
||||
- Catalan
|
||||
- Dutch
|
||||
- English
|
||||
@ -1261,20 +1638,21 @@ Updated translations:
|
||||
|
||||
### Special operations
|
||||
|
||||
* We added `application/ld+json` as acceptable MIME type for ActivityPub requests, so you'll need to recompile the `mime` library we use before recompiling Mobilizon:
|
||||
```
|
||||
MIX_ENV=prod mix deps.clean mime --build
|
||||
```
|
||||
- We added `application/ld+json` as acceptable MIME type for ActivityPub requests, so you'll need to recompile the `mime` library we use before recompiling Mobilizon:
|
||||
|
||||
* The [nginx configuration](https://framagit.org/framasoft/mobilizon/-/blob/main/support/nginx/mobilizon.conf) has been changed with improvements and support for custom error pages.
|
||||
```
|
||||
MIX_ENV=prod mix deps.clean mime --build
|
||||
```
|
||||
|
||||
* The cmake dependency has been added (see [our documentation](https://docs.joinmobilizon.org/administration/dependencies/#basic-tools))
|
||||
- The [nginx configuration](https://framagit.org/framasoft/mobilizon/-/blob/main/support/nginx/mobilizon.conf) has been changed with improvements and support for custom error pages.
|
||||
|
||||
- The cmake dependency has been added (see [our documentation](https://docs.joinmobilizon.org/administration/dependencies/#basic-tools))
|
||||
|
||||
### Added
|
||||
|
||||
- Possibility to login using LDAP
|
||||
- Possibility to login using OAuth providers
|
||||
- Enabled group features in production mode
|
||||
- Enabled group features in production mode
|
||||
- including posts (that can be public, unlisted, or restricted to your group members)
|
||||
- resources (collections of links, with folders, accessible to your group members)
|
||||
- discussions (group private and organized chats)
|
||||
@ -1298,11 +1676,12 @@ Updated translations:
|
||||
### Security
|
||||
|
||||
- Fix group settings being accessible and editable by non-group-admins (thx @pigpig for reporting this responsibly)
|
||||
- Fix events being editable by profiles without permissions (thx @pigpig for reporting this responsibly)
|
||||
- Fix events being editable by profiles without permissions (thx @pigpig for reporting this responsibly)
|
||||
|
||||
## [1.0.0-beta.3] - 2020-06-24
|
||||
|
||||
### Special operations
|
||||
|
||||
Config has moved from `.env` files to a more traditional way to handle things in the Elixir world, with `.exs` files.
|
||||
|
||||
To migrate existing configuration, you can simply run `mix mobilizon.instance gen` and fill in the adequate values previously in `.env` files (you don't need to perform the operations to create the database).
|
||||
@ -1312,6 +1691,7 @@ A minimal file template [is available](https://framagit.org/framasoft/mobilizon/
|
||||
Also make sure to remove the `EnvironmentFile=` line from the systemd service and set `Environment=MIX_ENV=prod` instead. See [the updated file](https://framagit.org/framasoft/mobilizon/blob/main/support/systemd/mobilizon.service).
|
||||
|
||||
### Added
|
||||
|
||||
- Possibility to participate to an event without an account (confirmation through email required)
|
||||
- Possibility to participate to a remote event (being redirected by providing federated identity)
|
||||
- Possibility to add a note as a participant when event participation is manually validated (required when participating without an account)
|
||||
@ -1328,6 +1708,7 @@ Also make sure to remove the `EnvironmentFile=` line from the systemd service an
|
||||
- Allow user to change language
|
||||
|
||||
### Changed
|
||||
|
||||
- Configuration handling (see above)
|
||||
- Improved a bit color theme
|
||||
- Signature validation also now checks if `Date` header has acceptable values
|
||||
@ -1338,6 +1719,7 @@ Also make sure to remove the `EnvironmentFile=` line from the systemd service an
|
||||
- Improved public event page
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed URL search
|
||||
- Fixed content accessed through URL search being public
|
||||
- Fix event links in some emails
|
||||
@ -1345,17 +1727,21 @@ Also make sure to remove the `EnvironmentFile=` line from the systemd service an
|
||||
## [1.0.0-beta.2] - 2019-12-18
|
||||
|
||||
### Special operations
|
||||
|
||||
These two operations couldn't be handled during migrations.
|
||||
They are optional, but you won't be able to search or get participant stats on existing events if they are not executed.
|
||||
These commands will be removed in Mobilizon 1.0.0-beta.3.
|
||||
|
||||
In order to populate search index for existing events, you need to run the following command (with prod environment):
|
||||
* `mix mobilizon.setup_search`
|
||||
|
||||
- `mix mobilizon.setup_search`
|
||||
|
||||
In order to move participant stats to the event table for existing events, you need to run the following command (with prod environment):
|
||||
* `mix mobilizon.move_participant_stats`
|
||||
|
||||
- `mix mobilizon.move_participant_stats`
|
||||
|
||||
### Added
|
||||
|
||||
- Federation is active
|
||||
- Added an interface for admins to view and manage instance followers and followings
|
||||
- Ability to comment below events
|
||||
@ -1380,6 +1766,7 @@ In order to move participant stats to the event table for existing events, you n
|
||||
- Upgraded frontend and backend dependencies
|
||||
|
||||
### Changed
|
||||
|
||||
- Move participant stats to event table **(read special instructions above)**
|
||||
- Limit length (20 characters) and number (10) of tags allowed
|
||||
- Added some backend changes and validation for field length
|
||||
@ -1393,6 +1780,7 @@ In order to move participant stats to the event table for existing events, you n
|
||||
- Also consider the PeerTube `CommentsEnabled` property to know if you can reply to an event
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix event URL validation and check if hostname is correct before showing it
|
||||
- Fix participations stats on the MyEvents page
|
||||
- Fix event description lists margin
|
||||
@ -1422,8 +1810,11 @@ In order to move participant stats to the event table for existing events, you n
|
||||
- Fixed event HTML representation when `GET` request has no `Accept` header
|
||||
|
||||
### Security
|
||||
|
||||
- Sanitize event title to avoid XSS
|
||||
|
||||
## [1.0.0-beta.1] - 2019-10-15
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release
|
||||
|
107
UPGRADE.md
107
UPGRADE.md
@ -1,7 +1,49 @@
|
||||
# Upgrading from 2.0 to 2.1
|
||||
|
||||
## Mailer library change
|
||||
|
||||
### Docker
|
||||
|
||||
The change is already applied. You may remove the `MOBILIZON_SMTP_HOSTNAME` environment key which is not used anymore.
|
||||
|
||||
### Release and source mode
|
||||
|
||||
In your configuration file under `config :mobilizon, Mobilizon.Web.Email.Mailer`,
|
||||
|
||||
- Change `Bamboo.SMTPAdapter` to `Swoosh.Adapters.SMTP`,
|
||||
- rename the `server` key to `relay`
|
||||
- remove the `hostname` key,
|
||||
- the default value of the username and password fields is an empty string and no longer `nil`.
|
||||
|
||||
```diff
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer,
|
||||
- adapter: Bamboo.SMTPAdapter,
|
||||
+ adapter: Swoosh.Adapters.SMTP,
|
||||
- server: "localhost",
|
||||
+ relay: "localhost",
|
||||
- hostname: "localhost",
|
||||
# usually 25, 465 or 587
|
||||
port: 25,
|
||||
- username: nil,
|
||||
+ username: "",
|
||||
- password: nil,
|
||||
+ password: "",
|
||||
# can be `:always` or `:never`
|
||||
tls: :if_available,
|
||||
allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
|
||||
retries: 1,
|
||||
# can be `true`
|
||||
no_mx_lookups: false,
|
||||
# can be `:always`. If your smtp relay requires authentication set it to `:always`.
|
||||
auth: :if_available
|
||||
```
|
||||
|
||||
# Upgrading from 1.3 to 2.0
|
||||
|
||||
Requirements dependencies depend on the way Mobilizon is installed.
|
||||
|
||||
## New Elixir version requirement
|
||||
|
||||
### Docker and Release install
|
||||
|
||||
You are already using latest Elixir version in the release tarball and Docker images.
|
||||
@ -17,24 +59,27 @@ Mobilizon 2.0 uses data based on [timezone-boundary-builder](https://github.com/
|
||||
### Docker install
|
||||
|
||||
The geographic timezone data is already bundled into the image, you have nothing to do.
|
||||
|
||||
### Release install
|
||||
|
||||
In order to keep the release tarballs light, the geographic timezone data is not bundled directly. You need to download the data :
|
||||
* either raw from Github, but **requires an extra ~1Gio of memory** to process the data
|
||||
|
||||
- either raw from Github, but **requires an extra ~1Gio of memory** to process the data
|
||||
|
||||
```sh
|
||||
sudo -u mobilizon mkdir /var/lib/mobilizon/timezones
|
||||
sudo -u mobilizon ./bin/mobilizon_ctl tz_world.update
|
||||
```
|
||||
|
||||
* either already processed from our own distribution server
|
||||
- either already processed from our own distribution server
|
||||
|
||||
```sh
|
||||
sudo -u mobilizon mkdir /var/lib/mobilizon/timezones
|
||||
sudo -u mobilizon curl -L 'https://packages.joinmobilizon.org/tz_world/timezones-geodata.dets' -o /var/lib/mobilizon/timezones/timezones-geodata.dets
|
||||
```
|
||||
|
||||
In both cases, ~700Mio of disk will be used. You may use the following configuration to specify where the data is expected:
|
||||
In both cases, ~700Mio of disk will be used. You may use the following configuration to specify where the data is expected if you decide to change it from the default location (`/var/lib/mobilizon/timezones`) :
|
||||
|
||||
```elixir
|
||||
config :tz_world, data_dir: "/some/place"
|
||||
```
|
||||
@ -42,14 +87,15 @@ config :tz_world, data_dir: "/some/place"
|
||||
### Source install
|
||||
|
||||
You need to download the data :
|
||||
* either raw from Github, but **requires an extra ~1Gio of memory** to process the data
|
||||
|
||||
- either raw from Github, but **requires an extra ~1Gio of memory** to process the data
|
||||
|
||||
```sh
|
||||
sudo -u mobilizon mkdir /var/lib/mobilizon/timezones
|
||||
sudo -u mobilizon mix mobilizon.tz_world.update
|
||||
```
|
||||
|
||||
* either already processed from our own distribution server
|
||||
- either already processed from our own distribution server
|
||||
|
||||
```sh
|
||||
sudo -u mobilizon mkdir /var/lib/mobilizon/timezones
|
||||
@ -57,6 +103,7 @@ You need to download the data :
|
||||
```
|
||||
|
||||
In both cases, ~700Mio of disk will be used. You may use the following configuration to specify where the data is expected:
|
||||
|
||||
```elixir
|
||||
config :tz_world, data_dir: "/some/place"
|
||||
```
|
||||
@ -75,14 +122,18 @@ Files in this folder are temporary and are cleaned once an hour.
|
||||
## New optional dependencies
|
||||
|
||||
These are optional, installing them will allow Mobilizon to export to PDF and ODS as well. Mobilizon 2.0 allows to export the participant list, but more is planned.
|
||||
|
||||
### Docker
|
||||
|
||||
Everything is included in our Docker image.
|
||||
|
||||
### Release and source install
|
||||
|
||||
New optional Python dependencies:
|
||||
* `Python` >= 3.6
|
||||
* `weasyprint` for PDF export (with [a few extra dependencies](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html))
|
||||
* `pyexcel-ods3` for ODS export (no extra dependencies)
|
||||
|
||||
- `Python` >= 3.6
|
||||
- `weasyprint` for PDF export (with [a few extra dependencies](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html))
|
||||
- `pyexcel-ods3` for ODS export (no extra dependencies)
|
||||
|
||||
Both can be installed through pip. You need to enable and configure exports for PDF and ODS in the configuration afterwards. Read [the dedicated docs page about this](https://docs.joinmobilizon.org/administration/configure/exports/).
|
||||
|
||||
@ -91,35 +142,41 @@ Both can be installed through pip. You need to enable and configure exports for
|
||||
The 1.1 version of Mobilizon brings Elixir releases support. An Elixir release is a self-contained directory that contains all of Mobilizon's code (front-end and backend), it's dependencies, as well as the Erlang Virtual Machine and runtime (only the parts you need). As long as the release has been assembled on the same OS and architecture, it can be deploy and run straight away. [Read more about releases](https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html#releases).
|
||||
|
||||
## Comparison
|
||||
|
||||
Migrating to releases means:
|
||||
* You only get a precompiled binary, so you avoid compilation times when updating
|
||||
* No need to have Elixir/NodeJS installed on the system
|
||||
* Code/data/config location is more common (/opt, /var/lib, /etc)
|
||||
* More efficient, as only what you need from the Elixir/Erlang standard libraries is included and all of the code is directly preloaded
|
||||
* You can't hardcode modifications in Mobilizon's code
|
||||
|
||||
- You only get a precompiled binary, so you avoid compilation times when updating
|
||||
- No need to have Elixir/NodeJS installed on the system
|
||||
- Code/data/config location is more common (/opt, /var/lib, /etc)
|
||||
- More efficient, as only what you need from the Elixir/Erlang standard libraries is included and all of the code is directly preloaded
|
||||
- You can't hardcode modifications in Mobilizon's code
|
||||
|
||||
Staying on source releases means:
|
||||
* You need to recompile everything with each update
|
||||
* Compiling frontend and backend has higher system requirements than just running Mobilizon
|
||||
* You can change things in Mobilizon's code and recompile right away to test changes
|
||||
|
||||
- You need to recompile everything with each update
|
||||
- Compiling frontend and backend has higher system requirements than just running Mobilizon
|
||||
- You can change things in Mobilizon's code and recompile right away to test changes
|
||||
|
||||
## Releases
|
||||
|
||||
If you want to migrate to releases, [we provide a full guide](https://docs.joinmobilizon.org/administration/upgrading/source_to_release/). You may do this at any time.
|
||||
|
||||
## Source install
|
||||
|
||||
To stay on a source release, you just need to check the following things:
|
||||
* Rename your configuration file `config/prod.secret.exs` to `config/runtime.exs`.
|
||||
* If your config file includes `server: true` under `Mobilizon.Web.Endpoint`, remove it.
|
||||
```diff
|
||||
config :mobilizon, Mobilizon.Web.Endpoint,
|
||||
- server: true,
|
||||
```
|
||||
* The uploads default directory is now `/var/lib/mobilizon/uploads`. To keep it in the previous `uploads/` directory, just add the following line to `config/runtime.exs`:
|
||||
|
||||
- Rename your configuration file `config/prod.secret.exs` to `config/runtime.exs`.
|
||||
- If your config file includes `server: true` under `Mobilizon.Web.Endpoint`, remove it.
|
||||
```diff
|
||||
config :mobilizon, Mobilizon.Web.Endpoint,
|
||||
- server: true,
|
||||
```
|
||||
- The uploads default directory is now `/var/lib/mobilizon/uploads`. To keep it in the previous `uploads/` directory, just add the following line to `config/runtime.exs`:
|
||||
```elixir
|
||||
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "uploads"
|
||||
```
|
||||
Or you may use any other directory where the `mobilizon` user has write permissions.
|
||||
* The GeoIP database default directory is now `/var/lib/mobilizon/geo/GeoLite2-City.mmdb`. To keep it in the previous `priv/data/GeoLite2-City.mmdb` directory, just add the following line to `config/runtime.exs`:
|
||||
- The GeoIP database default directory is now `/var/lib/mobilizon/geo/GeoLite2-City.mmdb`. To keep it in the previous `priv/data/GeoLite2-City.mmdb` directory, just add the following line to `config/runtime.exs`:
|
||||
```elixir
|
||||
config :geolix, databases: [
|
||||
%{
|
||||
@ -129,4 +186,4 @@ To stay on a source release, you just need to check the following things:
|
||||
}
|
||||
]
|
||||
```
|
||||
Or you may use any other directory where the `mobilizon` user has read permissions.
|
||||
Or you may use any other directory where the `mobilizon` user has read permissions.
|
||||
|
@ -106,13 +106,16 @@ config :mobilizon, :media_proxy,
|
||||
]
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer,
|
||||
adapter: Bamboo.SMTPAdapter,
|
||||
server: "localhost",
|
||||
hostname: "localhost",
|
||||
adapter: Swoosh.Adapters.SMTP,
|
||||
relay: "localhost",
|
||||
# usually 25, 465 or 587
|
||||
port: 25,
|
||||
username: nil,
|
||||
password: nil,
|
||||
username: "",
|
||||
password: "",
|
||||
# can be `:always` or `:never`
|
||||
auth: :if_available,
|
||||
# can be `true`
|
||||
ssl: false,
|
||||
# can be `:always` or `:never`
|
||||
tls: :if_available,
|
||||
allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
|
||||
@ -185,7 +188,13 @@ config :phoenix, :filter_parameters, ["password", "token"]
|
||||
config :absinthe, schema: Mobilizon.GraphQL.Schema
|
||||
config :absinthe, Absinthe.Logger, filter_variables: ["token", "password", "secret"]
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Gettext, one_module_per_locale: true
|
||||
config :codepagex, :encodings, [
|
||||
:ascii,
|
||||
~r[iso8859]i,
|
||||
:"VENDORS/MICSFT/WINDOWS/CP1252"
|
||||
]
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Gettext, split_module_by: [:locale, :domain]
|
||||
|
||||
config :ex_cldr,
|
||||
default_locale: "en",
|
||||
@ -206,7 +215,8 @@ config :mobilizon, :activitypub,
|
||||
# One day
|
||||
actor_stale_period: 3_600 * 48,
|
||||
actor_key_rotation_delay: 3_600 * 48,
|
||||
sign_object_fetches: true
|
||||
sign_object_fetches: true,
|
||||
stale_actor_search_exclusion_after: 3_600 * 24 * 7
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim
|
||||
|
||||
@ -290,6 +300,7 @@ config :mobilizon, Oban,
|
||||
crontab: [
|
||||
{"@hourly", Mobilizon.Service.Workers.BuildSiteMap, queue: :background},
|
||||
{"17 4 * * *", Mobilizon.Service.Workers.RefreshGroups, queue: :background},
|
||||
{"36 * * * *", Mobilizon.Service.Workers.RefreshInstances, queue: :background},
|
||||
{"@hourly", Mobilizon.Service.Workers.CleanOrphanMediaWorker, queue: :background},
|
||||
{"@hourly", Mobilizon.Service.Workers.CleanUnconfirmedUsersWorker, queue: :background},
|
||||
{"@hourly", Mobilizon.Service.Workers.ExportCleanerWorker, queue: :background},
|
||||
@ -336,6 +347,8 @@ config :mobilizon, :exports,
|
||||
Mobilizon.Service.Export.Participants.ODS
|
||||
]
|
||||
|
||||
config :mobilizon, :analytics, providers: []
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
import_config "#{config_env()}.exs"
|
||||
|
@ -67,7 +67,7 @@ config :phoenix, :stacktrace_depth, 20
|
||||
# Initialize plugs at runtime for faster development compilation
|
||||
config :phoenix, :plug_init_mode, :runtime
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer, adapter: Bamboo.LocalAdapter
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer, adapter: Swoosh.Adapters.Local
|
||||
|
||||
# Configure your database
|
||||
config :mobilizon, Mobilizon.Storage.Repo,
|
||||
|
@ -43,9 +43,8 @@ config :mobilizon, Mobilizon.Storage.Repo,
|
||||
pool_size: 10
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer,
|
||||
adapter: Bamboo.SMTPAdapter,
|
||||
server: System.get_env("MOBILIZON_SMTP_SERVER", "localhost"),
|
||||
hostname: System.get_env("MOBILIZON_SMTP_HOSTNAME", "localhost"),
|
||||
adapter: Swoosh.Adapters.SMTP,
|
||||
relay: System.get_env("MOBILIZON_SMTP_SERVER", "localhost"),
|
||||
port: System.get_env("MOBILIZON_SMTP_PORT", "25"),
|
||||
username: System.get_env("MOBILIZON_SMTP_USERNAME", nil),
|
||||
password: System.get_env("MOBILIZON_SMTP_PASSWORD", nil),
|
||||
|
@ -18,22 +18,27 @@ config :mobilizon, :cldr,
|
||||
locales: [
|
||||
"ar",
|
||||
"be",
|
||||
"bn",
|
||||
"ca",
|
||||
"cs",
|
||||
"cy",
|
||||
"de",
|
||||
"en",
|
||||
"es",
|
||||
"fa",
|
||||
"fi",
|
||||
"fr",
|
||||
"gd",
|
||||
"gl",
|
||||
"hu",
|
||||
"id",
|
||||
"it",
|
||||
"ja",
|
||||
"nl",
|
||||
"nn",
|
||||
"oc",
|
||||
"pl",
|
||||
"pt",
|
||||
"ru",
|
||||
"sv"
|
||||
"sv",
|
||||
"zh_Hant"
|
||||
]
|
||||
|
@ -54,7 +54,7 @@ config :mobilizon, :ldap,
|
||||
bind_uid: System.get_env("LDAP_BIND_UID"),
|
||||
bind_password: System.get_env("LDAP_BIND_PASSWORD")
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer, adapter: Bamboo.TestAdapter
|
||||
config :mobilizon, Mobilizon.Web.Email.Mailer, adapter: Swoosh.Adapters.Test
|
||||
|
||||
config :mobilizon, Mobilizon.Web.Upload, filters: [], link_name: false
|
||||
|
||||
|
@ -12,7 +12,7 @@ RUN yarn install --network-timeout 100000 \
|
||||
&& yarn run build
|
||||
|
||||
# Then, build the application binary
|
||||
FROM elixir:1.12-alpine AS builder
|
||||
FROM elixir:1.13-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache build-base git cmake
|
||||
|
||||
@ -49,11 +49,14 @@ LABEL org.opencontainers.image.title="mobilizon" \
|
||||
org.opencontainers.image.revision=$VCS_REF \
|
||||
org.opencontainers.image.created=$BUILD_DATE
|
||||
|
||||
RUN apk add --no-cache openssl ca-certificates ncurses-libs file postgresql-client libgcc libstdc++ imagemagick python3 py3-pip py3-pillow py3-cffi py3-brotli gcc musl-dev python3-dev pango libxslt-dev
|
||||
RUN apk add --no-cache curl openssl ca-certificates ncurses-libs file postgresql-client libgcc libstdc++ imagemagick python3 py3-pip py3-pillow py3-cffi py3-brotli gcc g++ musl-dev python3-dev pango libxslt-dev ttf-cantarell
|
||||
RUN pip install weasyprint pyexcel-ods3
|
||||
|
||||
RUN mkdir -p /var/lib/mobilizon/uploads && chown nobody:nobody /var/lib/mobilizon/uploads
|
||||
RUN mkdir -p /var/lib/mobilizon/timezones && chown nobody:nobody /var/lib/mobilizon/timezones
|
||||
RUN mkdir -p /var/lib/mobilizon/uploads/exports/{csv,pdf,ods} && chown -R nobody:nobody /var/lib/mobilizon/uploads/exports
|
||||
RUN mkdir -p /var/lib/mobilizon/timezones
|
||||
RUN curl -L 'https://packages.joinmobilizon.org/tz_world/timezones-geodata.dets' -o /var/lib/mobilizon/timezones/timezones-geodata.dets
|
||||
RUN chown nobody:nobody /var/lib/mobilizon/timezones
|
||||
RUN mkdir -p /etc/mobilizon && chown nobody:nobody /etc/mobilizon
|
||||
|
||||
USER nobody
|
||||
|
@ -1,15 +1,11 @@
|
||||
FROM elixir:latest
|
||||
LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
|
||||
|
||||
ENV REFRESHED_AT=2021-10-04
|
||||
ENV REFRESHED_AT=2022-04-06
|
||||
RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool python3-pip python3-setuptools
|
||||
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash && apt-get install nodejs -yq
|
||||
RUN npm install -g yarn wait-on
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
RUN mix local.hex --force && mix local.rebar --force
|
||||
# Weasyprint 53 requires pango >= 1.44.0, which is not available in Stretch.
|
||||
# TODO: Remove the version requirement when elixir:latest is based on Bullseye
|
||||
# https://github.com/erlang/docker-erlang-otp/issues/362
|
||||
# https://github.com/Kozea/WeasyPrint/issues/1384
|
||||
RUN pip3 install -Iv weasyprint==52 pyexcel_ods3
|
||||
RUN pip3 install -Iv weasyprint pyexcel_ods3
|
||||
RUN curl https://dbip.mirror.framasoft.org/files/dbip-city-lite-latest.mmdb --output GeoLite2-City.mmdb -s && mkdir -p /usr/share/GeoIP && mv GeoLite2-City.mmdb /usr/share/GeoIP/
|
||||
|
@ -29,7 +29,6 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"cypress/no-unnecessary-waiting": "off",
|
||||
"vue/max-len": [
|
||||
"off",
|
||||
{
|
||||
|
@ -1 +1,6 @@
|
||||
{}
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": true
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mobilizon",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@ -8,7 +8,7 @@
|
||||
"test:unit": "LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 TZ=UTC vue-cli-service test:unit",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"lint": "vue-cli-service lint",
|
||||
"build:assets": "vue-cli-service build",
|
||||
"build:assets": "vue-cli-service build --report",
|
||||
"build:pictures": "bash ./scripts/build/pictures.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -16,23 +16,35 @@
|
||||
"@absinthe/socket-apollo-link": "^0.2.1",
|
||||
"@apollo/client": "^3.3.16",
|
||||
"@mdi/font": "^6.1.95",
|
||||
"@sentry/tracing": "^6.16.1",
|
||||
"@sentry/vue": "^6.16.1",
|
||||
"@tailwindcss/line-clamp": "^0.4.0",
|
||||
"@tiptap/core": "^2.0.0-beta.41",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.25",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.24",
|
||||
"@tiptap/extension-bubble-menu": "^2.0.0-beta.9",
|
||||
"@tiptap/extension-character-count": "^2.0.0-beta.5",
|
||||
"@tiptap/extension-history": "^2.0.0-beta.5",
|
||||
"@tiptap/extension-bullet-list": "^2.0.0-beta.23",
|
||||
"@tiptap/extension-document": "^2.0.0-beta.15",
|
||||
"@tiptap/extension-dropcursor": "^2.0.0-beta.25",
|
||||
"@tiptap/extension-gapcursor": "^2.0.0-beta.33",
|
||||
"@tiptap/extension-heading": "^2.0.0-beta.23",
|
||||
"@tiptap/extension-history": "^2.0.0-beta.21",
|
||||
"@tiptap/extension-image": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-italic": "^2.0.0-beta.24",
|
||||
"@tiptap/extension-link": "^2.0.0-beta.8",
|
||||
"@tiptap/extension-list-item": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-list-item": "^2.0.0-beta.19",
|
||||
"@tiptap/extension-mention": "^2.0.0-beta.42",
|
||||
"@tiptap/extension-ordered-list": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-ordered-list": "^2.0.0-beta.24",
|
||||
"@tiptap/extension-paragraph": "^2.0.0-beta.22",
|
||||
"@tiptap/extension-strike": "^2.0.0-beta.26",
|
||||
"@tiptap/extension-text": "^2.0.0-beta.15",
|
||||
"@tiptap/extension-underline": "^2.0.0-beta.7",
|
||||
"@tiptap/starter-kit": "^2.0.0-beta.37",
|
||||
"@tiptap/vue-2": "^2.0.0-beta.21",
|
||||
"@vue-a11y/announcer": "^2.1.0",
|
||||
"@vue-a11y/skip-to": "^2.1.2",
|
||||
"@vue/apollo-option": "4.0.0-alpha.11",
|
||||
"apollo-absinthe-upload-link": "^1.5.0",
|
||||
"autoprefixer": "^10",
|
||||
"blurhash": "^1.1.3",
|
||||
"buefy": "^0.9.0",
|
||||
"bulma-divider": "^0.2.0",
|
||||
@ -44,20 +56,24 @@
|
||||
"intersection-observer": "^0.12.0",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"leaflet": "^1.4.0",
|
||||
"leaflet.locatecontrol": "^0.74.0",
|
||||
"leaflet.locatecontrol": "^0.76.0",
|
||||
"lodash": "^4.17.11",
|
||||
"ngeohash": "^0.6.3",
|
||||
"p-debounce": "^4.0.0",
|
||||
"phoenix": "^1.6",
|
||||
"postcss": "^8",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"sanitize-html": "^2.5.3",
|
||||
"tailwindcss": "^3",
|
||||
"tippy.js": "^6.2.3",
|
||||
"unfetch": "^4.2.0",
|
||||
"v-tooltip": "^2.1.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-class-component": "^7.2.3",
|
||||
"vue-i18n": "^8.14.0",
|
||||
"vue-matomo": "^4.1.0",
|
||||
"vue-meta": "^2.3.1",
|
||||
"vue-plausible": "^1.3.1",
|
||||
"vue-property-decorator": "^9.0.0",
|
||||
"vue-router": "^3.1.6",
|
||||
"vue-scrollto": "^2.17.1",
|
||||
@ -65,9 +81,10 @@
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.1.0",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/leaflet": "^1.5.2",
|
||||
"@types/leaflet.locatecontrol": "^0.60.7",
|
||||
"@types/leaflet.locatecontrol": "^0.74",
|
||||
"@types/lodash": "^4.14.141",
|
||||
"@types/ngeohash": "^0.6.2",
|
||||
"@types/phoenix": "^1.5.2",
|
||||
@ -78,22 +95,19 @@
|
||||
"@types/sanitize-html": "^2.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||
"@typescript-eslint/parser": "^5.3.0",
|
||||
"@vue/cli-plugin-babel": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-pwa": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-router": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-typescript": "~5.0.0-rc.0",
|
||||
"@vue/cli-plugin-unit-jest": "~5.0.0-rc.0",
|
||||
"@vue/cli-service": "~5.0.0-rc.0",
|
||||
"@vue/eslint-config-typescript": "^9.0.0",
|
||||
"@vue/cli-plugin-babel": "~5.0.4",
|
||||
"@vue/cli-plugin-eslint": "~5.0.4",
|
||||
"@vue/cli-plugin-pwa": "~5.0.4",
|
||||
"@vue/cli-plugin-router": "~5.0.4",
|
||||
"@vue/cli-plugin-typescript": "~5.0.4",
|
||||
"@vue/cli-plugin-unit-jest": "~5.0.4",
|
||||
"@vue/cli-service": "~5.0.4",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"@vue/test-utils": "^1.1.0",
|
||||
"@vue/vue2-jest": "^27.0.0-alpha.3",
|
||||
"@vue/vue3-jest": "^27.0.0-alpha.1",
|
||||
"cypress": "^8.3.0",
|
||||
"eslint": "^8.2.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
@ -102,11 +116,12 @@
|
||||
"jest-junit": "^13.0.0",
|
||||
"mock-apollo-client": "^1.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"prettier-eslint": "^13.0.0",
|
||||
"prettier-eslint": "^14.0.0",
|
||||
"sass": "^1.34.1",
|
||||
"sass-loader": "^12.0.0",
|
||||
"ts-jest": "27",
|
||||
"typescript": "~4.4.3",
|
||||
"typescript": "~4.5.5",
|
||||
"vue-cli-plugin-tailwind": "~3.0.0",
|
||||
"vue-i18n-extract": "^2.0.4",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack-cli": "^4.7.0"
|
||||
|
6
js/postcss.config.js
Normal file
6
js/postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
@ -203,6 +203,16 @@ export default class App extends Vue {
|
||||
this.interval = undefined;
|
||||
}
|
||||
|
||||
@Watch("config")
|
||||
async initializeStatistics(config: IConfig) {
|
||||
if (config) {
|
||||
const { statistics } = (await import("./services/statistics")) as {
|
||||
statistics: (config: IConfig, environment: Record<string, any>) => void;
|
||||
};
|
||||
statistics(config, { router: this.$router, version: config.version });
|
||||
}
|
||||
}
|
||||
|
||||
@Watch("$route", { immediate: true })
|
||||
updateAnnouncement(route: Route): void {
|
||||
const pageTitle = this.extractPageTitleFromRoute(route);
|
||||
@ -216,8 +226,12 @@ export default class App extends Vue {
|
||||
// Set the focus to the router view
|
||||
// https://marcus.io/blog/accessible-routing-vuejs
|
||||
setTimeout(() => {
|
||||
const focusTarget = this.routerView?.$el as HTMLElement;
|
||||
if (focusTarget) {
|
||||
const focusTarget = (
|
||||
this.routerView?.$refs?.componentFocusTarget !== undefined
|
||||
? this.routerView?.$refs?.componentFocusTarget
|
||||
: this.routerView?.$el
|
||||
) as HTMLElement;
|
||||
if (focusTarget && focusTarget instanceof Element) {
|
||||
// Make focustarget programmatically focussable
|
||||
focusTarget.setAttribute("tabindex", "-1");
|
||||
|
||||
|
@ -70,6 +70,9 @@ export const typePolicies: TypePolicies = {
|
||||
participantStats: { merge: replaceMergePolicy },
|
||||
},
|
||||
},
|
||||
Instance: {
|
||||
keyFields: ["domain"],
|
||||
},
|
||||
RootQueryType: {
|
||||
fields: {
|
||||
relayFollowers: paginatedLimitPagination<IFollower>(),
|
||||
|
9
js/src/assets/logo.svg
Normal file
9
js/src/assets/logo.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60">
|
||||
<path style="opacity:0;fill:#fea72b;fill-opacity:1;stroke:none;stroke-opacity:0" d="M-5.801-6.164h72.69v72.871h-72.69z" />
|
||||
<g data-name="Calque 2">
|
||||
<g data-name="header">
|
||||
<path d="M26.58 27.06q0 8-4.26 12.3a12.21 12.21 0 0 1-9 3.42 12.21 12.21 0 0 1-9-3.42Q0 35.1 0 27.06q0-8.04 4.26-12.3a12.21 12.21 0 0 1 9-3.42 12.21 12.21 0 0 1 9 3.42q4.32 4.24 4.32 12.3zM13.29 17q-5.67 0-5.67 10.06t5.67 10.08q5.71 0 5.71-10.08T13.29 17z" style="fill:#3a384c;fill-opacity:1" transform="translate(14.627 5.256) scale(1.15671)" />
|
||||
<path d="M9 6.78a7.37 7.37 0 0 1-.6-3 7.37 7.37 0 0 1 .6-3A8.09 8.09 0 0 1 12.83 0a7.05 7.05 0 0 1 3.69.84 7.37 7.37 0 0 1 .6 3 7.37 7.37 0 0 1-.6 3 7.46 7.46 0 0 1-3.87.84A6.49 6.49 0 0 1 9 6.78z" style="fill:#fff" transform="translate(14.627 5.256) scale(1.15671)" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 920 B |
5
js/src/assets/tailwind.css
Normal file
5
js/src/assets/tailwind.css
Normal file
@ -0,0 +1,5 @@
|
||||
@tailwind base;
|
||||
|
||||
@tailwind components;
|
||||
|
||||
@tailwind utilities;
|
@ -7,72 +7,18 @@
|
||||
@import "styles/vue-announcer.scss";
|
||||
@import "styles/vue-skip-to.scss";
|
||||
|
||||
// a {
|
||||
// color: $violet-2;
|
||||
// }
|
||||
|
||||
.title {
|
||||
margin: 30px auto 45px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
background: $secondary;
|
||||
display: inline;
|
||||
padding: 3px 8px;
|
||||
margin: 15px auto 30px;
|
||||
}
|
||||
|
||||
a.out,
|
||||
.content a,
|
||||
.ProseMirror a {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: $secondary;
|
||||
text-decoration-color: #ed8d07;
|
||||
text-decoration-thickness: 2px;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
main {
|
||||
|
||||
> section > .columns {
|
||||
min-height: 50vh;
|
||||
}
|
||||
> section {
|
||||
&.container {
|
||||
min-height: 80vh;
|
||||
}
|
||||
}
|
||||
> .container {
|
||||
background: $whitest;
|
||||
min-height: 70vh;
|
||||
}
|
||||
> #homepage {
|
||||
background: $whitest;
|
||||
#featured_events {
|
||||
background: $whitest;
|
||||
}
|
||||
#picture {
|
||||
.container,
|
||||
.section {
|
||||
background: $whitest;
|
||||
}
|
||||
}
|
||||
> .container {
|
||||
min-height: 25vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 1rem 1% 4rem;
|
||||
}
|
||||
|
||||
figure img.is-rounded {
|
||||
border: 1px solid $chapril_blue;
|
||||
}
|
||||
|
||||
$color-black: #000;
|
||||
|
||||
.mention {
|
||||
@ -115,16 +61,11 @@ body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#mobilizon {
|
||||
> main {
|
||||
background: $body-background-color;
|
||||
}
|
||||
> .container > .message {
|
||||
margin: 1rem auto auto;
|
||||
.message-header {
|
||||
button.delete {
|
||||
background: $chapril_grey;
|
||||
}
|
||||
#mobilizon > .container > .message {
|
||||
margin: 1rem auto auto;
|
||||
.message-header {
|
||||
button.delete {
|
||||
background: #4a4a4a;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,7 +82,7 @@ $list-radius: $radius !default;
|
||||
|
||||
$list-item-border: 1px solid $border !default;
|
||||
$list-item-color: $text !default;
|
||||
$list-item-active-background-color: $purple-1 !default;
|
||||
$list-item-active-background-color: $link !default;
|
||||
$list-item-active-color: $link-invert !default;
|
||||
$list-item-hover-background-color: $background !default;
|
||||
|
||||
@ -176,74 +117,16 @@ a.list-item {
|
||||
.setting-title {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
background: $secondary;
|
||||
color: $white;
|
||||
span {
|
||||
background: $secondary !important;
|
||||
color: $white !important;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
display: inline;
|
||||
|
||||
background: $secondary;
|
||||
padding: 2px 7.5px;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-body {
|
||||
background-color: $chapril_blue_light;
|
||||
}
|
||||
|
||||
.columns {
|
||||
background: $whitest;
|
||||
}
|
||||
.setting-menu-item {
|
||||
background-color: $yellow-4;
|
||||
|
||||
.router-link-active,
|
||||
.router-link-active {
|
||||
background-color: $info;
|
||||
color: $white;
|
||||
|
||||
a {
|
||||
color: $white;
|
||||
font-weight: 600 !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date-component-container {
|
||||
.datetime-container {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.time.datetime-container {
|
||||
color: $white;
|
||||
background: $chapril_blue_light;
|
||||
span.month {
|
||||
color: $whitest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
footer
|
||||
|
||||
*/
|
||||
footer.footer[data-v-40ab164b] span.select select {
|
||||
background: $chapril_blue_light;
|
||||
color: $footer-text-color;
|
||||
}
|
||||
|
||||
@mixin focus() {
|
||||
&:focus {
|
||||
border: 2px solid black;
|
||||
|
@ -1,118 +0,0 @@
|
||||
<template>
|
||||
<b-autocomplete
|
||||
:data="baseData"
|
||||
:placeholder="$t('Actor')"
|
||||
v-model="name"
|
||||
field="preferredUsername"
|
||||
:loading="$apollo.loading"
|
||||
check-infinite-scroll
|
||||
@typing="getAsyncData"
|
||||
@select="handleSelect"
|
||||
@infinite-scroll="getAsyncData"
|
||||
>
|
||||
<template #default="props">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img
|
||||
width="32"
|
||||
:src="props.option.avatar.url"
|
||||
v-if="props.option.avatar"
|
||||
alt=""
|
||||
/>
|
||||
<b-icon v-else icon="account-circle" />
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<span v-if="props.option.name">
|
||||
{{ props.option.name }}
|
||||
<br />
|
||||
<small>{{ `@${props.option.preferredUsername}` }}</small>
|
||||
<small v-if="props.option.domain">{{
|
||||
`@${props.option.domain}`
|
||||
}}</small>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ `@${props.option.preferredUsername}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="footer">
|
||||
<span class="has-text-grey" v-show="page > totalPages">
|
||||
Thats it! No more movies found.
|
||||
</span>
|
||||
</template>
|
||||
</b-autocomplete>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Model, Vue, Watch } from "vue-property-decorator";
|
||||
import debounce from "lodash/debounce";
|
||||
import { IPerson } from "@/types/actor";
|
||||
import { SEARCH_PERSONS } from "@/graphql/search";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
|
||||
const SEARCH_PERSON_LIMIT = 10;
|
||||
|
||||
@Component
|
||||
export default class ActorAutoComplete extends Vue {
|
||||
@Model("change", { type: Object }) readonly defaultSelected!: IPerson | null;
|
||||
|
||||
baseData: IPerson[] = [];
|
||||
|
||||
selected: IPerson | null = this.defaultSelected;
|
||||
|
||||
name: string = this.defaultSelected
|
||||
? this.defaultSelected.preferredUsername
|
||||
: "";
|
||||
|
||||
page = 1;
|
||||
|
||||
totalPages = 1;
|
||||
|
||||
mounted(): void {
|
||||
this.selected = this.defaultSelected;
|
||||
}
|
||||
|
||||
data(): Record<string, unknown> {
|
||||
return {
|
||||
getAsyncData: debounce(this.doGetAsyncData, 500),
|
||||
};
|
||||
}
|
||||
|
||||
@Watch("defaultSelected")
|
||||
updateDefaultSelected(defaultSelected: IPerson): void {
|
||||
console.log("update defaultSelected", defaultSelected);
|
||||
this.selected = defaultSelected;
|
||||
this.name = defaultSelected.preferredUsername;
|
||||
}
|
||||
|
||||
handleSelect(selected: IPerson): void {
|
||||
this.selected = selected;
|
||||
this.$emit("change", selected);
|
||||
}
|
||||
|
||||
async doGetAsyncData(name: string): Promise<void> {
|
||||
this.baseData = [];
|
||||
if (this.name !== name) {
|
||||
this.name = name;
|
||||
this.page = 1;
|
||||
}
|
||||
if (!name.length) {
|
||||
this.page = 1;
|
||||
this.totalPages = 1;
|
||||
return;
|
||||
}
|
||||
const {
|
||||
data: { searchPersons },
|
||||
} = await this.$apollo.query<{ searchPersons: Paginate<IPerson> }>({
|
||||
query: SEARCH_PERSONS,
|
||||
variables: {
|
||||
searchText: this.name,
|
||||
page: this.page,
|
||||
limit: SEARCH_PERSON_LIMIT,
|
||||
},
|
||||
});
|
||||
this.totalPages = Math.ceil(searchPersons.total / SEARCH_PERSON_LIMIT);
|
||||
this.baseData.push(...searchPersons.elements);
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,31 +1,86 @@
|
||||
<template>
|
||||
<div class="media" style="align-items: top" dir="auto">
|
||||
<div class="media-left">
|
||||
<figure class="image is-32x32" v-if="actor.avatar">
|
||||
<img class="is-rounded" :src="actor.avatar.url" alt="" />
|
||||
<div
|
||||
class="bg-white rounded-lg flex space-x-4 items-center"
|
||||
:class="{ 'flex-col p-4 shadow-md sm:p-8 pb-10 w-80': !inline }"
|
||||
>
|
||||
<div>
|
||||
<figure class="w-12 h-12" v-if="actor.avatar">
|
||||
<img
|
||||
class="rounded-lg"
|
||||
:src="actor.avatar.url"
|
||||
alt=""
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
</figure>
|
||||
<b-icon v-else size="is-medium" icon="account-circle" />
|
||||
<b-icon
|
||||
v-else
|
||||
:size="inline ? 'is-medium' : 'is-large'"
|
||||
icon="account-circle"
|
||||
class="ltr:-mr-0.5 rtl:-ml-0.5"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="media-content">
|
||||
<p>
|
||||
{{ actor.name || `@${usernameWithDomain(actor)}` }}
|
||||
</p>
|
||||
<p class="has-text-grey-dark" v-if="actor.name">
|
||||
<div :class="{ 'text-center': !inline }" class="overflow-hidden w-full">
|
||||
<h5
|
||||
class="text-xl font-medium violet-title tracking-tight text-gray-900 whitespace-pre-line line-clamp-2"
|
||||
>
|
||||
{{ displayName(actor) }}
|
||||
</h5>
|
||||
<p class="text-gray-500 truncate" v-if="actor.name">
|
||||
<span dir="ltr">@{{ usernameWithDomain(actor) }}</span>
|
||||
</p>
|
||||
<div
|
||||
v-if="full"
|
||||
class="summary"
|
||||
:class="{ limit: limit }"
|
||||
class="only-first-child"
|
||||
:class="{
|
||||
'line-clamp-3': limit,
|
||||
'line-clamp-10': !limit,
|
||||
}"
|
||||
v-html="actor.summary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="p-4 bg-white rounded-lg shadow-md sm:p-8 flex items-center space-x-4"
|
||||
dir="auto"
|
||||
>
|
||||
<div class="flex-shrink-0">
|
||||
<figure class="w-12 h-12" v-if="actor.avatar">
|
||||
<img
|
||||
class="rounded-lg"
|
||||
:src="actor.avatar.url"
|
||||
alt=""
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
</figure>
|
||||
<b-icon
|
||||
v-else
|
||||
size="is-large"
|
||||
icon="account-circle"
|
||||
class="ltr:-mr-0.5 rtl:-ml-0.5"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<h5 class="text-xl font-medium violet-title tracking-tight text-gray-900">
|
||||
{{ displayName(actor) }}
|
||||
</h5>
|
||||
<p class="text-gray-500 truncate" v-if="actor.name">
|
||||
<span dir="ltr">@{{ usernameWithDomain(actor) }}</span>
|
||||
</p>
|
||||
<div
|
||||
v-if="full"
|
||||
class="line-clamp-3"
|
||||
:class="{ limit: limit }"
|
||||
v-html="actor.summary"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import { IActor, usernameWithDomain } from "../../types/actor";
|
||||
import { displayName, IActor, usernameWithDomain } from "../../types/actor";
|
||||
|
||||
@Component
|
||||
export default class ActorCard extends Vue {
|
||||
@ -33,140 +88,19 @@ export default class ActorCard extends Vue {
|
||||
|
||||
@Prop({ required: false, type: Boolean, default: false }) full!: boolean;
|
||||
|
||||
@Prop({ required: false, type: Boolean, default: false }) inline!: boolean;
|
||||
|
||||
@Prop({ required: false, type: Boolean, default: false }) popover!: boolean;
|
||||
|
||||
@Prop({ required: false, type: Boolean, default: true }) limit!: boolean;
|
||||
|
||||
usernameWithDomain = usernameWithDomain;
|
||||
|
||||
displayName = displayName;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.summary.limit {
|
||||
max-width: 25rem;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/_mixins" as *;
|
||||
|
||||
.media {
|
||||
.media-left {
|
||||
margin-right: initial;
|
||||
@include margin-right(1rem);
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
display: block !important;
|
||||
z-index: 10000;
|
||||
|
||||
.tooltip-inner {
|
||||
background: black;
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
padding: 5px 10px 4px;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
border-color: black;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
margin-top: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
@include margin-left(5px);
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
@include margin-left(0);
|
||||
@include margin-right(0);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
@include margin-right(5px);
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
@include margin-left(0);
|
||||
@include margin-right(0);
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
$color: #f9f9f9;
|
||||
|
||||
.popover-inner {
|
||||
background: lighten($background-color, 65%);
|
||||
color: black;
|
||||
padding: 24px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 5px 30px rgba(black, 0.1);
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
border-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s, visibility 0.15s;
|
||||
}
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
<style scoped>
|
||||
.only-first-child ::v-deep :not(:first-child) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,28 +1,33 @@
|
||||
<template>
|
||||
<div class="actor-inline">
|
||||
<div class="actor-avatar">
|
||||
<figure class="image is-24x24" v-if="actor.avatar">
|
||||
<div class="inline-flex items-start">
|
||||
<div class="flex-none mr-2">
|
||||
<figure class="image is-48x48" v-if="actor.avatar">
|
||||
<img class="is-rounded" :src="actor.avatar.url" alt="" />
|
||||
</figure>
|
||||
<b-icon v-else size="is-medium" icon="account-circle" />
|
||||
<b-icon v-else size="is-large" icon="account-circle" />
|
||||
</div>
|
||||
|
||||
<div class="actor-name">
|
||||
<p>
|
||||
{{ actor.name || `@${usernameWithDomain(actor)}` }}
|
||||
<div class="flex-auto">
|
||||
<p class="text-base line-clamp-3 md:line-clamp-2 max-w-xl">
|
||||
{{ displayName(actor) }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 truncate">
|
||||
@{{ usernameWithDomain(actor) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import { IActor, usernameWithDomain } from "../../types/actor";
|
||||
import { displayName, IActor, usernameWithDomain } from "../../types/actor";
|
||||
|
||||
@Component
|
||||
export default class ActorInline extends Vue {
|
||||
@Prop({ required: true, type: Object }) actor!: IActor;
|
||||
|
||||
usernameWithDomain = usernameWithDomain;
|
||||
|
||||
displayName = displayName;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="ellipsis"
|
||||
class="truncate"
|
||||
:title="
|
||||
isDescriptionDifferentFromLocality
|
||||
? `${physicalAddress.description}, ${physicalAddress.locality}`
|
||||
@ -8,8 +8,7 @@
|
||||
"
|
||||
>
|
||||
<b-icon icon="map-marker" />
|
||||
<span v-if="isDescriptionDifferentFromLocality">
|
||||
{{ physicalAddress.description }},
|
||||
<span v-if="physicalAddress.locality">
|
||||
{{ physicalAddress.locality }}
|
||||
</span>
|
||||
<span v-else>
|
||||
@ -35,11 +34,3 @@ export default class InlineAddress extends Vue {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,262 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-table
|
||||
v-show="relayFollowers.elements.length > 0"
|
||||
:data="relayFollowers.elements"
|
||||
:loading="$apollo.queries.relayFollowers.loading"
|
||||
ref="table"
|
||||
:checked-rows.sync="checkedRows"
|
||||
detailed
|
||||
:show-detail-icon="false"
|
||||
paginated
|
||||
backend-pagination
|
||||
:current-page.sync="page"
|
||||
:aria-next-label="$t('Next page')"
|
||||
:aria-previous-label="$t('Previous page')"
|
||||
:aria-page-label="$t('Page')"
|
||||
:aria-current-label="$t('Current page')"
|
||||
:total="relayFollowers.total"
|
||||
:per-page="FOLLOWERS_PER_PAGE"
|
||||
@page-change="onFollowersPageChange"
|
||||
checkable
|
||||
checkbox-position="left"
|
||||
>
|
||||
<b-table-column
|
||||
field="actor.id"
|
||||
label="ID"
|
||||
width="40"
|
||||
numeric
|
||||
v-slot="props"
|
||||
>{{ props.row.actor.id }}</b-table-column
|
||||
>
|
||||
|
||||
<b-table-column
|
||||
field="actor.type"
|
||||
:label="$t('Type')"
|
||||
width="80"
|
||||
v-slot="props"
|
||||
>
|
||||
<b-icon icon="lan" v-if="RelayMixin.isInstance(props.row.actor)" />
|
||||
<b-icon icon="account-circle" v-else />
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column
|
||||
field="approved"
|
||||
:label="$t('Status')"
|
||||
width="100"
|
||||
sortable
|
||||
centered
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`"
|
||||
>{{ props.row.approved ? $t("Accepted") : $t("Pending") }}</span
|
||||
>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="actor.domain" :label="$t('Domain')" sortable>
|
||||
<template v-slot:default="props">
|
||||
<a
|
||||
@click="toggle(props.row)"
|
||||
v-if="RelayMixin.isInstance(props.row.actor)"
|
||||
>{{ props.row.actor.domain }}</a
|
||||
>
|
||||
<a @click="toggle(props.row)" v-else>{{
|
||||
`${props.row.actor.preferredUsername}@${props.row.actor.domain}`
|
||||
}}</a>
|
||||
</template>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column
|
||||
field="targetActor.updatedAt"
|
||||
:label="$t('Date')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:title="$options.filters.formatDateTimeString(props.row.updatedAt)"
|
||||
>{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), {
|
||||
locale: $dateFnsLocale,
|
||||
})
|
||||
}}</span
|
||||
></b-table-column
|
||||
>
|
||||
|
||||
<template #detail="props">
|
||||
<article>
|
||||
<div class="content">
|
||||
<strong>{{ props.row.actor.name }}</strong>
|
||||
<small v-if="props.row.actor.preferredUsername !== 'relay'"
|
||||
>@{{ props.row.actor.preferredUsername }}</small
|
||||
>
|
||||
<p v-html="props.row.actor.summary" />
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<template slot="bottom-left" v-if="checkedRows.length > 0">
|
||||
<div class="buttons">
|
||||
<b-button
|
||||
@click="acceptRelays"
|
||||
type="is-success"
|
||||
v-if="checkedRowsHaveAtLeastOneToApprove"
|
||||
>
|
||||
{{
|
||||
$tc(
|
||||
"No instance to approve|Approve instance|Approve {number} instances",
|
||||
checkedRows.length,
|
||||
{ number: checkedRows.length }
|
||||
)
|
||||
}}
|
||||
</b-button>
|
||||
<b-button @click="rejectRelays" type="is-danger">
|
||||
{{
|
||||
$tc(
|
||||
"No instance to reject|Reject instance|Reject {number} instances",
|
||||
checkedRows.length,
|
||||
{ number: checkedRows.length }
|
||||
)
|
||||
}}
|
||||
</b-button>
|
||||
</div>
|
||||
</template>
|
||||
</b-table>
|
||||
<b-message type="is-danger" v-if="relayFollowers.elements.length === 0">{{
|
||||
$t("No instance follows your instance yet.")
|
||||
}}</b-message>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Mixins } from "vue-property-decorator";
|
||||
import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import {
|
||||
ACCEPT_RELAY,
|
||||
REJECT_RELAY,
|
||||
RELAY_FOLLOWERS,
|
||||
} from "../../graphql/admin";
|
||||
import { IFollower } from "../../types/actor/follower.model";
|
||||
import RelayMixin from "../../mixins/relay";
|
||||
import RouteName from "@/router/name";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
|
||||
const FOLLOWERS_PER_PAGE = 10;
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
relayFollowers: {
|
||||
query: RELAY_FOLLOWERS,
|
||||
variables() {
|
||||
return {
|
||||
page: this.page,
|
||||
limit: FOLLOWERS_PER_PAGE,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Followers") as string,
|
||||
titleTemplate: "%s | Mobilizon",
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Followers extends Mixins(RelayMixin) {
|
||||
RelayMixin = RelayMixin;
|
||||
|
||||
formatDistanceToNow = formatDistanceToNow;
|
||||
|
||||
relayFollowers: Paginate<IFollower> = { elements: [], total: 0 };
|
||||
|
||||
checkedRows: IFollower[] = [];
|
||||
|
||||
FOLLOWERS_PER_PAGE = FOLLOWERS_PER_PAGE;
|
||||
|
||||
toggle(row: Record<string, unknown>): void {
|
||||
this.table.toggleDetails(row);
|
||||
}
|
||||
|
||||
get page(): number {
|
||||
return parseInt((this.$route.query.page as string) || "1", 10);
|
||||
}
|
||||
|
||||
set page(page: number) {
|
||||
this.pushRouter(RouteName.RELAY_FOLLOWERS, {
|
||||
page: page.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
acceptRelays(): void {
|
||||
this.checkedRows.forEach((row: IFollower) => {
|
||||
this.acceptRelay(`${row.actor.preferredUsername}@${row.actor.domain}`);
|
||||
});
|
||||
}
|
||||
|
||||
rejectRelays(): void {
|
||||
this.checkedRows.forEach((row: IFollower) => {
|
||||
this.rejectRelay(`${row.actor.preferredUsername}@${row.actor.domain}`);
|
||||
});
|
||||
}
|
||||
|
||||
async acceptRelay(address: string): Promise<void> {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: ACCEPT_RELAY,
|
||||
variables: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
await this.$apollo.queries.relayFollowers.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e: any) {
|
||||
if (e.message) {
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async rejectRelay(address: string): Promise<void> {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: REJECT_RELAY,
|
||||
variables: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
await this.$apollo.queries.relayFollowers.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e: any) {
|
||||
if (e.message) {
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get checkedRowsHaveAtLeastOneToApprove(): boolean {
|
||||
return this.checkedRows.some((checkedRow) => !checkedRow.approved);
|
||||
}
|
||||
|
||||
async onFollowersPageChange(page: number): Promise<void> {
|
||||
this.page = page;
|
||||
try {
|
||||
await this.$apollo.queries.relayFollowers.fetchMore({
|
||||
variables: {
|
||||
page: this.page,
|
||||
limit: FOLLOWERS_PER_PAGE,
|
||||
},
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,311 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<form @submit="followRelay">
|
||||
<b-field
|
||||
:label="$t('Add an instance')"
|
||||
custom-class="add-relay"
|
||||
horizontal
|
||||
>
|
||||
<b-field grouped expanded size="is-large">
|
||||
<p class="control">
|
||||
<b-input
|
||||
v-model="newRelayAddress"
|
||||
:placeholder="$t('Ex: mobilizon.fr')"
|
||||
/>
|
||||
</p>
|
||||
<p class="control">
|
||||
<b-button type="is-primary" native-type="submit">{{
|
||||
$t("Add an instance")
|
||||
}}</b-button>
|
||||
</p>
|
||||
</b-field>
|
||||
</b-field>
|
||||
</form>
|
||||
<b-table
|
||||
v-show="relayFollowings.elements.length > 0"
|
||||
:data="relayFollowings.elements"
|
||||
:loading="$apollo.queries.relayFollowings.loading"
|
||||
ref="table"
|
||||
:checked-rows.sync="checkedRows"
|
||||
:is-row-checkable="(row) => row.id !== 3"
|
||||
detailed
|
||||
:show-detail-icon="false"
|
||||
paginated
|
||||
backend-pagination
|
||||
:current-page.sync="page"
|
||||
:aria-next-label="$t('Next page')"
|
||||
:aria-previous-label="$t('Previous page')"
|
||||
:aria-page-label="$t('Page')"
|
||||
:aria-current-label="$t('Current page')"
|
||||
:total="relayFollowings.total"
|
||||
:per-page="FOLLOWINGS_PER_PAGE"
|
||||
@page-change="onFollowingsPageChange"
|
||||
checkable
|
||||
checkbox-position="left"
|
||||
>
|
||||
<b-table-column
|
||||
field="targetActor.id"
|
||||
label="ID"
|
||||
width="40"
|
||||
numeric
|
||||
v-slot="props"
|
||||
>{{ props.row.targetActor.id }}</b-table-column
|
||||
>
|
||||
|
||||
<b-table-column
|
||||
field="targetActor.type"
|
||||
:label="$t('Type')"
|
||||
width="80"
|
||||
v-slot="props"
|
||||
>
|
||||
<b-icon
|
||||
icon="lan"
|
||||
v-if="RelayMixin.isInstance(props.row.targetActor)"
|
||||
/>
|
||||
<b-icon icon="account-circle" v-else />
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column
|
||||
field="approved"
|
||||
:label="$t('Status')"
|
||||
width="100"
|
||||
sortable
|
||||
centered
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`"
|
||||
>{{ props.row.approved ? $t("Accepted") : $t("Pending") }}</span
|
||||
>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="targetActor.domain" :label="$t('Domain')" sortable>
|
||||
<template v-slot:default="props">
|
||||
<a
|
||||
@click="toggle(props.row)"
|
||||
v-if="RelayMixin.isInstance(props.row.targetActor)"
|
||||
>{{ props.row.targetActor.domain }}</a
|
||||
>
|
||||
<a @click="toggle(props.row)" v-else>{{
|
||||
`${props.row.targetActor.preferredUsername}@${props.row.targetActor.domain}`
|
||||
}}</a>
|
||||
</template>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column
|
||||
field="targetActor.updatedAt"
|
||||
:label="$t('Date')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:title="$options.filters.formatDateTimeString(props.row.updatedAt)"
|
||||
>{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), {
|
||||
locale: $dateFnsLocale,
|
||||
})
|
||||
}}</span
|
||||
></b-table-column
|
||||
>
|
||||
|
||||
<template #detail="props">
|
||||
<article>
|
||||
<div class="content">
|
||||
<strong>{{ props.row.targetActor.name }}</strong>
|
||||
<small v-if="props.row.actor.preferredUsername !== 'relay'"
|
||||
>@{{ props.row.targetActor.preferredUsername }}</small
|
||||
>
|
||||
<p v-html="props.row.targetActor.summary" />
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<template slot="bottom-left" v-if="checkedRows.length > 0">
|
||||
<b-button @click="removeRelays" type="is-danger">
|
||||
{{
|
||||
$tc(
|
||||
"No instance to remove|Remove instance|Remove {number} instances",
|
||||
checkedRows.length,
|
||||
{ number: checkedRows.length }
|
||||
)
|
||||
}}
|
||||
</b-button>
|
||||
</template>
|
||||
</b-table>
|
||||
<b-message type="is-danger" v-if="relayFollowings.total === 0">{{
|
||||
$t("You don't follow any instances yet.")
|
||||
}}</b-message>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Mixins } from "vue-property-decorator";
|
||||
import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { ADD_RELAY, REMOVE_RELAY } from "../../graphql/admin";
|
||||
import { IFollower } from "../../types/actor/follower.model";
|
||||
import RelayMixin from "../../mixins/relay";
|
||||
import { RELAY_FOLLOWINGS } from "@/graphql/admin";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
import RouteName from "@/router/name";
|
||||
import { ApolloCache, FetchResult, Reference } from "@apollo/client/core";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
const FOLLOWINGS_PER_PAGE = 10;
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
relayFollowings: {
|
||||
query: RELAY_FOLLOWINGS,
|
||||
variables() {
|
||||
return {
|
||||
page: this.page,
|
||||
limit: FOLLOWINGS_PER_PAGE,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Followings") as string,
|
||||
titleTemplate: "%s | Mobilizon",
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Followings extends Mixins(RelayMixin) {
|
||||
newRelayAddress = "";
|
||||
|
||||
RelayMixin = RelayMixin;
|
||||
|
||||
formatDistanceToNow = formatDistanceToNow;
|
||||
|
||||
relayFollowings: Paginate<IFollower> = { elements: [], total: 0 };
|
||||
|
||||
FOLLOWINGS_PER_PAGE = FOLLOWINGS_PER_PAGE;
|
||||
|
||||
checkedRows: IFollower[] = [];
|
||||
|
||||
get page(): number {
|
||||
return parseInt((this.$route.query.page as string) || "1", 10);
|
||||
}
|
||||
|
||||
set page(page: number) {
|
||||
this.pushRouter(RouteName.RELAY_FOLLOWINGS, {
|
||||
page: page.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
async onFollowingsPageChange(page: number): Promise<void> {
|
||||
this.page = page;
|
||||
try {
|
||||
await this.$apollo.queries.relayFollowings.fetchMore({
|
||||
variables: {
|
||||
page: this.page,
|
||||
limit: FOLLOWINGS_PER_PAGE,
|
||||
},
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
async followRelay(e: Event): Promise<void> {
|
||||
e.preventDefault();
|
||||
try {
|
||||
await this.$apollo.mutate<{ relayFollowings: Paginate<IFollower> }>({
|
||||
mutation: ADD_RELAY,
|
||||
variables: {
|
||||
address: this.newRelayAddress.trim(), // trim to fix copy and paste domain name spaces and tabs
|
||||
},
|
||||
update(
|
||||
cache: ApolloCache<{ relayFollowings: Paginate<IFollower> }>,
|
||||
{ data }: FetchResult
|
||||
) {
|
||||
cache.modify({
|
||||
fields: {
|
||||
relayFollowings(
|
||||
existingFollowings = { elements: [], total: 0 },
|
||||
{ readField }
|
||||
) {
|
||||
const newFollowingRef = cache.writeFragment({
|
||||
id: `${data?.addRelay.__typename}:${data?.addRelay.id}`,
|
||||
data: data?.addRelay,
|
||||
fragment: gql`
|
||||
fragment NewFollowing on Follower {
|
||||
id
|
||||
}
|
||||
`,
|
||||
});
|
||||
if (
|
||||
existingFollowings.elements.some(
|
||||
(ref: Reference) =>
|
||||
readField("id", ref) === data?.addRelay.id
|
||||
)
|
||||
) {
|
||||
return existingFollowings;
|
||||
}
|
||||
return {
|
||||
total: existingFollowings.total + 1,
|
||||
elements: [newFollowingRef, ...existingFollowings.elements],
|
||||
};
|
||||
},
|
||||
},
|
||||
broadcast: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
this.newRelayAddress = "";
|
||||
} catch (err: any) {
|
||||
if (err.message) {
|
||||
Snackbar.open({
|
||||
message: err.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeRelays(): void {
|
||||
this.checkedRows.forEach((row: IFollower) => {
|
||||
this.removeRelay(row);
|
||||
});
|
||||
}
|
||||
|
||||
async removeRelay(follower: IFollower): Promise<void> {
|
||||
const address = `${follower.targetActor.preferredUsername}@${follower.targetActor.domain}`;
|
||||
try {
|
||||
await this.$apollo.mutate<{ removeRelay: IFollower }>({
|
||||
mutation: REMOVE_RELAY,
|
||||
variables: {
|
||||
address,
|
||||
},
|
||||
update(cache: ApolloCache<{ removeRelay: IFollower }>) {
|
||||
cache.modify({
|
||||
fields: {
|
||||
relayFollowings(existingFollowingRefs, { readField }) {
|
||||
return {
|
||||
total: existingFollowingRefs.total - 1,
|
||||
elements: existingFollowingRefs.elements.filter(
|
||||
(followingRef: Reference) =>
|
||||
follower.id !== readField("id", followingRef)
|
||||
),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
await this.$apollo.queries.relayFollowings.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e: any) {
|
||||
if (e.message) {
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -195,10 +195,18 @@
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||
import { Editor, EditorContent, BubbleMenu } from "@tiptap/vue-2";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import Blockquote from "@tiptap/extension-blockquote";
|
||||
import BulletList from "@tiptap/extension-bullet-list";
|
||||
import Heading from "@tiptap/extension-heading";
|
||||
import Document from "@tiptap/extension-document";
|
||||
import Paragraph from "@tiptap/extension-paragraph";
|
||||
import Bold from "@tiptap/extension-bold";
|
||||
import Italic from "@tiptap/extension-italic";
|
||||
import Strike from "@tiptap/extension-strike";
|
||||
import Text from "@tiptap/extension-text";
|
||||
import Dropcursor from "@tiptap/extension-dropcursor";
|
||||
import Gapcursor from "@tiptap/extension-gapcursor";
|
||||
import History from "@tiptap/extension-history";
|
||||
import { IActor, IPerson, usernameWithDomain } from "../types/actor";
|
||||
import CustomImage from "./Editor/Image";
|
||||
import { UPLOAD_MEDIA } from "../graphql/upload";
|
||||
@ -210,7 +218,6 @@ import OrderedList from "@tiptap/extension-ordered-list";
|
||||
import ListItem from "@tiptap/extension-list-item";
|
||||
import Underline from "@tiptap/extension-underline";
|
||||
import Link from "@tiptap/extension-link";
|
||||
import CharacterCount from "@tiptap/extension-character-count";
|
||||
import { AutoDir } from "./Editor/Autodir";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
|
||||
@ -269,7 +276,9 @@ export default class EditorComponent extends Vue {
|
||||
transformPastedHTML: this.transformPastedHTML,
|
||||
},
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Blockquote,
|
||||
BulletList,
|
||||
Heading,
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
@ -279,12 +288,15 @@ export default class EditorComponent extends Vue {
|
||||
CustomImage,
|
||||
AutoDir,
|
||||
Underline,
|
||||
Bold,
|
||||
Italic,
|
||||
Strike,
|
||||
Dropcursor,
|
||||
Gapcursor,
|
||||
History,
|
||||
Link.configure({
|
||||
HTMLAttributes: { target: "_blank", rel: "noopener noreferrer ugc" },
|
||||
}),
|
||||
CharacterCount.configure({
|
||||
limit: this.maxSize,
|
||||
}),
|
||||
],
|
||||
injectCSS: false,
|
||||
content: this.value,
|
||||
|
@ -7,6 +7,8 @@ import apolloProvider from "@/vue-apollo";
|
||||
import { IPerson } from "@/types/actor";
|
||||
import pDebounce from "p-debounce";
|
||||
import { NormalizedCacheObject } from "@apollo/client/cache/inmemory/types";
|
||||
import { MentionOptions } from "@tiptap/extension-mention";
|
||||
import { Editor } from "@tiptap/core";
|
||||
|
||||
const client =
|
||||
apolloProvider.defaultClient as ApolloClient<NormalizedCacheObject>;
|
||||
@ -24,13 +26,21 @@ const fetchItems = async (query: string): Promise<IPerson[]> => {
|
||||
|
||||
const debouncedFetchItems = pDebounce(fetchItems, 200);
|
||||
|
||||
const mentionOptions: Partial<any> = {
|
||||
const mentionOptions: MentionOptions = {
|
||||
HTMLAttributes: {
|
||||
class: "mention",
|
||||
dir: "ltr",
|
||||
},
|
||||
renderLabel({ options, node }) {
|
||||
return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`;
|
||||
},
|
||||
suggestion: {
|
||||
items: async (query: string): Promise<IPerson[]> => {
|
||||
items: async ({
|
||||
query,
|
||||
}: {
|
||||
query: string;
|
||||
editor: Editor;
|
||||
}): Promise<IPerson[]> => {
|
||||
if (query === "") {
|
||||
return [];
|
||||
}
|
||||
@ -70,8 +80,12 @@ const mentionOptions: Partial<any> = {
|
||||
return component.ref?.onKeyDown(props);
|
||||
},
|
||||
onExit() {
|
||||
popup[0].destroy();
|
||||
component.destroy();
|
||||
if (popup && popup[0]) {
|
||||
popup[0].destroy();
|
||||
}
|
||||
if (component) {
|
||||
component.destroy();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@ -7,7 +7,7 @@
|
||||
:key="index"
|
||||
@click="selectItem(index)"
|
||||
>
|
||||
<actor-card :actor="item" />
|
||||
<actor-inline :actor="item" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@ -16,11 +16,11 @@
|
||||
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
|
||||
import { displayName, usernameWithDomain } from "@/types/actor/actor.model";
|
||||
import { IPerson } from "@/types/actor";
|
||||
import ActorCard from "../../components/Account/ActorCard.vue";
|
||||
import ActorInline from "../../components/Account/ActorInline.vue";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
ActorCard,
|
||||
ActorInline,
|
||||
},
|
||||
})
|
||||
export default class MentionList extends Vue {
|
||||
|
@ -5,10 +5,14 @@
|
||||
|
||||
.ProseMirror {
|
||||
position: relative;
|
||||
}
|
||||
.ProseMirror {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
white-space: break-spaces;
|
||||
-webkit-font-variant-ligatures: none;
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: "liga" 0; /* the above doesn't seem to work in Edge */
|
||||
|
||||
& [contenteditable="false"] {
|
||||
white-space: normal;
|
||||
@ -16,14 +20,22 @@
|
||||
& [contenteditable="false"] [contenteditable="true"] {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
pre {
|
||||
& pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
img.ProseMirror-separator {
|
||||
display: inline !important;
|
||||
border: none !important;
|
||||
margin: 0 !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
}
|
||||
.ProseMirror-gapcursor {
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
@ -40,16 +52,17 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
.ProseMirror-hideselection * {
|
||||
&::selection {
|
||||
.ProseMirror-hideselection {
|
||||
*::selection {
|
||||
background: transparent;
|
||||
}
|
||||
&::-moz-selection {
|
||||
*::-moz-selection {
|
||||
background: transparent;
|
||||
}
|
||||
caret-color: transparent;
|
||||
* {
|
||||
caret-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ProseMirror-focused .ProseMirror-gapcursor {
|
||||
display: block;
|
||||
}
|
||||
|
@ -48,13 +48,75 @@
|
||||
$t("Mobilizon")
|
||||
}}</a>
|
||||
</i18n>
|
||||
{{
|
||||
$t(
|
||||
"We improve this software thanks to your feedback. To let us know about this issue, two possibilities (both unfortunately require user account creation):"
|
||||
)
|
||||
}}
|
||||
<span v-if="sentryEnabled && sentryReady">
|
||||
{{
|
||||
$t(
|
||||
"We collect your feedback and the error information in order to improve this service."
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
<span v-else>
|
||||
{{
|
||||
$t(
|
||||
"We improve this software thanks to your feedback. To let us know about this issue, two possibilities (both unfortunately require user account creation):"
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
</p>
|
||||
<div class="content">
|
||||
<form
|
||||
v-if="sentryEnabled && sentryReady && !submittedFeedback"
|
||||
@submit.prevent="sendErrorToSentry"
|
||||
>
|
||||
<b-field :label="$t('What happened?')" label-for="what-happened">
|
||||
<b-input
|
||||
v-model="feedback"
|
||||
type="textarea"
|
||||
id="what-happened"
|
||||
:placeholder="$t(`I've clicked on X, then on Y`)"
|
||||
/>
|
||||
</b-field>
|
||||
<b-button icon-left="send" native-type="submit" type="is-primary">{{
|
||||
$t("Send feedback")
|
||||
}}</b-button>
|
||||
<p class="content">
|
||||
{{
|
||||
$t(
|
||||
"Please add as many details as possible to help identify the problem."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</form>
|
||||
<b-message type="is-danger" v-else-if="feedbackError">
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
"Sorry, we wen't able to save your feedback. Don't worry, we'll try to fix this issue anyway."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<i18n path="You may now close this page or {return_to_the_homepage}.">
|
||||
<template #return_to_the_homepage>
|
||||
<router-link :to="{ name: RouteName.HOME }">{{
|
||||
$t("return to the homepage")
|
||||
}}</router-link>
|
||||
</template>
|
||||
</i18n>
|
||||
</b-message>
|
||||
<b-message type="is-success" v-else-if="submittedFeedback">
|
||||
<p>{{ $t("Thanks a lot, your feedback was submitted!") }}</p>
|
||||
<i18n path="You may now close this page or {return_to_the_homepage}.">
|
||||
<template #return_to_the_homepage>
|
||||
<router-link :to="{ name: RouteName.HOME }">{{
|
||||
$t("return to the homepage")
|
||||
}}</router-link>
|
||||
</template>
|
||||
</i18n>
|
||||
</b-message>
|
||||
<div
|
||||
class="content"
|
||||
v-if="!(sentryEnabled && sentryReady) || submittedFeedback"
|
||||
>
|
||||
<p v-if="submittedFeedback">{{ $t("You may also:") }}</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
@ -65,7 +127,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://framagit.org/framasoft/mobilizon/-/issues/new?issuable_template=Bug"
|
||||
href="https://framagit.org/framasoft/mobilizon/-/issues/"
|
||||
target="_blank"
|
||||
>{{
|
||||
$t("Open an issue on our bug tracker (advanced users)")
|
||||
@ -74,7 +136,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p class="content">
|
||||
<p class="content" v-if="!sentryEnabled">
|
||||
{{
|
||||
$t(
|
||||
"Please add as many details as possible to help identify the problem."
|
||||
@ -89,14 +151,14 @@
|
||||
<p>{{ $t("Error stacktrace") }}</p>
|
||||
<pre>{{ error.stack }}</pre>
|
||||
</details>
|
||||
<p>
|
||||
<p v-if="!sentryEnabled">
|
||||
{{
|
||||
$t(
|
||||
"The technical details of the error can help developers solve the problem more easily. Please add them to your feedback."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<div class="buttons">
|
||||
<div class="buttons" v-if="!sentryEnabled">
|
||||
<b-tooltip
|
||||
:label="tooltipConfig.label"
|
||||
:type="tooltipConfig.type"
|
||||
@ -115,14 +177,20 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { CONTACT } from "@/graphql/config";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import { checkProviderConfig, convertConfig } from "@/services/statistics";
|
||||
import { IAnalyticsConfig, IConfig } from "@/types/config.model";
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import { LOGGED_USER } from "@/graphql/user";
|
||||
import { IUser } from "@/types/current-user.model";
|
||||
import { ISentryConfiguration } from "@/types/analytics/sentry.model";
|
||||
import { submitFeedback } from "@/services/statistics/sentry";
|
||||
import RouteName from "@/router/name";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: {
|
||||
query: CONTACT,
|
||||
},
|
||||
config: CONFIG,
|
||||
loggedUser: LOGGED_USER,
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
@ -138,7 +206,17 @@ export default class ErrorComponent extends Vue {
|
||||
|
||||
copied: "success" | "error" | false = false;
|
||||
|
||||
config!: { contact: string | null; name: string };
|
||||
config!: IConfig;
|
||||
|
||||
feedback = "";
|
||||
|
||||
submittedFeedback = false;
|
||||
|
||||
feedbackError = false;
|
||||
|
||||
loggedUser!: IUser;
|
||||
|
||||
RouteName = RouteName;
|
||||
|
||||
async copyErrorToClipboard(): Promise<void> {
|
||||
try {
|
||||
@ -193,6 +271,56 @@ export default class ErrorComponent extends Vue {
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
|
||||
get sentryEnabled(): boolean {
|
||||
return this.sentryProvider?.enabled === true;
|
||||
}
|
||||
|
||||
get sentryProvider(): IAnalyticsConfig | undefined {
|
||||
return this.config && checkProviderConfig(this.config, "sentry");
|
||||
}
|
||||
|
||||
get sentryConfig(): ISentryConfiguration | undefined {
|
||||
if (this.sentryProvider?.configuration) {
|
||||
return convertConfig(
|
||||
this.sentryProvider?.configuration
|
||||
) as ISentryConfiguration;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get sentryReady() {
|
||||
const eventId = window.sessionStorage.getItem("lastEventId");
|
||||
const dsn = this.sentryConfig?.dsn;
|
||||
const organization = this.sentryConfig?.organization;
|
||||
const project = this.sentryConfig?.project;
|
||||
const host = this.sentryConfig?.host;
|
||||
return eventId && dsn && organization && project && host;
|
||||
}
|
||||
|
||||
async sendErrorToSentry() {
|
||||
try {
|
||||
const eventId = window.sessionStorage.getItem("lastEventId");
|
||||
const dsn = this.sentryConfig?.dsn;
|
||||
const organization = this.sentryConfig?.organization;
|
||||
const project = this.sentryConfig?.project;
|
||||
const host = this.sentryConfig?.host;
|
||||
const endpoint = `https://${host}/api/0/projects/${organization}/${project}/user-feedback/`;
|
||||
if (eventId && dsn && this.sentryReady) {
|
||||
await submitFeedback(endpoint, dsn, {
|
||||
event_id: eventId,
|
||||
name:
|
||||
this.loggedUser?.defaultActor?.preferredUsername || "Unknown user",
|
||||
email: this.loggedUser?.email || "unknown@email.org",
|
||||
comments: this.feedback,
|
||||
});
|
||||
this.submittedFeedback = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.feedbackError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -67,7 +67,6 @@
|
||||
<inline-address
|
||||
dir="auto"
|
||||
v-if="event.physicalAddress"
|
||||
class="event-subtitle"
|
||||
:physical-address="event.physicalAddress"
|
||||
/>
|
||||
<div
|
||||
@ -188,16 +187,22 @@ a.card {
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
span.tag {
|
||||
margin: 5px auto;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.75em;
|
||||
span.tag {
|
||||
margin: 5px auto;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.75em;
|
||||
|
||||
&:not(.is-info, .is-danger) {
|
||||
background-color: #e6e4f4;
|
||||
color: #3c376e;
|
||||
color: $violet-3;
|
||||
}
|
||||
&.is-info {
|
||||
color: $violet-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,17 +169,20 @@ export default class EventFullDate extends Vue {
|
||||
|
||||
isSameDay(): boolean {
|
||||
const sameDay =
|
||||
new Date(this.beginsOn).toDateString() ===
|
||||
new Date(this.endsOn).toDateString();
|
||||
this.beginsOnDate.toDateString() === new Date(this.endsOn).toDateString();
|
||||
return this.endsOn !== undefined && sameDay;
|
||||
}
|
||||
|
||||
get beginsOnDate(): Date {
|
||||
return new Date(this.beginsOn);
|
||||
}
|
||||
|
||||
get differentFromUserTimezone(): boolean {
|
||||
return (
|
||||
!!this.timezone &&
|
||||
!!this.userActualTimezone &&
|
||||
getTimezoneOffset(this.timezone) !==
|
||||
getTimezoneOffset(this.userActualTimezone) &&
|
||||
getTimezoneOffset(this.timezone, this.beginsOnDate) !==
|
||||
getTimezoneOffset(this.userActualTimezone, this.beginsOnDate) &&
|
||||
this.timezone !== this.userActualTimezone
|
||||
);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ div.eventMetadataBlock {
|
||||
.content-wrapper {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
max-width: calc(100vw - 32px - 20px);
|
||||
|
||||
&.padding-left {
|
||||
padding: 0 20px;
|
||||
|
@ -34,14 +34,9 @@
|
||||
class="metadata-organized-by"
|
||||
:title="$t('Organized by')"
|
||||
>
|
||||
<popover-actor-card
|
||||
:actor="event.organizerActor"
|
||||
v-if="!event.attributedTo"
|
||||
>
|
||||
<actor-card :actor="event.organizerActor" />
|
||||
</popover-actor-card>
|
||||
<router-link
|
||||
v-if="event.attributedTo"
|
||||
class="hover:underline"
|
||||
:to="{
|
||||
name: RouteName.GROUP,
|
||||
params: {
|
||||
@ -49,23 +44,21 @@
|
||||
},
|
||||
}"
|
||||
>
|
||||
<popover-actor-card
|
||||
:actor="event.attributedTo"
|
||||
<actor-card
|
||||
v-if="
|
||||
!event.attributedTo || !event.options.hideOrganizerWhenGroupEvent
|
||||
"
|
||||
>
|
||||
<actor-card :actor="event.attributedTo" />
|
||||
</popover-actor-card>
|
||||
:actor="event.attributedTo"
|
||||
:inline="true"
|
||||
/>
|
||||
</router-link>
|
||||
|
||||
<popover-actor-card
|
||||
<actor-card v-else :actor="event.organizerActor" :inline="true" />
|
||||
<actor-card
|
||||
:inline="true"
|
||||
:actor="contact"
|
||||
v-for="contact in event.contacts"
|
||||
:key="contact.id"
|
||||
>
|
||||
<actor-card :actor="contact" />
|
||||
</popover-actor-card>
|
||||
/>
|
||||
</event-metadata-block>
|
||||
<event-metadata-block
|
||||
v-if="event.onlineAddress && urlToHostname(event.onlineAddress)"
|
||||
@ -74,6 +67,7 @@
|
||||
>
|
||||
<a
|
||||
target="_blank"
|
||||
class="hover:underline"
|
||||
rel="noopener noreferrer ugc"
|
||||
:href="event.onlineAddress"
|
||||
:title="
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<router-link
|
||||
class="event-minimalist-card-wrapper"
|
||||
class="event-minimalist-card-wrapper bg-white rounded-lg shadow-md"
|
||||
dir="auto"
|
||||
:to="{ name: RouteName.EVENT, params: { uuid: event.uuid } }"
|
||||
>
|
||||
@ -18,6 +18,20 @@
|
||||
</div>
|
||||
<div class="title-info-wrapper has-text-grey-dark">
|
||||
<h3 class="event-minimalist-title" :lang="event.language" dir="auto">
|
||||
<b-tag
|
||||
type="is-info"
|
||||
class="mr-1"
|
||||
v-if="event.status === EventStatus.TENTATIVE"
|
||||
>
|
||||
{{ $t("Tentative") }}
|
||||
</b-tag>
|
||||
<b-tag
|
||||
type="is-danger"
|
||||
class="mr-1"
|
||||
v-if="event.status === EventStatus.CANCELLED"
|
||||
>
|
||||
{{ $t("Cancelled") }}
|
||||
</b-tag>
|
||||
<b-tag
|
||||
class="mr-2"
|
||||
type="is-warning"
|
||||
@ -105,7 +119,7 @@
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import { IEvent, organizer, organizerDisplayName } from "@/types/event.model";
|
||||
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
||||
import { ParticipantRole } from "@/types/enums";
|
||||
import { EventStatus, ParticipantRole } from "@/types/enums";
|
||||
import RouteName from "../../router/name";
|
||||
import LazyImageWrapper from "@/components/Image/LazyImageWrapper.vue";
|
||||
import InlineAddress from "@/components/Address/InlineAddress.vue";
|
||||
@ -129,6 +143,8 @@ export default class EventMinimalistCard extends Vue {
|
||||
organizerDisplayName = organizerDisplayName;
|
||||
|
||||
organizer = organizer;
|
||||
|
||||
EventStatus = EventStatus;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -45,6 +45,22 @@
|
||||
</div>
|
||||
<div class="list-card-content">
|
||||
<div class="title-wrapper" dir="auto">
|
||||
<b-tag
|
||||
type="is-info"
|
||||
class="mr-1 mb-1"
|
||||
size="is-medium"
|
||||
v-if="participation.event.status === EventStatus.TENTATIVE"
|
||||
>
|
||||
{{ $t("Tentative") }}
|
||||
</b-tag>
|
||||
<b-tag
|
||||
type="is-danger"
|
||||
class="mr-1 mb-1"
|
||||
size="is-medium"
|
||||
v-if="participation.event.status === EventStatus.CANCELLED"
|
||||
>
|
||||
{{ $t("Cancelled") }}
|
||||
</b-tag>
|
||||
<router-link
|
||||
:to="{
|
||||
name: RouteName.EVENT,
|
||||
@ -257,7 +273,7 @@ import { Component, Prop } from "vue-property-decorator";
|
||||
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
||||
import { mixins } from "vue-class-component";
|
||||
import { RawLocation, Route } from "vue-router";
|
||||
import { EventVisibility, ParticipantRole } from "@/types/enums";
|
||||
import { EventStatus, EventVisibility, ParticipantRole } from "@/types/enums";
|
||||
import { IParticipant } from "../../types/participant.model";
|
||||
import {
|
||||
IEventCardOptions,
|
||||
@ -326,6 +342,8 @@ export default class EventParticipationCard extends mixins(
|
||||
|
||||
RouteName = RouteName;
|
||||
|
||||
EventStatus = EventStatus;
|
||||
|
||||
get mergedOptions(): IEventCardOptions {
|
||||
return { ...defaultOptions, ...this.options };
|
||||
}
|
||||
|
@ -5,33 +5,48 @@
|
||||
:placeholder="$t('Filter by profile or group name')"
|
||||
v-model="actorFilter"
|
||||
/>
|
||||
<b-radio-button
|
||||
v-model="selectedActor"
|
||||
:native-value="availableActor"
|
||||
class="list-item"
|
||||
v-for="availableActor in actualFilteredAvailableActors"
|
||||
:key="availableActor.id"
|
||||
<transition-group
|
||||
tag="ul"
|
||||
class="grid grid-cols-1 gap-y-3 m-5 max-w-md mx-auto"
|
||||
enter-active-class="duration-300 ease-out"
|
||||
enter-from-class="transform opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-active-class="duration-200 ease-in"
|
||||
leave-from-class="opacity-100"
|
||||
leave-to-class="transform opacity-0"
|
||||
>
|
||||
<div class="media" dir="auto">
|
||||
<figure class="image is-48x48" v-if="availableActor.avatar">
|
||||
<img
|
||||
class="image is-rounded"
|
||||
:src="availableActor.avatar.url"
|
||||
alt=""
|
||||
/>
|
||||
</figure>
|
||||
<b-icon
|
||||
class="media-left"
|
||||
v-else
|
||||
size="is-large"
|
||||
icon="account-circle"
|
||||
<li
|
||||
class="relative focus-within:shadow-lg"
|
||||
v-for="availableActor in actualFilteredAvailableActors"
|
||||
:key="availableActor.id"
|
||||
>
|
||||
<input
|
||||
class="sr-only peer"
|
||||
type="radio"
|
||||
:value="availableActor"
|
||||
name="availableActors"
|
||||
v-model="selectedActor"
|
||||
:id="`availableActor-${availableActor.id}`"
|
||||
/>
|
||||
<div class="media-content">
|
||||
<h3>{{ availableActor.name }}</h3>
|
||||
<small>{{ `@${availableActor.preferredUsername}` }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</b-radio-button>
|
||||
<label
|
||||
class="flex flex-wrap p-3 bg-white border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50 peer-checked:ring-primary peer-checked:ring-2 peer-checked:border-transparent"
|
||||
:for="`availableActor-${availableActor.id}`"
|
||||
>
|
||||
<figure class="image is-48x48" v-if="availableActor.avatar">
|
||||
<img
|
||||
class="image is-rounded"
|
||||
:src="availableActor.avatar.url"
|
||||
alt=""
|
||||
/>
|
||||
</figure>
|
||||
<b-icon v-else size="is-large" icon="account-circle" />
|
||||
<div>
|
||||
<h3>{{ availableActor.name }}</h3>
|
||||
<small>{{ `@${availableActor.preferredUsername}` }}</small>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
@ -51,6 +66,13 @@ import { MemberRole } from "@/types/enums";
|
||||
groupMemberships: {
|
||||
query: LOGGED_USER_MEMBERSHIPS,
|
||||
update: (data) => data.loggedUser.memberships,
|
||||
variables() {
|
||||
return {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
membershipName: this.actorFilter,
|
||||
};
|
||||
},
|
||||
},
|
||||
identities: IDENTITIES,
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="organizer-picker" v-if="selectedActor">
|
||||
<div
|
||||
class="bg-white border border-gray-300 rounded-lg cursor-pointer"
|
||||
v-if="selectedActor"
|
||||
>
|
||||
<!-- If we have a current actor (inline) -->
|
||||
<div
|
||||
v-if="inline && selectedActor.id"
|
||||
@ -65,42 +68,61 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="column contact-picker">
|
||||
<div v-if="isSelectedActorAGroup && actorMembers.length > 0">
|
||||
<div v-if="isSelectedActorAGroup">
|
||||
<p>{{ $t("Add a contact") }}</p>
|
||||
<b-input
|
||||
:placeholder="$t('Filter by name')"
|
||||
v-model="contactFilter"
|
||||
:value="contactFilter"
|
||||
@input="debounceSetFilterByName"
|
||||
dir="auto"
|
||||
/>
|
||||
<p
|
||||
class="field"
|
||||
v-for="actor in filteredActorMembers"
|
||||
:key="actor.id"
|
||||
>
|
||||
<b-checkbox v-model="actualContacts" :native-value="actor.id">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48" v-if="actor.avatar">
|
||||
<img
|
||||
class="image is-rounded"
|
||||
:src="actor.avatar.url"
|
||||
:alt="actor.avatar.alt"
|
||||
<div v-if="actorMembers.length > 0">
|
||||
<p
|
||||
class="field"
|
||||
v-for="actor in filteredActorMembers"
|
||||
:key="actor.id"
|
||||
>
|
||||
<b-checkbox
|
||||
v-model="actualContacts"
|
||||
:native-value="actor.id"
|
||||
>
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48" v-if="actor.avatar">
|
||||
<img
|
||||
class="image is-rounded"
|
||||
:src="actor.avatar.url"
|
||||
:alt="actor.avatar.alt"
|
||||
/>
|
||||
</figure>
|
||||
<b-icon
|
||||
v-else
|
||||
size="is-large"
|
||||
icon="account-circle"
|
||||
/>
|
||||
</figure>
|
||||
<b-icon v-else size="is-large" icon="account-circle" />
|
||||
</div>
|
||||
<div class="media-content" v-if="actor.name">
|
||||
<p class="is-4">{{ actor.name }}</p>
|
||||
<p class="is-6 has-text-grey-dark">
|
||||
</div>
|
||||
<div class="media-content" v-if="actor.name">
|
||||
<p class="is-4">{{ actor.name }}</p>
|
||||
<p class="is-6 has-text-grey-dark">
|
||||
{{ `@${usernameWithDomain(actor)}` }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="media-content" v-else>
|
||||
{{ `@${usernameWithDomain(actor)}` }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-content" v-else>
|
||||
{{ `@${usernameWithDomain(actor)}` }}
|
||||
</div>
|
||||
</div>
|
||||
</b-checkbox>
|
||||
</p>
|
||||
</b-checkbox>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
actorMembers.length === 0 && contactFilter.length > 0
|
||||
"
|
||||
>
|
||||
<empty-content icon="account-multiple" :inline="true">
|
||||
{{ $t("No group member found") }}
|
||||
</empty-content>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="content has-text-grey-dark has-text-centered">
|
||||
<p>{{ $t("Your profile will be shown as contact.") }}</p>
|
||||
@ -122,14 +144,16 @@ import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||
import { IMember } from "@/types/actor/member.model";
|
||||
import { IActor, IGroup, IPerson, usernameWithDomain } from "../../types/actor";
|
||||
import OrganizerPicker from "./OrganizerPicker.vue";
|
||||
import EmptyContent from "../Utils/EmptyContent.vue";
|
||||
import {
|
||||
CURRENT_ACTOR_CLIENT,
|
||||
IDENTITIES,
|
||||
LOGGED_USER_MEMBERSHIPS,
|
||||
PERSON_GROUP_MEMBERSHIPS,
|
||||
} from "../../graphql/actor";
|
||||
import { Paginate } from "../../types/paginate";
|
||||
import { GROUP_MEMBERS } from "@/graphql/member";
|
||||
import { ActorType, MemberRole } from "@/types/enums";
|
||||
import debounce from "lodash/debounce";
|
||||
|
||||
const MEMBER_ROLES = [
|
||||
MemberRole.CREATOR,
|
||||
@ -139,16 +163,17 @@ const MEMBER_ROLES = [
|
||||
];
|
||||
|
||||
@Component({
|
||||
components: { OrganizerPicker },
|
||||
components: { OrganizerPicker, EmptyContent },
|
||||
apollo: {
|
||||
members: {
|
||||
query: GROUP_MEMBERS,
|
||||
variables() {
|
||||
return {
|
||||
name: usernameWithDomain(this.selectedActor),
|
||||
groupName: usernameWithDomain(this.selectedActor),
|
||||
page: this.membersPage,
|
||||
limit: 10,
|
||||
roles: MEMBER_ROLES.join(","),
|
||||
name: this.contactFilter,
|
||||
};
|
||||
},
|
||||
update: (data) => data.group.members,
|
||||
@ -159,13 +184,17 @@ const MEMBER_ROLES = [
|
||||
},
|
||||
},
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
userMemberships: {
|
||||
query: LOGGED_USER_MEMBERSHIPS,
|
||||
variables: {
|
||||
page: 1,
|
||||
limit: 100,
|
||||
personMemberships: {
|
||||
query: PERSON_GROUP_MEMBERSHIPS,
|
||||
variables() {
|
||||
return {
|
||||
id: this.currentActor?.id,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
groupId: this.$route.query?.actorId,
|
||||
};
|
||||
},
|
||||
update: (data) => data.loggedUser.memberships,
|
||||
update: (data) => data.person.memberships,
|
||||
},
|
||||
identities: IDENTITIES,
|
||||
},
|
||||
@ -175,6 +204,9 @@ export default class OrganizerPickerWrapper extends Vue {
|
||||
|
||||
@Prop({ default: true, type: Boolean }) inline!: boolean;
|
||||
|
||||
@Prop({ type: Array, required: false, default: () => [] })
|
||||
contacts!: IActor[];
|
||||
|
||||
currentActor!: IPerson;
|
||||
|
||||
identities!: IPerson[];
|
||||
@ -185,13 +217,17 @@ export default class OrganizerPickerWrapper extends Vue {
|
||||
|
||||
usernameWithDomain = usernameWithDomain;
|
||||
|
||||
@Prop({ type: Array, required: false, default: () => [] })
|
||||
contacts!: IActor[];
|
||||
members: Paginate<IMember> = { elements: [], total: 0 };
|
||||
|
||||
membersPage = 1;
|
||||
|
||||
userMemberships: Paginate<IMember> = { elements: [], total: 0 };
|
||||
personMemberships: Paginate<IMember> = { elements: [], total: 0 };
|
||||
|
||||
data(): Record<string, unknown> {
|
||||
return {
|
||||
debounceSetFilterByName: debounce(this.setContactFilter, 1000),
|
||||
};
|
||||
}
|
||||
|
||||
get actualContacts(): (string | undefined)[] {
|
||||
return this.contacts.map(({ id }) => id);
|
||||
@ -204,15 +240,17 @@ export default class OrganizerPickerWrapper extends Vue {
|
||||
);
|
||||
}
|
||||
|
||||
@Watch("userMemberships")
|
||||
setContactFilter(contactFilter: string) {
|
||||
this.contactFilter = contactFilter;
|
||||
}
|
||||
|
||||
@Watch("personMemberships")
|
||||
setInitialActor(): void {
|
||||
if (this.$route.query?.actorId) {
|
||||
const actorId = this.$route.query?.actorId as string;
|
||||
const actor = this.userMemberships.elements.find(
|
||||
({ parent: { id }, role }) =>
|
||||
actorId === id && MEMBER_ROLES.includes(role)
|
||||
)?.parent as IActor;
|
||||
this.selectedActor = actor;
|
||||
if (
|
||||
this.personMemberships?.elements[0]?.parent?.id ===
|
||||
this.$route.query?.actorId
|
||||
) {
|
||||
this.selectedActor = this.personMemberships?.elements[0]?.parent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +292,7 @@ export default class OrganizerPickerWrapper extends Vue {
|
||||
actor.preferredUsername.toLowerCase(),
|
||||
actor.name?.toLowerCase(),
|
||||
actor.domain?.toLowerCase(),
|
||||
].some((match) => match?.includes(this.contactFilter.toLowerCase()));
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ export default class ShareEventModal extends Vue {
|
||||
}
|
||||
|
||||
get mastodonShareUrl(): string {
|
||||
return `https://toot.karamoff.dev/?text=${encodeURIComponent(
|
||||
return `https://toot.kytta.dev/?text=${encodeURIComponent(
|
||||
this.basicTextToEncode
|
||||
)}`;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
maxlength="20"
|
||||
maxtags="10"
|
||||
:placeholder="$t('Eg: Stockholm, Dance, Chess…')"
|
||||
@typing="getFilteredTags"
|
||||
@typing="debouncedGetFilteredTags"
|
||||
:id="id"
|
||||
dir="auto"
|
||||
>
|
||||
@ -33,6 +33,7 @@ import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import differenceBy from "lodash/differenceBy";
|
||||
import { ITag } from "../../types/tag.model";
|
||||
import { FILTER_TAGS } from "@/graphql/tags";
|
||||
import debounce from "lodash/debounce";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
@ -63,6 +64,12 @@ export default class TagInput extends Vue {
|
||||
return `tag-input-${TagInput.componentId}`;
|
||||
}
|
||||
|
||||
data(): Record<string, unknown> {
|
||||
return {
|
||||
debouncedGetFilteredTags: debounce(this.getFilteredTags, 200),
|
||||
};
|
||||
}
|
||||
|
||||
async getFilteredTags(text: string): Promise<void> {
|
||||
this.text = text;
|
||||
await this.$apollo.queries.tags.refetch();
|
||||
|
@ -31,11 +31,11 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content mb-2" dir="auto" v-html="group.summary" />
|
||||
<div class="card-custom-footer">
|
||||
<div class="mb-2 line-clamp-3" dir="auto" v-html="group.summary" />
|
||||
<div>
|
||||
<inline-address
|
||||
class="has-text-grey-dark"
|
||||
v-if="group.physicalAddress"
|
||||
v-if="group.physicalAddress && addressFullName(group.physicalAddress)"
|
||||
:physicalAddress="group.physicalAddress"
|
||||
/>
|
||||
<p class="has-text-grey-dark">
|
||||
@ -61,6 +61,7 @@ import { displayName, IGroup, usernameWithDomain } from "@/types/actor";
|
||||
import LazyImageWrapper from "@/components/Image/LazyImageWrapper.vue";
|
||||
import RouteName from "../../router/name";
|
||||
import InlineAddress from "@/components/Address/InlineAddress.vue";
|
||||
import { addressFullName } from "@/types/address.model";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -76,6 +77,8 @@ export default class GroupCard extends Vue {
|
||||
usernameWithDomain = usernameWithDomain;
|
||||
|
||||
displayName = displayName;
|
||||
|
||||
addressFullName = addressFullName;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -10,7 +10,7 @@
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import RedirectWithAccount from "@/components/Utils/RedirectWithAccount.vue";
|
||||
import { FETCH_GROUP } from "@/graphql/group";
|
||||
import { IGroup } from "@/types/actor";
|
||||
import { displayName, IGroup } from "@/types/actor";
|
||||
|
||||
@Component({
|
||||
components: { RedirectWithAccount },
|
||||
@ -52,7 +52,7 @@ export default class JoinGroupWithAccount extends Vue {
|
||||
}
|
||||
|
||||
get groupTitle(): undefined | string {
|
||||
return this.group?.name || this.group?.preferredUsername;
|
||||
return this.group && displayName(this.group);
|
||||
}
|
||||
|
||||
sentence = this.$t(
|
||||
|
@ -117,7 +117,7 @@ import { Component, Prop, Vue, Ref } from "vue-property-decorator";
|
||||
import { GroupVisibility } from "@/types/enums";
|
||||
import DiasporaLogo from "../Share/DiasporaLogo.vue";
|
||||
import MastodonLogo from "../Share/MastodonLogo.vue";
|
||||
import TelegramLogo from "../Share/MastodonLogo.vue";
|
||||
import TelegramLogo from "../Share/TelegramLogo.vue";
|
||||
import { displayName, IGroup } from "@/types/actor";
|
||||
|
||||
@Component({
|
||||
@ -177,7 +177,7 @@ export default class ShareGroupModal extends Vue {
|
||||
}
|
||||
|
||||
get mastodonShareUrl(): string {
|
||||
return `https://toot.karamoff.dev/?text=${encodeURIComponent(
|
||||
return `https://toot.kytta.dev/?text=${encodeURIComponent(
|
||||
this.basicTextToEncode
|
||||
)}`;
|
||||
}
|
||||
|
@ -142,7 +142,9 @@ export default class Map extends Vue {
|
||||
}
|
||||
|
||||
updateDraggableMarkerPosition(e: LatLng): void {
|
||||
this.updateDraggableMarkerCallback(e, this.zoom);
|
||||
if (this.updateDraggableMarkerCallback) {
|
||||
this.updateDraggableMarkerCallback(e, this.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
updateZoom(zoom: number): void {
|
||||
|
@ -28,7 +28,7 @@ export default class Vue2LeafletLocateControl extends Vue {
|
||||
unknown
|
||||
>;
|
||||
|
||||
@Prop({ type: Boolean, default: true }) visible = true;
|
||||
@Prop({ type: Boolean, default: true }) visible!: boolean;
|
||||
|
||||
ready = false;
|
||||
|
||||
|
@ -56,21 +56,6 @@
|
||||
>{{ $t("Create") }}</b-button
|
||||
>
|
||||
</b-navbar-item>
|
||||
<b-navbar-item
|
||||
v-if="config && config.features.koenaConnect"
|
||||
class="koena"
|
||||
tag="a"
|
||||
href="https://mediation.koena.net/framasoft/mobilizon/"
|
||||
target="_blank"
|
||||
rel="noopener external"
|
||||
hreflang="fr"
|
||||
>
|
||||
<img
|
||||
src="/img/koena-a11y.svg"
|
||||
width="150"
|
||||
alt="Contact accessibilité"
|
||||
/>
|
||||
</b-navbar-item>
|
||||
</template>
|
||||
<template slot="end">
|
||||
<b-navbar-item
|
||||
@ -285,6 +270,11 @@ export default class NavBar extends Vue {
|
||||
// If we don't have any identities, the user has validated their account,
|
||||
// is logging for the first time but didn't create an identity somehow
|
||||
if (this.identities.length === 0) {
|
||||
console.debug(
|
||||
"We have no identities listed for current user",
|
||||
this.identities
|
||||
);
|
||||
console.debug("Pushing route to REGISTER_PROFILE");
|
||||
try {
|
||||
await this.$router.push({
|
||||
name: RouteName.REGISTER_PROFILE,
|
||||
@ -389,15 +379,6 @@ nav {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.koena {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
& > img {
|
||||
max-height: 4rem;
|
||||
padding-top: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.identity-wrapper {
|
||||
display: flex;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
:rounded="true"
|
||||
style="height: 120px"
|
||||
/>
|
||||
<div class="title-info-wrapper has-text-grey-dark">
|
||||
<div class="title-info-wrapper has-text-grey-dark px-1">
|
||||
<h3 class="post-minimalist-title" :lang="post.language">
|
||||
{{ post.title }}
|
||||
</h3>
|
||||
|
@ -179,7 +179,7 @@ export default class SharePostModal extends Vue {
|
||||
}
|
||||
|
||||
get mastodonShareUrl(): string {
|
||||
return `https://toot.karamoff.dev/?text=${encodeURIComponent(
|
||||
return `https://toot.kytta.dev/?text=${encodeURIComponent(
|
||||
this.basicTextToEncode
|
||||
)}`;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
:class="{ 'is-titleless': !title }"
|
||||
>
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<div class="media-left hidden md:block">
|
||||
<b-icon icon="alert" type="is-warning" size="is-large" />
|
||||
</div>
|
||||
<div class="media-content">
|
||||
|
@ -45,7 +45,7 @@
|
||||
</a>
|
||||
<resource-dropdown
|
||||
class="actions"
|
||||
v-if="!inline || !preview"
|
||||
v-if="!inline && !preview"
|
||||
@delete="$emit('delete', resource.id)"
|
||||
@move="$emit('move', resource)"
|
||||
@rename="$emit('rename', resource)"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="resource">
|
||||
<article class="panel is-primary">
|
||||
<p class="panel-heading">
|
||||
<p class="panel-heading truncate">
|
||||
{{
|
||||
$t('Move "{resourceName}"', { resourceName: initialResource.title })
|
||||
}}
|
||||
@ -28,7 +28,7 @@
|
||||
</a>
|
||||
<template v-if="resource.children">
|
||||
<a
|
||||
class="panel-block"
|
||||
class="panel-block flex-wrap"
|
||||
v-for="element in resource.children.elements"
|
||||
:class="{
|
||||
clickable:
|
||||
@ -37,15 +37,17 @@
|
||||
:key="element.id"
|
||||
@click="goDown(element)"
|
||||
>
|
||||
<span class="panel-icon">
|
||||
<b-icon
|
||||
icon="folder"
|
||||
size="is-small"
|
||||
v-if="element.type === 'folder'"
|
||||
/>
|
||||
<b-icon icon="link" size="is-small" v-else />
|
||||
</span>
|
||||
{{ element.title }}
|
||||
<p class="truncate">
|
||||
<span class="panel-icon">
|
||||
<b-icon
|
||||
icon="folder"
|
||||
size="is-small"
|
||||
v-if="element.type === 'folder'"
|
||||
/>
|
||||
<b-icon icon="link" size="is-small" v-else />
|
||||
</span>
|
||||
<span>{{ element.title }}</span>
|
||||
</p>
|
||||
<span v-if="element.id === initialResource.id">
|
||||
<em v-if="element.type === 'folder'"> {{ $t("(this folder)") }}</em>
|
||||
<em v-else> {{ $t("(this link)") }}</em>
|
||||
@ -89,7 +91,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import { Component, Vue, Prop, Watch } from "vue-property-decorator";
|
||||
import { GET_RESOURCE } from "../../graphql/resources";
|
||||
import { IResource } from "../../types/resource";
|
||||
|
||||
@ -119,7 +121,7 @@ export default class ResourceSelector extends Vue {
|
||||
|
||||
@Prop({ required: true }) username!: string;
|
||||
|
||||
resource: IResource | undefined = this.initialResource.parent;
|
||||
resource: IResource | undefined = undefined;
|
||||
|
||||
RESOURCES_PER_PAGE = 10;
|
||||
|
||||
@ -131,6 +133,20 @@ export default class ResourceSelector extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
data() {
|
||||
return {
|
||||
resource: this.initialResource?.parent,
|
||||
};
|
||||
}
|
||||
|
||||
@Watch("initialResource")
|
||||
updateResourceFromProp() {
|
||||
if (this.initialResource) {
|
||||
this.resource = this.initialResource?.parent;
|
||||
this.$apollo.queries.resource.refetch();
|
||||
}
|
||||
}
|
||||
|
||||
updateResource(): void {
|
||||
this.$emit(
|
||||
"update-resource",
|
||||
|
@ -1,18 +1,22 @@
|
||||
<template>
|
||||
<label for="navSearchField">
|
||||
<span class="visually-hidden">{{ defaultPlaceHolder }}</span>
|
||||
<b-field label-for="navSearchField" class="-mt-2">
|
||||
<b-input
|
||||
custom-class="searchField"
|
||||
:placeholder="defaultPlaceHolder"
|
||||
type="search"
|
||||
id="navSearchField"
|
||||
icon="magnify"
|
||||
type="search"
|
||||
icon-clickable
|
||||
rounded
|
||||
custom-class="searchField"
|
||||
dir="auto"
|
||||
:placeholder="defaultPlaceHolder"
|
||||
v-model="search"
|
||||
@keyup.native.enter="enter"
|
||||
/>
|
||||
</label>
|
||||
>
|
||||
</b-input>
|
||||
<template #label>
|
||||
<span class="sr-only">{{ defaultPlaceHolder }}</span>
|
||||
</template>
|
||||
</b-field>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
@ -47,6 +51,7 @@ label span.visually-hidden {
|
||||
input.searchField {
|
||||
box-shadow: none;
|
||||
border-color: #b5b5b5;
|
||||
border-radius: 9999px !important;
|
||||
|
||||
&::placeholder {
|
||||
color: gray;
|
||||
|
@ -78,7 +78,7 @@
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="$t('Federation')"
|
||||
:to="{ name: RouteName.RELAYS }"
|
||||
:to="{ name: RouteName.INSTANCES }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
</ul>
|
||||
|
@ -17,7 +17,8 @@ span.tag {
|
||||
background: $purple-3;
|
||||
color: $violet-2;
|
||||
text-transform: uppercase;
|
||||
&::before {
|
||||
|
||||
&:not(.category)::before {
|
||||
content: "#";
|
||||
}
|
||||
}
|
||||
|
@ -7,29 +7,23 @@
|
||||
<b-field :label="$t('Title')">
|
||||
<b-input v-model="title" />
|
||||
</b-field>
|
||||
<b-field :label="$t('Assigned to')">
|
||||
<actor-auto-complete v-model="assignedTo" />
|
||||
</b-field>
|
||||
<b-field :label="$t('Assigned to')"> </b-field>
|
||||
<b-field :label="$t('Due on')">
|
||||
<b-datepicker v-model="dueDate" />
|
||||
<b-datepicker v-model="dueDate" :first-day-of-week="firstDayOfWeek" />
|
||||
</b-field>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import { Prop, Vue } from "vue-property-decorator";
|
||||
import debounce from "lodash/debounce";
|
||||
import { DebouncedFunc } from "lodash";
|
||||
import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import { ITodo } from "../../types/todos";
|
||||
import RouteName from "../../router/name";
|
||||
import { UPDATE_TODO } from "../../graphql/todos";
|
||||
import ActorAutoComplete from "../Account/ActorAutoComplete.vue";
|
||||
import { IPerson } from "../../types/actor";
|
||||
|
||||
@Component({
|
||||
components: { ActorAutoComplete },
|
||||
})
|
||||
export default class Todo extends Vue {
|
||||
@Prop({ required: true, type: Object }) todo!: ITodo;
|
||||
|
||||
@ -99,5 +93,9 @@ export default class Todo extends Vue {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get firstDayOfWeek(): number {
|
||||
return this.$dateFnsLocale?.options?.weekStartsOn || 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
69
js/src/components/Utils/Breadcrumbs.vue
Normal file
69
js/src/components/Utils/Breadcrumbs.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<nav class="flex mb-3" :aria-label="$t('Breadcrumbs')">
|
||||
<ol class="inline-flex items-center space-x-1 md:space-x-3 flex-wrap">
|
||||
<li
|
||||
class="inline-flex items-center"
|
||||
v-for="(element, index) in links"
|
||||
:key="index"
|
||||
:aria-current="index > 0 ? 'page' : undefined"
|
||||
>
|
||||
<router-link
|
||||
v-if="index === 0"
|
||||
:to="element"
|
||||
class="inline-flex items-center text-gray-800 hover:text-gray-900"
|
||||
>
|
||||
{{ element.text }}
|
||||
</router-link>
|
||||
<div class="flex items-center" v-else-if="index === links.length - 1">
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400 rtl:rotate-180"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span
|
||||
class="ltr:ml-1 rtl:mr-1 font-medium text-gray-600 md:ltr:ml-2 md:rtl:mr-2"
|
||||
>{{ element.text }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center" v-else>
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400 rtl:rotate-180"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<router-link
|
||||
:to="element"
|
||||
class="ltr:ml-1 rtl:mr-1 font-medium text-gray-800 hover:text-gray-900 md:ltr:ml-2 md:rtl:mr-2"
|
||||
>{{ element.text }}</router-link
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<slot></slot>
|
||||
</ol>
|
||||
</nav>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
import { Location } from "vue-router";
|
||||
|
||||
type LinkElement = Location & { text: string };
|
||||
|
||||
@Component
|
||||
export default class Breadcrumbs extends Vue {
|
||||
@Prop({ type: Array, required: true }) links!: LinkElement[];
|
||||
}
|
||||
</script>
|
@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<div class="empty-content" :class="{ inline }" role="note">
|
||||
<div
|
||||
class="empty-content"
|
||||
:class="{ inline, 'text-center': center }"
|
||||
role="note"
|
||||
>
|
||||
<b-icon :icon="icon" size="is-large" />
|
||||
<h2 class="empty-content__title">
|
||||
<!-- @slot Mandatory title -->
|
||||
<slot />
|
||||
</h2>
|
||||
<p v-show="$slots.desc">
|
||||
<p v-show="$slots.desc" :class="descriptionClasses">
|
||||
<!-- @slot Optional description -->
|
||||
<slot name="desc" />
|
||||
</p>
|
||||
@ -17,7 +21,10 @@ import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
@Component
|
||||
export default class EmptyContent extends Vue {
|
||||
@Prop({ type: String, required: true }) icon!: string;
|
||||
@Prop({ type: String, required: false, default: "" })
|
||||
descriptionClasses!: string;
|
||||
@Prop({ type: Boolean, required: false, default: false }) inline!: boolean;
|
||||
@Prop({ type: Boolean, required: false, default: false }) center!: boolean;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -34,15 +34,6 @@ export const FETCH_PERSON = gql`
|
||||
feedTokens {
|
||||
token
|
||||
}
|
||||
organizedEvents {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ACTOR_FRAGMENT}
|
||||
@ -84,6 +75,7 @@ export const GET_PERSON = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
}
|
||||
}
|
||||
participations(page: $participationPage, limit: $participationLimit) {
|
||||
@ -95,6 +87,7 @@ export const GET_PERSON = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,6 +206,7 @@ export const LOGGED_USER_DRAFTS = gql`
|
||||
alt
|
||||
}
|
||||
beginsOn
|
||||
status
|
||||
visibility
|
||||
attributedTo {
|
||||
...ActorFragment
|
||||
@ -235,10 +229,14 @@ export const LOGGED_USER_DRAFTS = gql`
|
||||
`;
|
||||
|
||||
export const LOGGED_USER_MEMBERSHIPS = gql`
|
||||
query LoggedUserMemberships($page: Int, $limit: Int) {
|
||||
query LoggedUserMemberships(
|
||||
$membershipName: String
|
||||
$page: Int
|
||||
$limit: Int
|
||||
) {
|
||||
loggedUser {
|
||||
id
|
||||
memberships(page: $page, limit: $limit) {
|
||||
memberships(name: $membershipName, page: $page, limit: $limit) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
@ -343,6 +341,30 @@ export const PERSON_STATUS_GROUP = gql`
|
||||
${ACTOR_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const PERSON_GROUP_MEMBERSHIPS = gql`
|
||||
query PersonGroupMemberships($id: ID!, $groupId: ID!) {
|
||||
person(id: $id) {
|
||||
id
|
||||
memberships(groupId: $groupId) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
role
|
||||
parent {
|
||||
...ActorFragment
|
||||
}
|
||||
invitedBy {
|
||||
...ActorFragment
|
||||
}
|
||||
insertedAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ACTOR_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED = gql`
|
||||
subscription GroupMembershipSubscriptionChanged(
|
||||
$actorId: ID!
|
||||
|
@ -70,13 +70,66 @@ export const RELAY_FOLLOWINGS = gql`
|
||||
${RELAY_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const ADD_RELAY = gql`
|
||||
mutation addRelay($address: String!) {
|
||||
addRelay(address: $address) {
|
||||
...relayFragment
|
||||
export const INSTANCE_FRAGMENT = gql`
|
||||
fragment InstanceFragment on Instance {
|
||||
domain
|
||||
hasRelay
|
||||
relayAddress
|
||||
followerStatus
|
||||
followedStatus
|
||||
eventCount
|
||||
personCount
|
||||
groupCount
|
||||
followersCount
|
||||
followingsCount
|
||||
reportsCount
|
||||
mediaSize
|
||||
}
|
||||
`;
|
||||
|
||||
export const INSTANCE = gql`
|
||||
query instance($domain: ID!) {
|
||||
instance(domain: $domain) {
|
||||
...InstanceFragment
|
||||
}
|
||||
}
|
||||
${RELAY_FRAGMENT}
|
||||
${INSTANCE_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const INSTANCES = gql`
|
||||
query Instances(
|
||||
$page: Int
|
||||
$limit: Int
|
||||
$orderBy: InstancesSortFields
|
||||
$direction: String
|
||||
$filterDomain: String
|
||||
$filterFollowStatus: InstanceFilterFollowStatus
|
||||
$filterSuspendStatus: InstanceFilterSuspendStatus
|
||||
) {
|
||||
instances(
|
||||
page: $page
|
||||
limit: $limit
|
||||
orderBy: $orderBy
|
||||
direction: $direction
|
||||
filterDomain: $filterDomain
|
||||
filterFollowStatus: $filterFollowStatus
|
||||
filterSuspendStatus: $filterSuspendStatus
|
||||
) {
|
||||
total
|
||||
elements {
|
||||
...InstanceFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
${INSTANCE_FRAGMENT}
|
||||
`;
|
||||
export const ADD_INSTANCE = gql`
|
||||
mutation addInstance($domain: String!) {
|
||||
addInstance(domain: $domain) {
|
||||
...InstanceFragment
|
||||
}
|
||||
}
|
||||
${INSTANCE_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const REMOVE_RELAY = gql`
|
||||
@ -190,3 +243,26 @@ export const SAVE_ADMIN_SETTINGS = gql`
|
||||
}
|
||||
${ADMIN_SETTINGS_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const ADMIN_UPDATE_USER = gql`
|
||||
mutation AdminUpdateUser(
|
||||
$id: ID!
|
||||
$email: String
|
||||
$role: UserRole
|
||||
$confirmed: Boolean
|
||||
$notify: Boolean
|
||||
) {
|
||||
adminUpdateUser(
|
||||
id: $id
|
||||
email: $email
|
||||
role: $role
|
||||
confirmed: $confirmed
|
||||
notify: $notify
|
||||
) {
|
||||
id
|
||||
email
|
||||
role
|
||||
confirmedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -11,6 +11,10 @@ export const CONFIG = gql`
|
||||
demoMode
|
||||
countryCode
|
||||
languages
|
||||
eventCategories {
|
||||
id
|
||||
label
|
||||
}
|
||||
anonymous {
|
||||
participation {
|
||||
allowed
|
||||
@ -67,7 +71,6 @@ export const CONFIG = gql`
|
||||
features {
|
||||
groups
|
||||
eventCreation
|
||||
koenaConnect
|
||||
}
|
||||
restrictions {
|
||||
onlyAdminCanCreateGroups
|
||||
@ -92,6 +95,15 @@ export const CONFIG = gql`
|
||||
enabled
|
||||
publicKey
|
||||
}
|
||||
analytics {
|
||||
id
|
||||
enabled
|
||||
configuration {
|
||||
key
|
||||
value
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -103,6 +115,10 @@ export const CONFIG_EDIT_EVENT = gql`
|
||||
features {
|
||||
groups
|
||||
}
|
||||
eventCategories {
|
||||
id
|
||||
label
|
||||
}
|
||||
anonymous {
|
||||
participation {
|
||||
allowed
|
||||
|
@ -23,6 +23,7 @@ const FULL_EVENT_FRAGMENT = gql`
|
||||
joinOptions
|
||||
draft
|
||||
language
|
||||
category
|
||||
picture {
|
||||
id
|
||||
url
|
||||
@ -61,6 +62,7 @@ const FULL_EVENT_FRAGMENT = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
language
|
||||
picture {
|
||||
id
|
||||
@ -202,11 +204,11 @@ export const CREATE_EVENT = gql`
|
||||
$picture: MediaInput
|
||||
$onlineAddress: String
|
||||
$phoneAddress: String
|
||||
$category: String
|
||||
$category: EventCategory
|
||||
$physicalAddress: AddressInput
|
||||
$options: EventOptionsInput
|
||||
$contacts: [Contact]
|
||||
$metadata: EventMetadataInput
|
||||
$metadata: [EventMetadataInput]
|
||||
) {
|
||||
createEvent(
|
||||
organizerActorId: $organizerActorId
|
||||
@ -252,11 +254,11 @@ export const EDIT_EVENT = gql`
|
||||
$phoneAddress: String
|
||||
$organizerActorId: ID
|
||||
$attributedToId: ID
|
||||
$category: String
|
||||
$category: EventCategory
|
||||
$physicalAddress: AddressInput
|
||||
$options: EventOptionsInput
|
||||
$contacts: [Contact]
|
||||
$metadata: EventMetadataInput
|
||||
$metadata: [EventMetadataInput]
|
||||
) {
|
||||
updateEvent(
|
||||
eventId: $id
|
||||
@ -438,6 +440,7 @@ export const FETCH_GROUP_EVENTS = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
draft
|
||||
options {
|
||||
...EventOptions
|
||||
|
@ -42,6 +42,7 @@ export const LIST_GROUPS = gql`
|
||||
id
|
||||
uuid
|
||||
title
|
||||
status
|
||||
beginsOn
|
||||
}
|
||||
total
|
||||
@ -104,6 +105,7 @@ export const GROUP_FIELDS_FRAGMENTS = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
draft
|
||||
language
|
||||
options {
|
||||
@ -224,6 +226,15 @@ export const FETCH_GROUP = gql`
|
||||
${RESOURCE_METADATA_BASIC_FIELDS_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const FETCH_GROUP_BY_ID = gql`
|
||||
query FetchGroupById($id: ID!) {
|
||||
groupById(id: $name) {
|
||||
...GroupFullFields
|
||||
}
|
||||
}
|
||||
${GROUP_FIELDS_FRAGMENTS}
|
||||
`;
|
||||
|
||||
export const GET_GROUP = gql`
|
||||
query GetGroup(
|
||||
$id: ID!
|
||||
|
@ -36,6 +36,7 @@ export const HOME_USER_QUERIES = gql`
|
||||
alt
|
||||
}
|
||||
beginsOn
|
||||
status
|
||||
visibility
|
||||
language
|
||||
organizerActor {
|
||||
@ -77,6 +78,7 @@ export const HOME_USER_QUERIES = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
picture {
|
||||
url
|
||||
}
|
||||
@ -127,6 +129,7 @@ export const CLOSE_CONTENT = gql`
|
||||
title
|
||||
uuid
|
||||
beginsOn
|
||||
status
|
||||
picture {
|
||||
id
|
||||
url
|
||||
|
@ -44,10 +44,16 @@ export const REJECT_INVITATION = gql`
|
||||
`;
|
||||
|
||||
export const GROUP_MEMBERS = gql`
|
||||
query ($name: String!, $roles: String, $page: Int, $limit: Int) {
|
||||
group(preferredUsername: $name) {
|
||||
query (
|
||||
$groupName: String!
|
||||
$name: String
|
||||
$roles: String
|
||||
$page: Int
|
||||
$limit: Int
|
||||
) {
|
||||
group(preferredUsername: $groupName) {
|
||||
...ActorFragment
|
||||
members(page: $page, limit: $limit, roles: $roles) {
|
||||
members(name: $name, page: $page, limit: $limit, roles: $roles) {
|
||||
elements {
|
||||
id
|
||||
role
|
||||
|
@ -32,6 +32,7 @@ export const LOGGED_USER_PARTICIPATIONS = gql`
|
||||
alt
|
||||
}
|
||||
beginsOn
|
||||
status
|
||||
visibility
|
||||
organizerActor {
|
||||
...ActorFragment
|
||||
@ -98,6 +99,7 @@ export const LOGGED_USER_UPCOMING_EVENTS = gql`
|
||||
alt
|
||||
}
|
||||
beginsOn
|
||||
status
|
||||
visibility
|
||||
organizerActor {
|
||||
...ActorFragment
|
||||
@ -144,6 +146,7 @@ export const LOGGED_USER_UPCOMING_EVENTS = gql`
|
||||
uuid
|
||||
title
|
||||
beginsOn
|
||||
status
|
||||
picture {
|
||||
url
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ export const FETCH_POST = gql`
|
||||
export const CREATE_POST = gql`
|
||||
mutation CreatePost(
|
||||
$title: String!
|
||||
$body: String
|
||||
$body: String!
|
||||
$attributedToId: ID!
|
||||
$visibility: PostVisibility
|
||||
$draft: Boolean
|
||||
|
@ -2,8 +2,13 @@ import gql from "graphql-tag";
|
||||
import { ACTOR_FRAGMENT } from "./actor";
|
||||
|
||||
export const REPORTS = gql`
|
||||
query Reports($status: ReportStatus, $page: Int, $limit: Int) {
|
||||
reports(status: $status, page: $page, limit: $limit) {
|
||||
query Reports(
|
||||
$status: ReportStatus
|
||||
$domain: String
|
||||
$page: Int
|
||||
$limit: Int
|
||||
) {
|
||||
reports(status: $status, domain: $domain, page: $page, limit: $limit) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
|
@ -11,6 +11,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||
$tags: String
|
||||
$term: String
|
||||
$type: EventType
|
||||
$category: String
|
||||
$beginsOn: DateTime
|
||||
$endsOn: DateTime
|
||||
$eventPage: Int
|
||||
@ -23,6 +24,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||
tags: $tags
|
||||
term: $term
|
||||
type: $type
|
||||
category: $category
|
||||
beginsOn: $beginsOn
|
||||
endsOn: $endsOn
|
||||
page: $eventPage
|
||||
@ -38,6 +40,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||
id
|
||||
url
|
||||
}
|
||||
status
|
||||
tags {
|
||||
...TagFragment
|
||||
}
|
||||
@ -108,6 +111,7 @@ export const INTERACT = gql`
|
||||
title
|
||||
uuid
|
||||
beginsOn
|
||||
status
|
||||
picture {
|
||||
id
|
||||
url
|
||||
|
@ -209,14 +209,30 @@ export const UPDATE_ACTIVITY_SETTING = gql`
|
||||
`;
|
||||
|
||||
export const LIST_USERS = gql`
|
||||
query ListUsers($email: String, $page: Int, $limit: Int) {
|
||||
users(email: $email, page: $page, limit: $limit) {
|
||||
query ListUsers(
|
||||
$email: String
|
||||
$currentSignInIp: String
|
||||
$page: Int
|
||||
$limit: Int
|
||||
$sort: SortableUserField
|
||||
$direction: SortDirection
|
||||
) {
|
||||
users(
|
||||
email: $email
|
||||
currentSignInIp: $currentSignInIp
|
||||
page: $page
|
||||
limit: $limit
|
||||
sort: $sort
|
||||
direction: $direction
|
||||
) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
email
|
||||
locale
|
||||
confirmedAt
|
||||
currentSignInIp
|
||||
currentSignInAt
|
||||
disabled
|
||||
actors {
|
||||
...ActorFragment
|
||||
|
1022
js/src/i18n/ar.json
1022
js/src/i18n/ar.json
File diff suppressed because it is too large
Load Diff
1096
js/src/i18n/be.json
1096
js/src/i18n/be.json
File diff suppressed because it is too large
Load Diff
1233
js/src/i18n/bn.json
1233
js/src/i18n/bn.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1151
js/src/i18n/cs.json
1151
js/src/i18n/cs.json
File diff suppressed because it is too large
Load Diff
1263
js/src/i18n/cy.json
Normal file
1263
js/src/i18n/cy.json
Normal file
File diff suppressed because it is too large
Load Diff
222
js/src/i18n/da.json
Normal file
222
js/src/i18n/da.json
Normal file
@ -0,0 +1,222 @@
|
||||
{
|
||||
"A user-friendly, emancipatory and ethical tool for gathering, organising, and mobilising.": "Et brugervenligt, befriende og etisk værktøj for at samles, organisere og mobilisere.",
|
||||
"A validation email was sent to {email}": "En godkendelsesemail er blevet sendt til {email}",
|
||||
"Abandon editing": "Afbryd redigering",
|
||||
"About": "Om",
|
||||
"About Mobilizon": "Om Mobilizon",
|
||||
"About this event": "Om denne begivenhed",
|
||||
"About this instance": "Om denne udbyder",
|
||||
"Accepted": "Accepteret",
|
||||
"Account": "Konto",
|
||||
"Add": "Tilføj",
|
||||
"Add a note": "Tilføj et notat",
|
||||
"Add an address": "Tilføj en addresse",
|
||||
"Add an instance": "Tilføj en udbyder",
|
||||
"Add some tags": "Tilføj nogle nøgleord",
|
||||
"Add to my calendar": "Tilføj til min kalender",
|
||||
"Additional comments": "Yderligere kommentarer",
|
||||
"Admin": "Administrator",
|
||||
"Admin settings successfully saved.": "Administrator indstillinger er blevet gemt.",
|
||||
"Administration": "Administrering",
|
||||
"All the places have already been taken": "Alle pladserne er allerede optaget",
|
||||
"Allow registrations": "Tillad registrering",
|
||||
"Anonymous participant": "Anonym deltager",
|
||||
"Anonymous participants will be asked to confirm their participation through e-mail.": "Anonyme deltagere vil blive bedt om at bekræfte deres deltagelse via e-mail.",
|
||||
"Anonymous participations": "Anonyme deltagelser",
|
||||
"Are you really sure you want to delete your whole account? You'll lose everything. Identities, settings, events created, messages and participations will be gone forever.": "Er du helt sikker på at du vil slette hele din konto? Alt vil forsvinde. Identiteter, indstillinger, skabte begivenheder, beskeder og deltagelser vil være borte for evigt.",
|
||||
"Are you sure you want to <b>delete</b> this comment? This action cannot be undone.": "Er du sikker på at du vil <b>slette</b> kommentaren? Denne handling kan ikke fortrydes.",
|
||||
"Are you sure you want to <b>delete</b> this event? This action cannot be undone. You may want to engage the discussion with the event creator or edit its event instead.": "Er du sikker på at du vil <b>slette</b> begivenheden? Denne handling kan ikke fortrydes. Du kan overveje at snakke med begivenhedens skaber eller at redigere begivenheden i stedet.",
|
||||
"Are you sure you want to cancel the event creation? You'll lose all modifications.": "Er du sikker på at du vil annullere at skabe begivenheden? Alle ændringer vil gå tabt.",
|
||||
"Are you sure you want to cancel the event edition? You'll lose all modifications.": "Er du sikker på at du vil annullere at redigere begivenheden? Alle ændringer vil gå tabt.",
|
||||
"Are you sure you want to cancel your participation at event \"{title}\"?": "Er du sikker på at du vil annullere din deltagelse i begivenheden \"{title}\"?",
|
||||
"Are you sure you want to delete this event? This action cannot be reverted.": "Er du sikker på du vil slette begivenheden? Denne handling kan ikke fortrydes.",
|
||||
"Avatar": "Avatar",
|
||||
"Back to previous page": "Tilbage til forrige side",
|
||||
"Before you can login, you need to click on the link inside it to validate your account.": "Før du kan logge ind skal du klikke på linket i den for at bekræfte din konto.",
|
||||
"By {username}": "Af {username}",
|
||||
"Cancel": "Annuller",
|
||||
"Cancel anonymous participation": "Annuller anonym deltagelse",
|
||||
"Cancel creation": "Annuller skabelse",
|
||||
"Cancel edition": "Annuller redigering",
|
||||
"Cancel my participation request…": "Annuller min anmodning om deltagelse…",
|
||||
"Cancel my participation…": "Annuller min deltagelse…",
|
||||
"Cancelled: Won't happen": "Afbrudt: Sker ikke",
|
||||
"Change": "Ændre",
|
||||
"Change my email": "Skift email",
|
||||
"Change my identity…": "Ændre min identitet…",
|
||||
"Change my password": "Skift kodeord",
|
||||
"Clear": "Ryd",
|
||||
"Click to upload": "Klik for at uploade",
|
||||
"Close": "Luk",
|
||||
"Close comments for all (except for admins)": "Luk kommentarer for alle (undtagen administratorer)",
|
||||
"Closed": "Lukket",
|
||||
"Comment deleted": "Kommentar slettet",
|
||||
"Comment from @{username} reported": "Kommentaren fra @{username} er blevet indberettet",
|
||||
"Comments": "Kommentarer",
|
||||
"Confirm my participation": "Bekræft min deltagelse",
|
||||
"Confirmed: Will happen": "Bekræftet: Kommer til at ske",
|
||||
"Continue editing": "Fortsæt med at redigere",
|
||||
"Country": "Land",
|
||||
"Create": "Skab",
|
||||
"Create a new event": "Lav en ny begivenhed",
|
||||
"Create a new group": "Lav en ny gruppe",
|
||||
"Create a new identity": "Lav en ny identitet",
|
||||
"Create group": "Skab en gruppe",
|
||||
"Create my event": "Skab min begivenhed",
|
||||
"Create my group": "Skab min gruppe",
|
||||
"Create my profile": "Skab min profil",
|
||||
"Create token": "Skab token",
|
||||
"Current identity has been changed to {identityName} in order to manage this event.": "Den aktive identitet er blevet ændret til {identityName} for at håndtere denne begivenhed.",
|
||||
"Current page": "Nuværende side",
|
||||
"Custom": "Tilpasset",
|
||||
"Custom URL": "Tilpasset addresse",
|
||||
"Custom text": "Tilpasset tekst",
|
||||
"Dashboard": "Dashboard",
|
||||
"Date": "Dato",
|
||||
"Date and time settings": "Dato og tidsinstillinger",
|
||||
"Date parameters": "Datoparametre",
|
||||
"Default": "Standard",
|
||||
"Delete": "Slet",
|
||||
"Delete Comment": "Slet kommentar",
|
||||
"Delete Event": "Slet begivenhed",
|
||||
"Delete account": "Slet konto",
|
||||
"Delete event": "Slet begivenhed",
|
||||
"Delete everything": "Slet alt",
|
||||
"Delete my account": "Slet min konto",
|
||||
"Delete this identity": "Slet denne identitet",
|
||||
"Delete your identity": "Slet din identitet",
|
||||
"Delete {eventTitle}": "Slet {eventTitle}",
|
||||
"Delete {preferredUsername}": "Slet {preferredUsername}",
|
||||
"Deleting comment": "Sletter kommentar",
|
||||
"Deleting event": "Sletter begivenhed",
|
||||
"Deleting my account will delete all of my identities.": "Hvis jeg sletter min konto, bliver alle mine identiteter slettet.",
|
||||
"Deleting your Mobilizon account": "Sletter din Mobilizon konto",
|
||||
"Description": "Beskrivelse",
|
||||
"Display name": "Viste navn",
|
||||
"Display participation price": "Vis pris for deltagelse",
|
||||
"Domain": "Domæne",
|
||||
"Draft": "Kladde",
|
||||
"Drafts": "Kladder",
|
||||
"Edit": "Rediger",
|
||||
"Eg: Stockholm, Dance, Chess…": "F.eks.: Stockholm, Dans, Skak…",
|
||||
"Either on the {instance} instance or on another instance.": "Enten på {instance} udbyderen eller på en anden udbyder.",
|
||||
"Either the account is already validated, either the validation token is incorrect.": "Enten er kontoen allerede godkendt, eller valideringskoden forkert.",
|
||||
"Either the email has already been changed, either the validation token is incorrect.": "Enten er emailadressen allerede blevet ændret, eller valideringskoden er forkert.",
|
||||
"Either the participation request has already been validated, either the validation token is incorrect.": "Enten er deltagelsesanmodningen allerede blevet godkendt, eller valideringskoden er forkert.",
|
||||
"Email": "Email",
|
||||
"Ends on…": "Slutter…",
|
||||
"Enter the link URL": "Indtast linket",
|
||||
"Error while changing email": "Fejl under ændring af emailadresse",
|
||||
"Error while validating account": "Fejl under godkendelse af konto",
|
||||
"Error while validating participation request": "Fejl under godkendelse af deltagelsesanmodning",
|
||||
"Event": "Begivenhed",
|
||||
"Event already passed": "Begivenheden er ovre",
|
||||
"Event cancelled": "Begivenheden er aflyst",
|
||||
"Event creation": "Skabelse af begivenhed",
|
||||
"Event edition": "Redigering af begivenhed",
|
||||
"Event list": "Liste af begivenheder",
|
||||
"Event page settings": "Indstillinger for begivenhedens side",
|
||||
"Event to be confirmed": "Begivenheden skal bekræftes",
|
||||
"Event {eventTitle} deleted": "Begivenheden {eventTitle} blev slettet",
|
||||
"Event {eventTitle} reported": "Begivenheden {eventTitle} blev indmeldt",
|
||||
"Events": "Begivenheder",
|
||||
"Ex: mobilizon.fr": "F.eks: mobilizon.fr",
|
||||
"Explore": "Udforsk",
|
||||
"Failed to save admin settings": "Kunne ikke gemme admin indstillinger",
|
||||
"Featured events": "Udvalgte begivenheder",
|
||||
"Federation": "Federation",
|
||||
"Find an address": "Find en adresse",
|
||||
"Find an instance": "Find en udbyder",
|
||||
"Followers": "Følgere",
|
||||
"Followings": "Følger",
|
||||
"For instance: London, Taekwondo, Architecture…": "For eksempel: London, Taekwondo, Arkitektur…",
|
||||
"Forgot your password ?": "Glemt dit kodeord?",
|
||||
"From the {startDate} at {startTime} to the {endDate}": "Fra d. {startDate} kl. {startTime} til d. {endDate}",
|
||||
"From the {startDate} at {startTime} to the {endDate} at {endTime}": "Fra d. {startDate} kl. {startTime} til d. {endDate} kl. {endTime}",
|
||||
"From the {startDate} to the {endDate}": "Fra d. {startDate} til d. {endDate}",
|
||||
"Gather ⋅ Organize ⋅ Mobilize": "Samles ⋅ Organiser ⋅ Mobiliser",
|
||||
"General": "Generelt",
|
||||
"General information": "Generel information",
|
||||
"Getting location": "Henter placering",
|
||||
"Go": "Gå",
|
||||
"Group name": "Gruppenavn",
|
||||
"Group {displayName} created": "Gruppen {displayName} er oprettet",
|
||||
"Groups": "Grupper",
|
||||
"Headline picture": "Hovedbillede",
|
||||
"Hide replies": "Skjul svar",
|
||||
"I create an identity": "Jeg skaber en identitet",
|
||||
"I don't have a Mobilizon account": "Jeg har ikke en Mobilizon konto",
|
||||
"I have a Mobilizon account": "Jeg har en Mobilizon konto",
|
||||
"I have an account on another Mobilizon instance.": "Jeg har en konto på en anden Mobilizon udbyder.",
|
||||
"I participate": "Jeg deltager",
|
||||
"I want to allow people to participate without an account.": "Jeg vil lade personer uden en konto deltage.",
|
||||
"I want to approve every participation request": "Jeg vil godkende for alle deltagelsesanmodninger",
|
||||
"Identity {displayName} created": "Identiteten {displayName} er skabt",
|
||||
"Identity {displayName} deleted": "Identiteten {displayName} er slettet",
|
||||
"Identity {displayName} updated": "Identiteten {displayName} er opdateret",
|
||||
"If an account with this email exists, we just sent another confirmation email to {email}": "Hvis en konto med denne emailadresse findes, har vi lige sendt en bekræftelsesmail til {email}",
|
||||
"If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "Hvis denne identitet er den eneste administrator af nogle grupper, skal du slette grupperne før du kan slette identiteten.",
|
||||
"If you want, you may send a message to the event organizer here.": "Hvis du vil kan du sende en besked til begivenhedens arrangør her.",
|
||||
"Instance Name": "Udbyderens navn",
|
||||
"Instance Terms": "Udbyderens brugsvilkår",
|
||||
"Instance Terms Source": "Kilde til udbyderens vilkår",
|
||||
"Instance Terms URL": "Adresse til udbyderens vilkår",
|
||||
"Instance settings": "Indstillinger for udbyderen",
|
||||
"Instances": "Udbydere",
|
||||
"Join <b>{instance}</b>, a Mobilizon instance": "Bliv medlem af <b>{instance}</b>, en Mobilizon udbyder",
|
||||
"Last published event": "Nyeste begivenhed",
|
||||
"Last week": "Sidste uge",
|
||||
"Learn more": "Lær mere",
|
||||
"Learn more about Mobilizon": "Lær mere om Mobilizon",
|
||||
"Leave event": "Forlad begivenhed",
|
||||
"Leaving event \"{title}\"": "Forlader begivenheden \"{title}\"",
|
||||
"License": "Licens",
|
||||
"Limited number of places": "Begrænset antal pladser",
|
||||
"Load more": "Indlæs flere",
|
||||
"Locality": "Sted",
|
||||
"Log in": "Log ind",
|
||||
"Log out": "Log ud",
|
||||
"Login": "Log ind",
|
||||
"Login on Mobilizon!": "Log ind på Mobilizon!",
|
||||
"Login on {instance}": "Log ind på {instance}",
|
||||
"Manage participations": "Håndter deltagelser",
|
||||
"Mark as resolved": "Marker som løst",
|
||||
"Members": "Medlemmer",
|
||||
"Message": "Besked",
|
||||
"Mobilizon is a federated network. You can interact with this event from a different server.": "Mobilizon er et føderalt netværk. Du kan interagere med denne begivenhed fra andre udbydere.",
|
||||
"Moderated comments (shown after approval)": "Modererede kommentarer (vist efter godkendelse)",
|
||||
"Moderation": "Moderering",
|
||||
"Moderation log": "Moderationslog",
|
||||
"My account": "Min konto",
|
||||
"My events": "Mine begivenheder",
|
||||
"My identities": "Mine identiteter",
|
||||
"Name": "Navn",
|
||||
"New email": "Ny email",
|
||||
"New note": "Nyt notat",
|
||||
"New password": "Nyt kodeord",
|
||||
"New profile": "Ny profil",
|
||||
"Next page": "Næste side",
|
||||
"No address defined": "Ingen adresse givet",
|
||||
"No closed reports yet": "Ingen behandlede indmeldinger endnu",
|
||||
"No comment": "Ingen kommentar",
|
||||
"No comments yet": "Ingen kommentarer endnu",
|
||||
"No end date": "Ingen slutdato",
|
||||
"No events found": "Ingen begivenheder fundet",
|
||||
"No group found": "Ingen gruppe fundet",
|
||||
"No groups found": "Ingen grupper fundet",
|
||||
"No instance follows your instance yet.": "Ingen udbydere følger din udbyder endnu.",
|
||||
"No instance to approve|Approve instance|Approve {number} instances": "Ingen udbydere at godkende|Godkend udbyder|Godkend {number} udbydere",
|
||||
"No instance to reject|Reject instance|Reject {number} instances": "Ingen udbydere at afvise|Afvis udbyder|Afvis {number} udbydere",
|
||||
"No instance to remove|Remove instance|Remove {number} instances": "Ingen udbydere at fjerne|Fjern udbyder|Fjern {number} udbydere",
|
||||
"No message": "Ingen besked",
|
||||
"No open reports yet": "Ingen åbne indmeldinger endnu",
|
||||
"No participant to approve|Approve participant|Approve {number} participants": "Ingen deltagere at godkende|Godkend deltager|Godkend {number} deltagere",
|
||||
"No participant to reject|Reject participant|Reject {number} participants": "Ingen deltagere at afvise|Afvis deltagere|Afvis {number} deltagere",
|
||||
"No resolved reports yet": "Ingen løste indmeldinger endnu",
|
||||
"No results for \"{queryText}\"": "Ingen resultater for \"{queryText}\"",
|
||||
"Notes": "Notater",
|
||||
"Number of places": "Antal steder",
|
||||
"OK": "OK",
|
||||
"Old password": "Gammelt kodeord",
|
||||
"Please do not use it in any real way.": "Brug det venligst ikke som andet end en prøve."
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -340,7 +340,6 @@
|
||||
"Transfer to {outsideDomain}": "Transfer to {outsideDomain}",
|
||||
"Type": "Type",
|
||||
"URL": "URL",
|
||||
"Unfortunately, this instance isn't opened to registrations": "Unfortunately, this instance isn't opened to registrations",
|
||||
"Unfortunately, your participation request was rejected by the organizers.": "Unfortunately, your participation request was rejected by the organizers.",
|
||||
"Unknown actor": "Unknown actor",
|
||||
"Unknown error.": "Unknown error.",
|
||||
@ -1253,5 +1252,83 @@
|
||||
"The membership request from {profile} was rejected": "The membership request from {profile} was rejected",
|
||||
"The member was approved": "The member was approved",
|
||||
"Emails usually don't contain capitals, make sure you haven't made a typo.": "Emails usually don't contain capitals, make sure you haven't made a typo.",
|
||||
"To follow groups and be informed of their latest events": "To follow groups and be informed of their latest events"
|
||||
}
|
||||
"To follow groups and be informed of their latest events": "To follow groups and be informed of their latest events",
|
||||
"No group member found": "No group member found",
|
||||
"This group was not found": "This group was not found",
|
||||
"Back to group list": "Back to group list",
|
||||
"This profile was not found": "This profile was not found",
|
||||
"Back to profile list": "Back to profile list",
|
||||
"This user was not found": "This user was not found",
|
||||
"Back to user list": "Back to user list",
|
||||
"Stop following instance": "Stop following instance",
|
||||
"Follow instance": "Follow instance",
|
||||
"Accept follow": "Accept follow",
|
||||
"Reject follow": "Reject follow",
|
||||
"This instance doesn't follow yours.": "This instance doesn't follow yours.",
|
||||
"Only Mobilizon instances can be followed": "",
|
||||
"Follow a new instance": "Follow a new instance",
|
||||
"Follow status": "Follow status",
|
||||
"All": "All",
|
||||
"Following": "Following",
|
||||
"Followed": "Followed",
|
||||
"Followed, pending response": "Followed, pending response",
|
||||
"Follows us": "Follows us",
|
||||
"Follows us, pending approval": "Follows us, pending approval",
|
||||
"No instance found.": "No instance found.",
|
||||
"No instances match this filter. Try resetting filter fields?": "No instances match this filter. Try resetting filter fields?",
|
||||
"You haven't interacted with other instances yet.": "You haven't interacted with other instances yet.",
|
||||
"mobilizon-instance.tld": "mobilizon-instance.tld",
|
||||
"Report status": "Report status",
|
||||
"access the corresponding account": "access the corresponding account",
|
||||
"Organized events": "Organized events",
|
||||
"Memberships": "Memberships",
|
||||
"This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.": "This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.",
|
||||
"Total number of participations": "Total number of participations",
|
||||
"Uploaded media total size": "Uploaded media total size",
|
||||
"0 Bytes": "0 Bytes",
|
||||
"Change email": "Change email",
|
||||
"Confirm user": "Confirm user",
|
||||
"Change role": "Change role",
|
||||
"The user has been disabled": "The user has been disabled",
|
||||
"This user doesn't have any profiles": "This user doesn't have any profiles",
|
||||
"Edit user email": "Edit user email",
|
||||
"Change user email": "Change user email",
|
||||
"Previous email": "Previous email",
|
||||
"Notify the user of the change": "Notify the user of the change",
|
||||
"Change user role": "Change user role",
|
||||
"Suspend the account?": "Suspend the account?",
|
||||
"Do you really want to suspend this account? All of the user's profiles will be deleted.": "Do you really want to suspend this account? All of the user's profiles will be deleted.",
|
||||
"Suspend the account": "Suspend the account",
|
||||
"No user matches the filter": "No user matches the filter",
|
||||
"new@email.com": "new@email.com",
|
||||
"Other users with the same email domain": "Other users with the same email domain",
|
||||
"Other users with the same IP address": "Other users with the same IP address",
|
||||
"IP Address": "IP Address",
|
||||
"Last seen on": "Last seen on",
|
||||
"No user matches the filters": "No user matches the filters",
|
||||
"Reset filters": "Reset filters",
|
||||
"Category": "Category",
|
||||
"Select a category": "Select a category",
|
||||
"Any category": "Any category",
|
||||
"We collect your feedback and the error information in order to improve this service.": "We collect your feedback and the error information in order to improve this service.",
|
||||
"What happened?": "What happened?",
|
||||
"I've clicked on X, then on Y": "I've clicked on X, then on Y",
|
||||
"Send feedback": "Send feedback",
|
||||
"Sorry, we wen't able to save your feedback. Don't worry, we'll try to fix this issue anyway.": "Sorry, we wen't able to save your feedback. Don't worry, we'll try to fix this issue anyway.",
|
||||
"return to the homepage": "return to the homepage",
|
||||
"Thanks a lot, your feedback was submitted!": "Thanks a lot, your feedback was submitted!",
|
||||
"You may also:": "You may also:",
|
||||
"You may now close this page or {return_to_the_homepage}.": "You may now close this page or {return_to_the_homepage}.",
|
||||
"This group is a remote group, it's possible the original instance has more informations.": "This group is a remote group, it's possible the original instance has more informations.",
|
||||
"View the group profile on the original instance": "View the group profile on the original instance",
|
||||
"View past events": "View past events",
|
||||
"Get informed of the upcoming public events": "Get informed of the upcoming public events",
|
||||
"Join": "Join",
|
||||
"Become part of the community and start organizing events": "Become part of the community and start organizing events",
|
||||
"Follow requests will be approved by a group moderator": "Follow requests will be approved by a group moderator",
|
||||
"Follow request pending approval": "Follow request pending approval",
|
||||
"Your membership is pending approval": "Your membership is pending approval",
|
||||
"Activate notifications": "Activate notifications",
|
||||
"Deactivate notifications": "Deactivate notifications",
|
||||
"Membership requests will be approved by a group moderator": "Membership requests will be approved by a group moderator"
|
||||
}
|
1253
js/src/i18n/eo.json
1253
js/src/i18n/eo.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1235
js/src/i18n/eu.json
1235
js/src/i18n/eu.json
File diff suppressed because it is too large
Load Diff
1149
js/src/i18n/fa.json
1149
js/src/i18n/fa.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,8 +6,8 @@
|
||||
"+ Add a resource": "+ Cuir goireas ris",
|
||||
"+ Create a post": "+ Cruthaich post",
|
||||
"+ Create an event": "+ Cruthaich tachartas",
|
||||
"+ Post a public message": "+ Postaich teachdaireachd phoblach",
|
||||
"+ Start a discussion": "+ Tòisich air deasbad",
|
||||
"0 Bytes": "0 baidht",
|
||||
"<b>{contact}</b> will be displayed as contact.": "Thèid <b>{contact}</b> a shealltain mar neach-conaltraidh.|Thèid <b>{contact}</b> a shealltain mar luchd-conaltraidh.|Thèid <b>{contact}</b> a shealltain mar luchd-conaltraidh.|Thèid <b>{contact}</b> a shealltain mar luchd-conaltraidh.",
|
||||
"@{group}": "@{group}",
|
||||
"@{username}": "@{username}",
|
||||
@ -45,6 +45,7 @@
|
||||
"About this instance": "Mun ionstans seo",
|
||||
"About {instance}": "Mu {instance}",
|
||||
"Accept": "Gabh ris",
|
||||
"Accept follow": "Gabh ris an iarrtas leantainn",
|
||||
"Accepted": "Air a ghabhail ris",
|
||||
"Accessibility": "So-ruigsinneachd",
|
||||
"Accessible only by link": "Inntrigeadh le ceangal a-mhàin",
|
||||
@ -54,6 +55,7 @@
|
||||
"Account settings": "Roghainnean a’ chunntais",
|
||||
"Actions": "Gnìomhan",
|
||||
"Activate browser push notifications": "Gnìomhaich brathan putaidh a’ bhrabhsair",
|
||||
"Activate notifications": "Gnìomhaich na brathan",
|
||||
"Activated": "An gnìomh",
|
||||
"Active": "Gnìomhach",
|
||||
"Activity": "Gnìomhachd",
|
||||
@ -61,7 +63,6 @@
|
||||
"Add": "Cuir ris",
|
||||
"Add / Remove…": "Cuir ris / Thoir air falbh…",
|
||||
"Add a contact": "Cuir fiosrachadh conaltraidh ris",
|
||||
"Add a group": "Cuir buidheann ris",
|
||||
"Add a new post": "Cuir post ùr ris",
|
||||
"Add a note": "Cuir nòta ris",
|
||||
"Add a todo": "Cuir rud ri dhèanamh ris",
|
||||
@ -79,6 +80,7 @@
|
||||
"Admin settings successfully saved.": "Chaidh roghainnean an rianaire a shàbhaladh.",
|
||||
"Administration": "Rianachd",
|
||||
"Administrator": "Rianaire",
|
||||
"All": "Na h-uile",
|
||||
"All activities": "A h-uile gnìomhachd",
|
||||
"All good, let's continue!": "Tha seo dòigheil, leanamaid oirnn!",
|
||||
"All the places have already been taken": "Chan eil àite saor air fhàgail",
|
||||
@ -102,6 +104,7 @@
|
||||
"Anonymous participant": "Freastalaiche gun ainm",
|
||||
"Anonymous participants will be asked to confirm their participation through e-mail.": "Thèid iarraidh air freastalaichean gun ainm gun dearbh iad an com-pàirteachadh air a’ phost-d.",
|
||||
"Anonymous participations": "Com-pàirteachaidhean gun ainm",
|
||||
"Any category": "Roinn-seòrsa sam bith",
|
||||
"Any day": "Latha sam bith",
|
||||
"Any type": "Seòrsa sam bith",
|
||||
"Anyone can join freely": "Faodaidh neach sam bith a dhol an sàs ann gu saor",
|
||||
@ -128,9 +131,13 @@
|
||||
"Atom feed for events and posts": "Inbhir Atom dha na tachartasan is postaichean",
|
||||
"Attending": "An làthair",
|
||||
"Avatar": "Avatar",
|
||||
"Back to group list": "Air ais gu liosta nam buidhnean",
|
||||
"Back to previous page": "Air ais dhan duilleag roimhpe",
|
||||
"Back to profile list": "Air ais gu liosta nam pròifilean",
|
||||
"Back to top": "Air ais gun bhàrr",
|
||||
"Back to user list": "Air ais gu liosta nan cleachdaichean",
|
||||
"Banner": "Bratach",
|
||||
"Become part of the community and start organizing events": "Faigh ballrachd sa choimhearsnachd agus tòisich air tachartasan a chur air dòigh",
|
||||
"Before you can login, you need to click on the link inside it to validate your account.": "Mus urrainn dhut clàradh a-steach, feumaidh tu briogadh air a’ cheangal ’na broinn gus an cunntas agad a dhearbhadh.",
|
||||
"Begins on": "Tòisichidh e aig",
|
||||
"Big Blue Button": "Big Blue Button",
|
||||
@ -140,7 +147,6 @@
|
||||
"Browser notifications": "Brathan a’ bhrabhsair",
|
||||
"Bullet list": "Liosta pheilearaichte",
|
||||
"By others": "Le daoine eile",
|
||||
"By {author}": "Le {author}",
|
||||
"By {group}": "Le {group}",
|
||||
"By {username}": "Le {username}",
|
||||
"Can be an email or a link, or just plain text.": "’S urrainn dhut post-d no ceangal no teacsa lom a cleachdadh.",
|
||||
@ -155,11 +161,16 @@
|
||||
"Cancel my participation…": "Sguir dhen chom-pàirteachadh agam…",
|
||||
"Cancelled": "Chaidh a chur gu neoini",
|
||||
"Cancelled: Won't happen": "Sguireadh dheth: Cha tachair seo",
|
||||
"Category": "Roinn-seòrsa",
|
||||
"Change": "Atharraich",
|
||||
"Change email": "Atharraich am post-d",
|
||||
"Change my email": "Atharraich am post-d agam",
|
||||
"Change my identity…": "Atharraich an dearbh-aithne agam…",
|
||||
"Change my password": "Atharraich am facal-faire agam",
|
||||
"Change role": "Atharraich an dreuchd",
|
||||
"Change timezone": "Atharraich an roinn-tìde",
|
||||
"Change user email": "Atharraich post-d a’ chleachdaiche",
|
||||
"Change user role": "Atharraich dreuchd a’ chleachdaiche",
|
||||
"Check your inbox (and your junk mail folder).": "Thoir sùil air a’ bhogsa a-steach agad (’s air a’ phasgan airson puist-d thruilleis).",
|
||||
"Choose the source of the instance's Privacy Policy": "Tagh tùs do phoileasaidh prìobhaideachd an ionstans",
|
||||
"Choose the source of the instance's Terms": "Tagh tùs do theirmichean an ionstans",
|
||||
@ -184,7 +195,8 @@
|
||||
"Confirm my participation": "Dearbh an com-pàirteachadh agam",
|
||||
"Confirm my particpation": "Dearbh an com-pàirteachadh agam",
|
||||
"Confirm participation": "Dearbh an com-pàirteachadh",
|
||||
"Confirmed": "Air a dhearbhachadh",
|
||||
"Confirm user": "Dearbh an cleachdaiche",
|
||||
"Confirmed": "Air a dhearbhadh",
|
||||
"Confirmed at": "Chaidh a dhearbhachadh",
|
||||
"Confirmed: Will happen": "Air dearbhadh: Tachraidh seo",
|
||||
"Congratulations, your account is now created!": "Meal do naidheachd, chaidh an cunntas agad a chruthachadh!",
|
||||
@ -231,6 +243,7 @@
|
||||
"Date and time": "Ceann-là ’s àm",
|
||||
"Date and time settings": "Roghainnean a’ chinn-là ’s an ama",
|
||||
"Date parameters": "Paramadairean a’ chinn-là",
|
||||
"Deactivate notifications": "Cuir na brathan à gnìomh",
|
||||
"Decline": "Diùlt",
|
||||
"Decrease": "Lùghdaich",
|
||||
"Default": "Bun-roghainn",
|
||||
@ -268,6 +281,7 @@
|
||||
"Displayed nickname": "Am far-ainm a chithear",
|
||||
"Displayed on homepage and meta tags. Describe what Mobilizon is and what makes this instance special in a single paragraph.": "Thèid seo a shealltainn air an duilleag-dhachaigh agus am measg nan tagaichean meata. Mìnich dè th’ ann am Mobilizon agus dè tha sònraichte mun ionstans agad ann an earrann a-mhàin.",
|
||||
"Do not receive any mail": "Na faigh post-d idir",
|
||||
"Do you really want to suspend this account? All of the user's profiles will be deleted.": "A bheil thu cinnteach gu bheil thu airson an cunntas seo a chur à rèim? Thèid gach pròifil a’ chleachdaiche a sguabadh às.",
|
||||
"Do you wish to {create_event} or {explore_events}?": "A bheil thu airson {create_event} no {explore_events}?",
|
||||
"Do you wish to {create_group} or {explore_groups}?": "A bheil thu airson {create_group} no {explore_groups}?",
|
||||
"Does the event needs to be confirmed later or is it cancelled?": "Am bi an tachartas feumach air dearbhadh uaireigin eile no an deach a chur dheth?",
|
||||
@ -279,6 +293,7 @@
|
||||
"Edit": "Deasaich",
|
||||
"Edit post": "Deasaich am post",
|
||||
"Edit profile {profile}": "Deasaich pròifil {profile}",
|
||||
"Edit user email": "Deasaich post-d a’ chleachdaiche",
|
||||
"Edited {ago}": "Air a dheasachadh {ago}",
|
||||
"Edited {relative_time} ago": "Chaidh a dheasachadh {relative_time} air ais",
|
||||
"Eg: Stockholm, Dance, Chess…": "M.e.: Steòrnabhagh, Cèilidh, Spòrs…",
|
||||
@ -290,7 +305,6 @@
|
||||
"Element value": "Luach na h-eileamaid",
|
||||
"Email": "Post-d",
|
||||
"Email address": "Seòladh puist-d",
|
||||
"Email notifications": "Brathan puist-d",
|
||||
"Email validate": "Dearbh am post-d",
|
||||
"Emails usually don't contain capitals, make sure you haven't made a typo.": "Cha bhi litrichean mòra ann am post-d mar as trice, dèan cinnteach nach do rinn thu mearachd sgrìobhaidh.",
|
||||
"Enabled": "An comas",
|
||||
@ -354,11 +368,21 @@
|
||||
"Find or add an element": "Lorg no cuir eileamaid ris",
|
||||
"First steps": "Na ciad ceuman",
|
||||
"Follow": "Lean air",
|
||||
"Follow a new instance": "Lean air ionstans ùr",
|
||||
"Follow instance": "Lean air an ionstans",
|
||||
"Follow request pending approval": "Iarrtas leantainn ri aontachadh",
|
||||
"Follow requests will be approved by a group moderator": "Thèid aontachadh ri iarrtasan leantainn le maor a’ bhuidhinn",
|
||||
"Follow status": "Staid na leantainn",
|
||||
"Followed": "’Ga leantainn leinne",
|
||||
"Followed, pending response": "’Ga leantainn leinne, a’ feitheamh air freagairt",
|
||||
"Follower": "Neach-leantainn",
|
||||
"Followers": "Luchd-leantainn",
|
||||
"Followers will receive new public events and posts.": "Gheibh an luchd-leantainn tachartasan is postaichean poblach.",
|
||||
"Following": "A’ leantainn",
|
||||
"Following the group will allow you to be informed of the {group_upcoming_public_events}, whereas joining the group means you will {access_to_group_private_content_as_well}, including group discussions, group resources and members-only posts.": "Ma leanas tu air a’ bhuidheann, gheibh thu fiosrachadh mu {group_upcoming_public_events} ach ma gheibh thu ballrachd sa bhuidheann, gheibh thu {access_to_group_private_content_as_well}, a’ gabhail a-staigh deasbadan a’ bhuidhinn, goireasan a’ bhuidhinn agus postaichean a tha do bhuill a-mhàin.",
|
||||
"Followings": "A’ leantainn",
|
||||
"Follows us": "A’ leantainn oirnn",
|
||||
"Follows us, pending approval": "A’ leantainn oirnn, a’ feitheamh air dearbhadh",
|
||||
"For instance: London": "Mar eisimpleir: Glaschu",
|
||||
"For instance: London, Taekwondo, Architecture…": "Mar eisimpleir: Glaschu, Camanachd, Ailtireachd…",
|
||||
"Forgot your password ?": "Na dhìochuimhnich thu am facal-faire agad?",
|
||||
@ -375,6 +399,7 @@
|
||||
"General information": "Fiosrachadh coitcheann",
|
||||
"General settings": "Roghainnean coitcheann",
|
||||
"Geolocation was not determined in time.": "Cha deach leis a’ gheò-lorgadh ri àm.",
|
||||
"Get informed of the upcoming public events": "Faigh naidheachdan mu thachartasan poblach ri thighinn",
|
||||
"Getting location": "A’ faighinn an ionaid",
|
||||
"Getting there": "Mar a gheibh thu ann",
|
||||
"Glossary": "Briathrachan",
|
||||
@ -419,8 +444,10 @@
|
||||
"I want to approve every participation request": "Tha mi airson aontachadh ris a h-uile iarrtas air com-pàirteachadh",
|
||||
"I've been mentionned in a comment under an event": "Chaidh iomradh a thoirt orm ann am beachd fo thachartas",
|
||||
"I've been mentionned in a group discussion": "Chaidh iomradh a thoirt orm ann an deasbad buidhinn",
|
||||
"I've clicked on X, then on Y": "Briog mi air X ’s an uairsin air Y",
|
||||
"ICS feed for events": "Inbhir ICS dha na tachartasan",
|
||||
"ICS/WebCal Feed": "Inbhir ICS/WebCal",
|
||||
"IP Address": "Seòladh IP",
|
||||
"Identities": "Dearbh-aithnean",
|
||||
"Identity {displayName} created": "Chaidh an dearbh-aithne {displayName} a chruthachadh",
|
||||
"Identity {displayName} deleted": "Chaidh an dearbh-aithne {displayName} a sguabadh às",
|
||||
@ -451,7 +478,6 @@
|
||||
"Instance administrator": "Rianaire ionstans",
|
||||
"Instance configuration": "Rèiteachadh an ionstans",
|
||||
"Instance feeds": "Inbhirean an ionstans",
|
||||
"Instance follows": "Ionstansan ’gan leantainn",
|
||||
"Instance languages": "Cànain an ionstans",
|
||||
"Instance rules": "Riaghailtean an ionstans",
|
||||
"Instance settings": "Roghainnean an ionstans",
|
||||
@ -467,6 +493,7 @@
|
||||
"It is possible that the content is not accessible on this instance, because this instance has blocked the profiles or groups behind this content.": "Dh’fhaoidte nach gabh an t-susbaint inntrigeadh air an ionstans seo on a bhac an t-ionstans seo na pròifilean no buidhnean a tha air cùlaibh na susbainte seo.",
|
||||
"Italic": "Eadailteach",
|
||||
"Jitsi Meet": "Jitsi Meet",
|
||||
"Join": "Faigh ballrachd",
|
||||
"Join <b>{instance}</b>, a Mobilizon instance": "Faigh ballrachd air <b>{instance}</b>, seo ionstans Mobilizon",
|
||||
"Join group": "Faigh ballrachd sa bhuidheann",
|
||||
"Join group {group}": "Faigh ballrachd sa bhuidheann {group}",
|
||||
@ -477,6 +504,7 @@
|
||||
"Last group created": "Am buidheann mu dheireadh a chruthaich thu",
|
||||
"Last published event": "An tachartas foillsichte as ùire",
|
||||
"Last published events": "Na tachartasan foillsichte as ùire",
|
||||
"Last seen on": "Chunnacas an turas mu dheireadh",
|
||||
"Last sign-in": "An clàradh a-steach mu dheireadh",
|
||||
"Last week": "An t-seachdain seo chaidh",
|
||||
"Latest posts": "Na puist as ùire",
|
||||
@ -514,6 +542,8 @@
|
||||
"Member": "Ball",
|
||||
"Members": "Buill",
|
||||
"Members-only post": "Post do bhuill a-mhàin",
|
||||
"Membership requests will be approved by a group moderator": "Thèid aontachadh ri iarrtasan ballrachd le maor a’ bhuidhinn",
|
||||
"Memberships": "Ballrachdan",
|
||||
"Mentions": "Iomraidhean",
|
||||
"Message": "Teachdaireachd",
|
||||
"Microsoft Teams": "Microsoft Teams",
|
||||
@ -566,12 +596,15 @@
|
||||
"No follower matches the filters": "Chan eil neach-leantainn sam bith a’ maidseadh nan criathragan",
|
||||
"No group found": "Cha deach buidheann sam bith a lorg",
|
||||
"No group matches the filters": "Chan eil buidheann sam bith a’ maidseadh nan criathragan",
|
||||
"No group member found": "Cha deach ball a lorg sa bhuidheann",
|
||||
"No groups found": "Cha deach buidheann sam bith a lorg",
|
||||
"No information": "Gun fhiosrachadh",
|
||||
"No instance follows your instance yet.": "Chan eil ionstans sam bith a’ leantainn air an ionstans agad-sa fhathast.",
|
||||
"No instance found.": "Cha deach ionstans a lorg.",
|
||||
"No instance to approve|Approve instance|Approve {number} instances": "Aontaich ri {number} ionstans|Aontaich ri {number} ionstans|Aontaich ri {number} ionstansan|Aontaich ri {number} ionstans",
|
||||
"No instance to reject|Reject instance|Reject {number} instances": "Diùlt {number} ionstans|Diùlt {number} ionstans|Diùlt {number} ionstansan|Diùlt {number} ionstans",
|
||||
"No instance to remove|Remove instance|Remove {number} instances": "Thoir air falbh {number} ionstans|Thoir air falbh {number} ionstans|Thoir air falbh {number} ionstansan|Thoir air falbh {number} ionstans",
|
||||
"No instances match this filter. Try resetting filter fields?": "Chan eil ionstans sam bith a’ freagairt ris a’ chriathrag seo. Saoil an ath-shuidhich thu raointean na criathraige?",
|
||||
"No languages found": "Cha deach cànan a lorg",
|
||||
"No member matches the filters": "Chan eil ball sam bith a’ maidseadh nan criathragan",
|
||||
"No members found": "Cha deach ball a lorg",
|
||||
@ -590,7 +623,6 @@
|
||||
"No posts found": "Cha deach post a lorg",
|
||||
"No posts yet": "Chan eil post ann fhathast",
|
||||
"No profile matches the filters": "Chan eil pròifil sam bith a’ maidseadh nan criathragan",
|
||||
"No profiles found": "Cha deach pròifil a lorg",
|
||||
"No public upcoming events": "Cha bhi tachartas poblach ann a dh’aithghearr",
|
||||
"No resolved reports yet": "Cha deach gearan fuasgladh fhathast",
|
||||
"No resources in this folder": "Chan eil goireas sa phasgan seo",
|
||||
@ -599,18 +631,20 @@
|
||||
"No results for \"{queryText}\"": "Cha deach toradh a lorg airson “{queryText}”",
|
||||
"No results for {search}": "Cha deach toradh a lorg airson {search}",
|
||||
"No rules defined yet.": "Cha deach riaghailt a mhìneachadh fhathast.",
|
||||
"No user matches the filter": "Chan eil cleachdaiche sam bith a’ maidseadh na criathraige",
|
||||
"No user matches the filters": "Chan eil cleachdaiche sam bith a’ maidseadh nan criathragan",
|
||||
"None": "Chan eil gin",
|
||||
"Not accessible with a wheelchair": "Cha ghabh a ruigsinn le cathair-chuibhle",
|
||||
"Not approved": "Gun aonta",
|
||||
"Not confirmed": "Gun dearbhadh",
|
||||
"Notes": "Nòtaichean",
|
||||
"Nothing to see here": "Chan eil dad ri fhaicinn an-seo",
|
||||
"Notification before the event": "Brath ron tachartas",
|
||||
"Notification on the day of the event": "Brath air latha an tachartais",
|
||||
"Notification settings": "Roghainnean nam brathan",
|
||||
"Notifications": "Brathan",
|
||||
"Notifications for manually approved participations to an event": "Brathan mu chom-pàirteachaichean air tachartas a chaidh aontachadh riutha à làimh",
|
||||
"Notify participants": "Cuir brath dha na com-pàirtichean",
|
||||
"Notify the user of the change": "Leig fios leis a’ chleachdaiche mun atharrachadh",
|
||||
"Now, create your first profile:": "Nise, cruthaich a’ chiad phròifil agad:",
|
||||
"Number of places": "Co mheud àite",
|
||||
"OK": "Ceart ma-thà",
|
||||
@ -619,7 +653,6 @@
|
||||
"On {date} ending at {endTime}": "{date}, a’ crìochnachadh aig {endTime}",
|
||||
"On {date} from {startTime} to {endTime}": "{date} o {startTime} gu {endTime}",
|
||||
"On {date} starting at {startTime}": "{date}, a’ tòiseachadh aig {startTime}",
|
||||
"On {instance}": "Air {instance}",
|
||||
"On {instance} and other federated instances": "Air {instance} agus ionstansan co-naisgte eile",
|
||||
"Online": "Air loidhne",
|
||||
"Online ticketing": "Ticeadan air loidhne",
|
||||
@ -639,8 +672,8 @@
|
||||
"Ordered list": "Liosta le òrdugh",
|
||||
"Organized": "’Ga eagrachadh",
|
||||
"Organized by": "’Ga eagrachadh le",
|
||||
"Organized by you": "Air a chur air dòigh leatsa",
|
||||
"Organized by {name}": "’Ga eagrachadh le {ainm}",
|
||||
"Organized events": "Tachartasan ’gan cur air dòigh",
|
||||
"Organizer": "Eagraiche",
|
||||
"Organizer notifications": "Brathan an eagraiche",
|
||||
"Organizers": "Eagraichean",
|
||||
@ -648,6 +681,8 @@
|
||||
"Other actions": "Gnìomhan eile",
|
||||
"Other notification options:": "Roghainnean eile nam brathan:",
|
||||
"Other software may also support this.": "Dh’fhaoidte gun doir bathar-bog eile taic ri seo cuideachd.",
|
||||
"Other users with the same IP address": "Cleachdaichean eile aig a bheil an t-aon seòladh IP",
|
||||
"Other users with the same email domain": "Cleachdaichean eile aig a bheil an aon àrainn puist-d",
|
||||
"Otherwise this identity will just be removed from the group administrators.": "Air neo thèid an dearbh-aithne seo a thoirt air falbh le rianairean a’ bhuidhinn.",
|
||||
"Page": "Duilleag",
|
||||
"Page limited to my group (asks for auth)": "Duilleag cuingichte air a’ bhuidheann agam (thèid dearbhadh iarraidh)",
|
||||
@ -674,7 +709,6 @@
|
||||
"Pending": "Ri dhèiligeadh",
|
||||
"Personal feeds": "Inbhirean pearsanta",
|
||||
"Pick": "Tagh",
|
||||
"Pick a group": "Tagh buidheann",
|
||||
"Pick a profile or a group": "Tagh pròifil no buidheann",
|
||||
"Pick an identity": "Tagh dearbh-aithne",
|
||||
"Pick an instance": "Tagh ionstans",
|
||||
@ -697,6 +731,7 @@
|
||||
"Powered by {mobilizon}. © 2018 - {date} The Mobilizon Contributors - Made with the financial support of {contributors}.": "Le cumhachd {mobilizon}. © 2018 – {date} Luchd-cuideachaidh Mobilizon – Le taic maoineachaidh o {contributors}.",
|
||||
"Preferences": "Roghainnean",
|
||||
"Previous": "Air ais",
|
||||
"Previous email": "Am post-d roimhe",
|
||||
"Previous month": "Am mìos roimhe",
|
||||
"Previous page": "An duilleag roimhpe",
|
||||
"Price sheet": "Siota phrìsean",
|
||||
@ -745,6 +780,7 @@
|
||||
"Registrations": "Clàraidhean",
|
||||
"Registrations are restricted by allowlisting.": "Tha an clàradh cuingichte le liosta ceadachaidh.",
|
||||
"Reject": "Diùlt",
|
||||
"Reject follow": "Diùlt an iarrtas leantainn",
|
||||
"Reject member": "Diùlt am ball",
|
||||
"Rejected": "Air a dhiùltadh",
|
||||
"Remember my participation in this browser": "Cùm an com-pàirteachadh agam an cuimhne a’ bhrabhsair seo",
|
||||
@ -757,6 +793,7 @@
|
||||
"Reply": "Freagair",
|
||||
"Report": "Dèan gearan",
|
||||
"Report #{reportNumber}": "Gearan #{report_number}",
|
||||
"Report status": "Staid a’ ghearain",
|
||||
"Report this comment": "Dèan gearan mun bheachd seo",
|
||||
"Report this event": "Dèan gearan mun tachartas seo",
|
||||
"Report this group": "Dèan gearan mun bhuidheann seo",
|
||||
@ -773,6 +810,7 @@
|
||||
"Resend confirmation email": "Cuir am post-d dearbhaidh a-rithist",
|
||||
"Resent confirmation email": "Chaidh am post-d dearbhaidh a chur a-rithist",
|
||||
"Reset": "Ath-shuidhich",
|
||||
"Reset filters": "Ath-shuidhich na criathragan",
|
||||
"Reset my password": "Ath-shuidhich am facal-faire agam",
|
||||
"Reset password": "Ath-shuidhich am facal-faire",
|
||||
"Resolved": "Air fhuasgladh",
|
||||
@ -791,7 +829,7 @@
|
||||
"Search": "Lorg",
|
||||
"Search events, groups, etc.": "Lorg tachartasan, buidhnean is msaa.",
|
||||
"Searching…": "’Ga lorg…",
|
||||
"Search…": "Lorg…",
|
||||
"Select a category": "Tagh roinn-seòrsa",
|
||||
"Select a language": "Tagh cànan",
|
||||
"Select a radius": "Tagh astar",
|
||||
"Select a timezone": "Tagh roinn-tìde",
|
||||
@ -799,6 +837,7 @@
|
||||
"Select the activities for which you wish to receive an email or a push notification.": "Tagh na gnìomhachdan dhan fhaigh thu post-d no brath putaidh.",
|
||||
"Send": "Cuir",
|
||||
"Send email": "Cuir post-d",
|
||||
"Send feedback": "Cuir do bheachd thugainn",
|
||||
"Send notification e-mails": "Cuir puist-d bhrathan",
|
||||
"Send password reset": "Cuir ath-shuidheachadh an fhacail-fhaire",
|
||||
"Send the confirmation email again": "Cuir am post-d dearbhaidh a-rithist",
|
||||
@ -825,13 +864,17 @@
|
||||
"Skip to main content": "Thoir leum gun phrìomh shusbaint",
|
||||
"Social": "Sòisealta",
|
||||
"Some terms, technical or otherwise, used in the text below may cover concepts that are difficult to grasp. We have provided a glossary here to help you understand them better:": "Tha cuid dhe na faclan a tha ’gan cleachdadh san teacsa gu h-ìosal, co-dhiù an e faclan teicnigeach a th’ annta gus nach e, mu bheachdan a tha caran doirbh a thuigsinn ma dh’fhaoidte. Rinn sinn briathrachan ach am bhiod e na b’ fhasa dhut an tuigsinn:",
|
||||
"Sorry, we wen't able to save your feedback. Don't worry, we'll try to fix this issue anyway.": "Tha sinn duilich ach cha b’ urrainn dhuinn do bheachd a shàbhaladh. Na gabh dragh, feuchaidh sinn gun càraich sinn an duilgheadas co-dhiù.",
|
||||
"Starts on…": "Àm-tòiseachaidh…",
|
||||
"Status": "Staid",
|
||||
"Stop following instance": "Na lean tuilleadh air an ionstans",
|
||||
"Street": "Sràid",
|
||||
"Submit": "Cuir a-null",
|
||||
"Subtitles": "Fo-thiotalan",
|
||||
"Suspend": "Cuir à rèim",
|
||||
"Suspend group": "Cuir am buidheann à rèim",
|
||||
"Suspend the account": "Cuir an cunntas à rèim",
|
||||
"Suspend the account?": "A bheil thu airson an cunntas a chur à rèim?",
|
||||
"Suspended": "Chaidh a chur à rèim",
|
||||
"Tag search": "Lorg taga",
|
||||
"Task lists": "Liostaichean shaothraichean",
|
||||
@ -841,6 +884,7 @@
|
||||
"Terms": "Teirmichean",
|
||||
"Terms of service": "Teirmichean na seirbheise",
|
||||
"Text": "Teacsa",
|
||||
"Thanks a lot, your feedback was submitted!": "Mòran taing, chaidh do bheachdan a chur thugainn!",
|
||||
"That you follow or of which you are a member": "A tha thu a’ leantainn orra no ’nad bhall ann",
|
||||
"The Big Blue Button video teleconference URL": "URL co-labhairt video Big Blue Button",
|
||||
"The Google Meet video teleconference URL": "URL co-labhairt video Google Meet",
|
||||
@ -871,7 +915,6 @@
|
||||
"The event will show as attributed to this group.": "Thèid an tachartas seo iomruineadh dhan bhuidheann seo.",
|
||||
"The event will show as attributed to this profile.": "Thèid an tachartas seo iomruineadh dhan phròifil seo.",
|
||||
"The event will show as attributed to your personal profile.": "Thèid an tachartas seo iomruineadh dhan phròifil phearsanta agad.",
|
||||
"The event will show the group as organizer.": "Seallaidh an tachartas am buidheann mar eagraiche.",
|
||||
"The event {event} was created by {profile}.": "Chaidh an tachartas {event} a chruthachadh le {profile}.",
|
||||
"The event {event} was deleted by {profile}.": "Chaidh an tachartas {event} a sguabadh às le {profile}.",
|
||||
"The event {event} was updated by {profile}.": "Chaidh an tachartas {event} ùrachadh le {profile}.",
|
||||
@ -899,6 +942,7 @@
|
||||
"The report will be sent to the moderators of your instance. You can explain why you report this content below.": "Thèid do ghearan a chuir dha na maoir aig an ionstans agad. ’S urrainn dhut mìneachadh carson a tha thu a’ dèanamh gearan mun t-susbaint seo gu h-ìosal.",
|
||||
"The selected picture is too heavy. You need to select a file smaller than {size}.": "Tha an dealbh a thagh thu ro throm. Feumaidh tu faidhle a thaghadh a tha nas lugha na {size}.",
|
||||
"The technical details of the error can help developers solve the problem more easily. Please add them to your feedback.": "Cuidichidh am fiosrachadh teicnigeach mun mhearachd gum fuasgail an luchd-leasachaidh an duilgheadas nas fhasa. Cuir ri do bheachd e.",
|
||||
"The user has been disabled": "Chaidh an cleachdaiche a chur à comas",
|
||||
"The {default_privacy_policy} will be used. They will be translated in the user's language.": "Thèid {default_privacy_policy} a chleachdadh. Thèid a h-eadar-theangachadh gu cànan a’ chleachdaiche.",
|
||||
"The {default_terms} will be used. They will be translated in the user's language.": "Thèid {default_terms} a chleachdadh. Thèid an eadar-theangachadh gu cànan a’ chleachdaiche.",
|
||||
"There are {participants} participants.": "Tha {participants} com-pàirtiche(an) ann.",
|
||||
@ -914,11 +958,13 @@
|
||||
"This event has been cancelled.": "Chaidh an tachartas seo a chur gu neoini.",
|
||||
"This event is accessible only through it's link. Be careful where you post this link.": "Cha ghabh an tachartas seo inntrigeadh ach leis a’ cheangal aige. Thoir an aire mus postaich thu an ceangal seo am badeigin.",
|
||||
"This group doesn't have a description yet.": "Chan eil tuairisgeul aig a’ bhuidheann seo fhathast.",
|
||||
"This group is a remote group, it's possible the original instance has more informations.": "’S e buidheann cèin a tha seo agus dh’fhaoidte gu bheil barrachd fiosrachaidh aig an ionstans tùsail.",
|
||||
"This group is accessible only through it's link. Be careful where you post this link.": "Cha ghabh an tachartas seo inntrigeadh ach leis a’ cheangal aige. Thoir an aire mus postaich thu an ceangal seo am badeigin.",
|
||||
"This group is invite-only": "Feumaidh tu cuireadh airson ballrachd fhaighinn sa bhuidheann seo",
|
||||
"This group was not found": "Cha deach am buidheann seo a lorg",
|
||||
"This identifier is unique to your profile. It allows others to find you.": "Tha an t-aithnichear seo àraidh dhan phròifil agad. Leigidh e le càch do lorg.",
|
||||
"This identity is not a member of any group.": "Chan eil an dearbh-aithne seo ’na ball ann am buidheann sam bith.",
|
||||
"This information is saved only on your computer. Click for details": "Tha dèid am fiosrachadh seo a shàbhaladh ach air a’ choimpiutair agad. Briog airson mion-fhiosrachadh",
|
||||
"This instance doesn't follow yours.": "Chan eil an t-ionstans seo a’ leantainn air an fhear agadsa.",
|
||||
"This instance hasn't got push notifications enabled.": "Chan eil na brathan putaidh an comas aig an ionstans seo.",
|
||||
"This instance isn't opened to registrations, but you can register on other instances.": "Chan eil an t-ionstans seo fosgailte a chùm clàraidh ach ’s urrainn dhut clàradh air ionstansan eile.",
|
||||
"This instance, <b>{instanceName} ({domain})</b>, hosts your profile, so remember its name.": "’S e an t-ionstans seo <b>{instanceName} ({domain})</b> a tha ag òstadh na pròifil agad, mar sin cuir ainm-san ’nad chuimhne.",
|
||||
@ -928,7 +974,11 @@
|
||||
"This post is accessible only for members. You have access to it for moderation purposes only because you are an instance moderator.": "Chan fhaigh ach na buill cothrom air a’ phost seo. Faodaidh tu inntrigeadh a chùm maorsainneachd a-mhàin on a tha thu ’nad mhaor air an ionstans seo.",
|
||||
"This post is accessible only through it's link. Be careful where you post this link.": "Cha ghabh am post seo inntrigeadh ach leis a’ cheangal aige. Thoir an aire mus postaich thu an ceangal seo am badeigin.",
|
||||
"This profile is from another instance, the informations shown here may be incomplete.": "Tha a’ phròifil seo o ionstans eile, dh’fhaoidte nach eil am fiosrachadh a chì thu an-seo coileanta.",
|
||||
"This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.": "Tha a’ phròifil seo air an ionstans seo, mar sin feumaidh tu {access_the_corresponding_account} gus a cur à rèim.",
|
||||
"This profile was not found": "Cha deach a’ phròifil seo a lorg",
|
||||
"This setting will be used to display the website and send you emails in the correct language.": "Thèid an roghainn seo a chleachdadh airson an làrach-lìn a shealltainn agus puist-d a chur thugad sa chànan cheart.",
|
||||
"This user doesn't have any profiles": "Chan eil pròifil sam bith aig a’ chleachdaiche seo",
|
||||
"This user was not found": "Cha deach an cleachdaiche seo a lorg",
|
||||
"This website isn't moderated and the data that you enter will be automatically destroyed every day at 00:01 (Paris timezone).": "Chan eil an làrach-lìn seo fo mhaorsainneachd agus thèid an dàta a chuireas tu a-steach a mhilleadh gu fèin-obrachail gach oidhche aig 00:01 (roinn-tìde Pharais).",
|
||||
"This week": "An t-seachdain seo",
|
||||
"This weekend": "An deireadh-seachdain seo",
|
||||
@ -949,6 +999,7 @@
|
||||
"Today": "An-diugh",
|
||||
"Tomorrow": "A-màireach",
|
||||
"Tools": "Innealan",
|
||||
"Total number of participations": "Com-pàirteachaidhean iomlan",
|
||||
"Transfer to {outsideDomain}": "Tar-chur gu {outsideDomain}",
|
||||
"Triggered profile refreshment": "Thèid a’ phròifil ath-nuadhachadh",
|
||||
"Twitch live": "Twitch beò",
|
||||
@ -968,7 +1019,6 @@
|
||||
"Underline": "Fo-loidhne",
|
||||
"Undo": "Neo-dhèan",
|
||||
"Unfollow": "Na lean tuilleadh",
|
||||
"Unfortunately, this instance isn't opened to registrations": "Gu mì-fhortanach, chan eil an t-ionstans seo fosgailte a chùm clàraidh",
|
||||
"Unfortunately, your participation request was rejected by the organizers.": "Gu mì-fhortanach, dhiùlt na h-eagraichean do chom-pàirteachadh.",
|
||||
"Unknown": "Chan eil fhios",
|
||||
"Unknown actor": "Actar nach aithne dhuinn",
|
||||
@ -976,7 +1026,6 @@
|
||||
"Unknown value for the openness setting.": "Chaidh luach nach aithne dhuinn a shuidheachadh air dè cho fosgailte ’s a tha am buidheann.",
|
||||
"Unlogged participation": "Com-pàirteachadh gun logadh",
|
||||
"Unsaved changes": "Atharraichean gun sàbhaladh",
|
||||
"Unset group": "Dì-shuidhich am buidheann",
|
||||
"Unsubscribe to browser push notifications": "Cuir crìoch air an fho-sgrìobhadh air brathan putaidh",
|
||||
"Unsuspend": "Cuir an gnìomh a-rithist",
|
||||
"Upcoming": "Ri thighinn",
|
||||
@ -991,6 +1040,7 @@
|
||||
"Update post": "Ùraich am post",
|
||||
"Updated": "Air ùrachadh",
|
||||
"Uploaded media size": "Meud a’ mheadhain a chaidh a luchdadh suas",
|
||||
"Uploaded media total size": "Meud iomlan nam meadhanan a chaidh a luchdadh suas",
|
||||
"Use my location": "Cleachd an t-ionad agam",
|
||||
"User": "Cleachdaiche",
|
||||
"User settings": "Roghainnean a’ chleachdaiche",
|
||||
@ -1010,6 +1060,8 @@
|
||||
"View less": "Seall nas lugha",
|
||||
"View more": "Seall barrachd",
|
||||
"View page on {hostname} (in a new window)": "Seall an duilleag air {hostname} (ann an uinneag ùr)",
|
||||
"View past events": "Seall na tachartasan san àm a dh’fhalbh",
|
||||
"View the group profile on the original instance": "Faic pròifil a’ buidhinn air an ionstans tùsail",
|
||||
"Visibility was set to an unknown value.": "Chaidh luach nach aithne dhuinn a shuidheachadh air an t-so-fhaicsinneachd.",
|
||||
"Visibility was set to private.": "Chaidh so-fhaicsinneachd phrìobhaideach a shuidheachadh air.",
|
||||
"Visibility was set to public.": "Chaidh so-fhaicsinneachd phoblach a shuidheachadh air.",
|
||||
@ -1017,6 +1069,7 @@
|
||||
"Visible everywhere on the web (public)": "Chithear air feadh an lìn e (poblach)",
|
||||
"Waiting for organization team approval.": "A’ feitheamh air aontachadh leis an sgioba eagrachaidh.",
|
||||
"Warning": "Rabhadh",
|
||||
"We collect your feedback and the error information in order to improve this service.": "Cruinnichidh sinn do bheachdan agus am fiosrachadh mun mhearachd ach an doir sinn piseach air an t-seirbheis seo.",
|
||||
"We couldn't save your participation inside this browser. Not to worry, you have successfully confirmed your participation, we just couldn't save it's status in this browser because of a technical issue.": "Cha b’ urrainn dhuinn an com-pàirteachadh agad a shàbhaladh sa bhrabhsair seo. Na gabh dragh, dhearbh thu gun gabh thu pàirt ann ach cha b’ urrainn dhuinn sin a shàbhaladh sa bhrabhsair seo ri linn duilgheadas teicnigeach.",
|
||||
"We improve this software thanks to your feedback. To let us know about this issue, two possibilities (both unfortunately require user account creation):": "Bheir sinn piseach air a’ bhathar-bhog le taic do bheachdan. Tha dà dhòigh ann airson innse dhuinn mu dhèidhinn na trioblaide seo (gu mì-fhortanach, feumaidh tu cunntas a chruthachadh dhaibh):",
|
||||
"We just sent an email to {email}": "Tha sinn air post-d a chur gu {email}",
|
||||
@ -1032,6 +1085,7 @@
|
||||
"Welcome back!": "Fàilte air ais!",
|
||||
"Welcome to Mobilizon, {username}!": "Fàilte gu Mobilizon, {username}!",
|
||||
"What can I do to help?": "Dè nì mi airson cuideachadh?",
|
||||
"What happened?": "Dè thachair?",
|
||||
"Wheelchair accessibility": "Inntrigeadh cathrach-cuibhle",
|
||||
"When a moderator from the group creates an event and attributes it to the group, it will show up here.": "Nuair a chruthaicheas maor a’ bhuidhinn tachartas le iomruineadh dhan bhuidheann, nochdaidh e an-seo.",
|
||||
"When the event is private, you'll need to share the link around.": "Nuair a bhios an tachartas prìobhaideach, feumaidh tu fhèin an ceangal a cho-roinneadh.",
|
||||
@ -1046,7 +1100,6 @@
|
||||
"Why create an account?": "Carson a chruthaichinn cunntas?",
|
||||
"Will allow to display and manage your participation status on the event page when using this device. Uncheck if you're using a public device.": "Leigidh seo leat staid do chom-pàirteachaidh a shealltainn ’s a stiùireadh air duilleag an tachartais nuair a chleachdas tu an t-uidheam seo. Thoir a’ chromag air falbh ma tha thu a’ cleachdadh uidheam poblach.",
|
||||
"Within {number} kilometers of {place}": "Am broinn {number} chilemeatair o {place}|Am broinn {number} chilemeatair o {place}|Am broinn {number} cilemeatairean o {place}|Am broinn {number} cilemeatair o {place}",
|
||||
"Write something…": "Sgrìobh rudeigin…",
|
||||
"Yesterday": "An-dè",
|
||||
"You accepted the invitation to join the group.": "Ghabh thu ris a’ bhallrachd sa bhuidheann.",
|
||||
"You added the member {member}.": "Chuir thu am ball {member} ris.",
|
||||
@ -1081,6 +1134,7 @@
|
||||
"You don't follow any instances yet.": "Chan eil thu a’ leantainn air ionstans sam bith fhathast.",
|
||||
"You don't have any upcoming events. Maybe try another filter?": "Chan eil tachartas ri thighinn agad. Am feuch thu criathrag eile?",
|
||||
"You excluded member {member}.": "Dhùin thu am ball {member} a-mach.",
|
||||
"You have attended {count} events in the past.": "",
|
||||
"You have been disconnected": "Chaidh do cheangal a bhriseadh",
|
||||
"You have been invited by {invitedBy} to the following group:": "Thug {invitedBy} cuireadh dhut dhan bhuidheann seo:",
|
||||
"You have been removed from this group's members.": "Chaidh do thoirt air falbh o bhallrachd a’ bhuidhinn seo.",
|
||||
@ -1088,15 +1142,17 @@
|
||||
"You have one event in {days} days.": "| Bidh {count} tachartas agad sna {days} là(ithean) ri thighinn| Bidh {count} thachartas agad sna {days} là(ithean) ri thighinn| Bidh {count} tachartasan agad sna {days} là(ithean) ri thighinn| Bidh {count} tachartas agad sna {days} là(ithean) ri thighinn",
|
||||
"You have one event today.": "Bidh {count} tachartas agad an-diugh| Bidh {count} thachartas agad an-diugh| Bidh {count} tachartasan agad an-diugh| Bidh {count} tachartas agad an-diugh",
|
||||
"You have one event tomorrow.": "Bidh {count} tachartas agad a-màireach| Bidh {count} thachartas agad a-màireach| Bidh {count} tachartasan agad a-màireach| Bidh {count} tachartas agad a-màireach",
|
||||
"You haven't interacted with other instances yet.": "Cha do rinn thu eadar-ghnìomh le ionstans sam bith eile fhathast.",
|
||||
"You invited {member}.": "Thug thu cuireadh dha {member}.",
|
||||
"You may also:": "’S urrainn dhut cuideachd:",
|
||||
"You may clear all participation information for this device with the buttons below.": "’S urrainn dhut gach fiosrachadh mun chom-pàirteachadh a shuathadh bàn on uidheam seo leis na putanan gu h-ìosal.",
|
||||
"You may now close this page or {return_to_the_homepage}.": "’S urrainn dhut an duilleag seo a dhùnadh a-nis no {return_to_the_homepage}.",
|
||||
"You may now close this window, or {return_to_event}.": "’S urrainn dhut an uinneag seo a dhùnadh a-nis no {return_to_event}.",
|
||||
"You may show some members as contacts.": "Faodaidh tu cuid a bhuill a shealltainn ’nan luchd-aithne.",
|
||||
"You moved the folder {resource} into {new_path}.": "Ghluais thu am pasgan {resource} gu {new_path}.",
|
||||
"You moved the folder {resource} to the root folder.": "Ghluais thu am pasgan {resource} dhan phasgan freumhach.",
|
||||
"You moved the resource {resource} into {new_path}.": "Ghluais thu an goireas {resource} gu {new_path}.",
|
||||
"You moved the resource {resource} to the root folder.": "Ghluais thu an goireas {resource} dhan phasgan freumhach.",
|
||||
"You need to create the group before you create an event.": "Feumaidh buidheann a chruthachadh mus cruthaich thu tachartas.",
|
||||
"You need to login.": "Feumaidh tu clàradh a-steach.",
|
||||
"You posted a comment on the event {event}.": "Chuir thu beachd ris an tachartas {event}.",
|
||||
"You promoted the member {member} to an unknown role.": "Thug thu dreuchd nach aithnich sinn dha {member} (àrdachadh).",
|
||||
@ -1121,7 +1177,7 @@
|
||||
"You were promoted to moderator by {profile}.": "Rinn {profile} maor dhiot (àrdachadh).",
|
||||
"You will be able to add an avatar and set other options in your account settings.": "’S urrainn dhut avatar a chur ris is roghainnean eile a thaghadh ann an roghainnean a’ chunntais agad.",
|
||||
"You will be redirected to the original instance": "Thèid d’ ath-stiùireadh dhan ionstans tùsail",
|
||||
"You will find here all the events you have created or of which you are a participant.": "Chì thu a h-uile tachartas a chruthaich thu no sa bheil thu a’ gabhail pàirt an-seo.",
|
||||
"You will find here all the events you have created or of which you are a participant, as well as events organized by groups you follow or are a member of.": "Chì thu a h-uile tachartas a chruthaich thu no sa bheil thu a’ gabhail pàirt an-seo agus na tachartasan a chaidh a chur air dòigh le buidhnean air a leanas tu no sa bheil thu ’nad bhall cuideachd.",
|
||||
"You will receive notifications about this group's public activity depending on %{notification_settings}.": "Gheibh thu brathan mu ghnìomhachd phoblach a’ bhuidhinn seo a-rèir %{notification_settings} agad.",
|
||||
"You wish to participate to the following event": "Tha thu airson pàirt a ghabhail san tachartas a leanas",
|
||||
"You'll get a weekly recap every Monday for upcoming events, if you have any.": "Gheibh thu cuimhneachan gach madainn DiLuain mu na tachartasan ri thighinn ma tha gin agad.",
|
||||
@ -1142,6 +1198,7 @@
|
||||
"Your email is being changed": "Tha am post-d agad ’ga atharrachadh",
|
||||
"Your email will only be used to confirm that you're a real person and send you eventual updates for this event. It will NOT be transmitted to other instances or to the event organizer.": "Cha dèid am post-d agad a chleachdadh ach airson dearbhadh gur e neach a th’ annad agus airson naidheachdan a chur thugad mun tachartas seo. ’S ann NACH DÈID a thar-chur gu ionstansan eile no gu eagraiche an tachartais.",
|
||||
"Your federated identity": "An dearbh-aithne co-naisgte agad",
|
||||
"Your membership is pending approval": "Tha do bhallrachd a’ feitheamh ri aontachadh",
|
||||
"Your membership was approved by {profile}.": "Dh’aontaich {profile} gum faigh thu ballrachd.",
|
||||
"Your participation has been confirmed": "Chaidh an com-pàirteachadh agad a dhearbhadh",
|
||||
"Your participation has been rejected": "Chaidh an com-pàirteachadh agad a dhiùltadh",
|
||||
@ -1166,6 +1223,7 @@
|
||||
"[This comment has been deleted]": "[Chaidh am beachd seo a sguabadh às]",
|
||||
"[deleted]": "[air a sguabadh às]",
|
||||
"a non-existent report": "gearan nach eil ann",
|
||||
"access the corresponding account": "an cunntas cho-cheangailte inntrigeadh",
|
||||
"access to the group's private content as well": "inntrigeadh do shusbaint phrìobhaideach a’ bhuidhinn cuideachd",
|
||||
"and {number} groups": "agus {number} buidheann/buidhnean",
|
||||
"any distance": "astar sam bith",
|
||||
@ -1185,10 +1243,13 @@
|
||||
"https://mensuel.framapad.org/p/some-secret-token": "https://mensuel.framapad.org/p/some-secret-token",
|
||||
"iCal Feed": "Inbhir iCal",
|
||||
"instance rules": "riaghailtean an ionstans",
|
||||
"mobilizon-instance.tld": "ionstans-mobilizon.tld",
|
||||
"more than 1360 contributors": "còrr is 1360 luchd-cuideachaidh",
|
||||
"new@email.com": "ùr@post-d.com",
|
||||
"profile@instance": "ainm@ionstans",
|
||||
"report #{report_number}": "gearan #{report_number}",
|
||||
"return to the event's page": "till gu duilleag an tachartais",
|
||||
"return to the homepage": "tilleadh dhan duilleag-dhachaigh",
|
||||
"terms of service": "teirmichean na seirbheise",
|
||||
"with another identity…": "le dearbh-aithne eile…",
|
||||
"your notification settings": "roghainnean nam brathan",
|
||||
@ -1196,9 +1257,9 @@
|
||||
"{available}/{capacity} available places": "{available}/{capacity} àite air fhàgail|{available}/{capacity} àite air fhàgail|{available}/{capacity} àiteachan air fhàgail|{available}/{capacity} àite air fhàgail",
|
||||
"{count} km": "{count} km",
|
||||
"{count} members": "{count} bhall|{count} bhall|{count} buill|{count} ball",
|
||||
"{count} members or followers": "",
|
||||
"{count} participants": "{count} chom-pàirtiche| {count} chom-pàirtiche| {count} com-pàirtichean| {count} com-pàirtiche",
|
||||
"{count} requests waiting": "Tha {count} iarrtas(an) a’ feitheamh",
|
||||
"{count} team members": "Buill an sgioba ({count})",
|
||||
"{folder} - Resources": "{folder} – Goireasan",
|
||||
"{group} activity timeline": "Loidhne-ama nan gnìomhachdan aig {group}",
|
||||
"{group} events": "Tachartasan {group}",
|
||||
|
File diff suppressed because it is too large
Load Diff
341
js/src/i18n/he.json
Normal file
341
js/src/i18n/he.json
Normal file
@ -0,0 +1,341 @@
|
||||
{
|
||||
"A user-friendly, emancipatory and ethical tool for gathering, organising, and mobilising.": "כלי ידידותי למשתמש.ת, חופשי ואתי להתאספות, להתארגנות ולגיוס לפעולה משותפת.",
|
||||
"A validation email was sent to {email}": "הודעת אימות נשלחה בדואר אלקטרוני לכתובת {email}",
|
||||
"Abandon editing": "עזיבת עריכה",
|
||||
"About": "אודות",
|
||||
"About Mobilizon": "אודות מוביליזון",
|
||||
"About this event": "אודות האירוע",
|
||||
"About this instance": "אודות האתר",
|
||||
"Accepted": "התקבל",
|
||||
"Account": "חשבון",
|
||||
"Add": "הוספה",
|
||||
"Add a note": "הוספת הערה",
|
||||
"Add an address": "הוספת כתובת",
|
||||
"Add an instance": "הוספת אתר",
|
||||
"Add some tags": "הוספת תגיות",
|
||||
"Add to my calendar": "הוספה ללוח השנה שלי",
|
||||
"Additional comments": "הערות נוספות",
|
||||
"Admin": "מנהל.ת",
|
||||
"Admin settings successfully saved.": "הגדרות מנהל.ת נשמרו בהצלחה.",
|
||||
"Administration": "ניהול",
|
||||
"All the places have already been taken": "כל המקומות כבר תפוסים",
|
||||
"Allow registrations": "אפשור הרשמה",
|
||||
"Anonymous participant": "משתתפ.ת בלתי מזוהה",
|
||||
"Anonymous participants will be asked to confirm their participation through e-mail.": "משתתפים.ות בלתי מזוהים.ות יתבקשו לאשר השתתפות באמצעות דואר אלקטרוני.",
|
||||
"Anonymous participations": "השתתפות בלתי מזוהה",
|
||||
"Are you really sure you want to delete your whole account? You'll lose everything. Identities, settings, events created, messages and participations will be gone forever.": "האם את.ה בטוח.ה שאת.ה רוצה למחוק לגמרי את החשבון שלך? תאבד.י הכל. זהויות, הגדרות, אירועים שנוצרו, הודעות והשתתפויות יימחקו לצמיתות.",
|
||||
"Are you sure you want to <b>delete</b> this comment? This action cannot be undone.": "האם את.ה בטוח.ה שאת.ה רוצה <b>למחוק</b> את התגובה? לא ניתן יהיה לבטל את הפעולה.",
|
||||
"Are you sure you want to <b>delete</b> this event? This action cannot be undone. You may want to engage the discussion with the event creator or edit its event instead.": "האם את.ה בטוח.ה שאת.ה רוצה <b>למחוק</b> את האירוע? לא ניתן יהיה לבטל את הפעולה. ייתכן שתרצ.י ליצור קשר עם יוצר.ת האירוע, או לערוך את האירוע, במקום למחוק.",
|
||||
"Are you sure you want to cancel the event creation? You'll lose all modifications.": "האם את.ה בטוח.ה שאת.ה רוצה לבטל את יצירת האירוע? כל השינויים יאבדו.",
|
||||
"Are you sure you want to cancel the event edition? You'll lose all modifications.": "האם את.ה בטוח.ה שאת.ה רוצה לבטל את עריכת האירוע? כל השינויים יאבדו.",
|
||||
"Are you sure you want to cancel your participation at event \"{title}\"?": "האם את.ה בטוח.ה שאת.ה רוצה לבטל את השתתפותך באירוע \"{title}\"?",
|
||||
"Are you sure you want to delete this event? This action cannot be reverted.": "האם את.ה בטוח.ה שאת.ה רוצה למחוק את האירוע? לא ניתן יהיה לבטל את הפעולה.",
|
||||
"Avatar": "תמונה",
|
||||
"Back to previous page": "חזרה לדף הקודם",
|
||||
"Before you can login, you need to click on the link inside it to validate your account.": "לפני שתוכל.י להתחבר, עלייך ללחוץ על הקישור שבתוך ההודעה כדי לאשר את החשבון שלך.",
|
||||
"By {username}": "נכתב על־ידי {username}",
|
||||
"Cancel": "ביטול",
|
||||
"Cancel anonymous participation": "ביטול השתתפות בלתי מזוהה",
|
||||
"Cancel creation": "ביטול יצירה",
|
||||
"Cancel edition": "ביטול עריכה",
|
||||
"Cancel my participation request…": "ביטול בקשת ההשתתפות שלי…",
|
||||
"Cancel my participation…": "ביטול ההשתתפות שלי…",
|
||||
"Cancelled: Won't happen": "מבוטל: לא יתקיים",
|
||||
"Change": "שינוי",
|
||||
"Change my email": "שינוי כתובת דואר אלקטרוני",
|
||||
"Change my identity…": "שינוי הזהות שלי…",
|
||||
"Change my password": "שינוי ססמה",
|
||||
"Clear": "ניקוי",
|
||||
"Click to upload": "לחצ.י להעלאה",
|
||||
"Close": "סגירה",
|
||||
"Close comments for all (except for admins)": "ביטול תגובות לכולןם (מלבד מנהלים.ות)",
|
||||
"Closed": "סגור",
|
||||
"Comment deleted": "התגובה נמחקה",
|
||||
"Comment from @{username} reported": "התגובה של @{username} דווחה",
|
||||
"Comments": "תגובות",
|
||||
"Confirm my participation": "אישור ההשתתפות שלי",
|
||||
"Confirm my particpation": "אישור ההשתתפות שלי",
|
||||
"Confirmed: Will happen": "מאושר: יתקיים",
|
||||
"Continue editing": "המשך עריכה",
|
||||
"Country": "מדינה",
|
||||
"Create": "יצירה",
|
||||
"Create a new event": "יצירת אירוע חדש",
|
||||
"Create a new group": "יצירת קבוצה חדשה",
|
||||
"Create a new identity": "יצירת זהות חדשה",
|
||||
"Create group": "יצירת קבוצה",
|
||||
"Create my event": "יצירת אירוע",
|
||||
"Create my group": "יצירת קבוצה",
|
||||
"Create my profile": "יצירת הפרופיל שלי",
|
||||
"Create token": "יצירת אסימון",
|
||||
"Current identity has been changed to {identityName} in order to manage this event.": "הזהות הנוכחית שונתה ל־{identityName} כדי לנהל אירוע זה.",
|
||||
"Current page": "הדף הנוכחי",
|
||||
"Custom": "התאמה אישית",
|
||||
"Custom URL": "קישור מותאם אישית",
|
||||
"Custom text": "טקסט מותאם אישית",
|
||||
"Dashboard": "לוח בקרה",
|
||||
"Date": "תאריך",
|
||||
"Date and time settings": "הגדרות זמן ותאריך",
|
||||
"Date parameters": "מאפייני תאריך",
|
||||
"Default": "ברירת מחדל",
|
||||
"Delete": "מחיקה",
|
||||
"Delete Comment": "מחיקת תגובה",
|
||||
"Delete Event": "מחיקת אירוע",
|
||||
"Delete account": "מחיקת חשבון",
|
||||
"Delete event": "מחיקת אירוע",
|
||||
"Delete everything": "מחיקת הכל",
|
||||
"Delete my account": "מחיקת החשבון שלי",
|
||||
"Delete this identity": "מחיקת זהות",
|
||||
"Delete your identity": "מחיקת הזהות שלך",
|
||||
"Delete {eventTitle}": "מחיקת {eventTitle}",
|
||||
"Delete {preferredUsername}": "מחיקת {preferredUsername}",
|
||||
"Deleting comment": "מוחק תגובה",
|
||||
"Deleting event": "מוחק אירוע",
|
||||
"Deleting my account will delete all of my identities.": "מחיקת החשבון שלי תמחק את כל הזהויות שלי.",
|
||||
"Deleting your Mobilizon account": "מחיקת החשבון שלך במוביליזון",
|
||||
"Description": "תיאור",
|
||||
"Display name": "שם תצוגה",
|
||||
"Display participation price": "הצגת מחיר השתתפות",
|
||||
"Draft": "טיוטה",
|
||||
"Drafts": "טיוטות",
|
||||
"Edit": "עריכה",
|
||||
"Eg: Stockholm, Dance, Chess…": "למשל: תל אביב, ריקוד, שחמט…",
|
||||
"Either on the {instance} instance or on another instance.": "או באתר {instance} או באתר אחר.",
|
||||
"Either the account is already validated, either the validation token is incorrect.": "החשבון כבר מאומת, או שקוד האימות שגוי.",
|
||||
"Either the email has already been changed, either the validation token is incorrect.": "או שכתובת הדואר האלקטרוני כבר שונתה, או שקוד האימות שגוי.",
|
||||
"Either the participation request has already been validated, either the validation token is incorrect.": "או שבקשת ההשתתפות כבר אומתה, או שקוד האימות שגוי.",
|
||||
"Email": "דואר אלקטרוני",
|
||||
"Ends on…": "נמשך עד…",
|
||||
"Enter the link URL": "הזינ.י את הקישור",
|
||||
"Error while changing email": "שגיאה בעת שינוי כתובת דואר אלקטרוני",
|
||||
"Error while validating account": "שגיאה בעת אימות חשבון",
|
||||
"Error while validating participation request": "שגיאה בעת אימות בקשת השתתפות",
|
||||
"Event": "אירוע",
|
||||
"Event already passed": "האירוע כבר חלף",
|
||||
"Event cancelled": "האירוע בוטל",
|
||||
"Event creation": "יצירת אירוע",
|
||||
"Event edition": "עריכת אירוע",
|
||||
"Event list": "רשימת אירועים",
|
||||
"Event page settings": "הגדרות עמוד אירוע",
|
||||
"Event to be confirmed": "אירוע לאישור",
|
||||
"Event {eventTitle} deleted": "האירוע {eventTitle} נמחק",
|
||||
"Event {eventTitle} reported": "האירוע {eventTitle} דווח",
|
||||
"Events": "אירועים",
|
||||
"Ex: mobilizon.fr": "למשל: mobilizon.fr",
|
||||
"Explore": "סיור",
|
||||
"Failed to save admin settings": "שמירת הגדרות ניהול נכשלה",
|
||||
"Featured events": "אירועים מומלצים",
|
||||
"Federation": "ביזור",
|
||||
"Find an address": "מציאת כתובת",
|
||||
"Find an instance": "מציאת אתר",
|
||||
"Followers": "עוקבים.ות",
|
||||
"Followings": "עוקב.ת אחרי",
|
||||
"For instance: London, Taekwondo, Architecture…": "לדוגמה: תל אביב, אייקידו, ארכיטקטורה…",
|
||||
"Forgot your password ?": "שכחת ססמה?",
|
||||
"From the {startDate} at {startTime} to the {endDate}": "מתאריך {startDate} בשעה {startTime} עד התאריך {endDate}",
|
||||
"From the {startDate} at {startTime} to the {endDate} at {endTime}": "מתאריך {startDate} בשעה {startTime} עד התאריך {endDate} בשעה {endTime}",
|
||||
"From the {startDate} to the {endDate}": "מהתאריך {startDate} עד התאריך {endDate}",
|
||||
"Gather ⋅ Organize ⋅ Mobilize": "להתאסף ⋅ להתארגן ⋅ לפעול",
|
||||
"General": "כללי",
|
||||
"General information": "מידע כללי",
|
||||
"Getting location": "מחפש מיקום",
|
||||
"Go": "קדימה",
|
||||
"Group name": "שם הקבוצה",
|
||||
"Group {displayName} created": "הקבוצה {displayName} נוצרה",
|
||||
"Groups": "קבוצות",
|
||||
"Headline picture": "תמונת כותרת",
|
||||
"Hide replies": "הסתרת תגובות",
|
||||
"I create an identity": "אני יוצר.ת זהות",
|
||||
"I don't have a Mobilizon account": "אין לי חשבון מוביליזון",
|
||||
"I have a Mobilizon account": "יש לי חשבון מוביליזון",
|
||||
"I have an account on another Mobilizon instance.": "יש לי חשבון באתר מוביליזון אחר.",
|
||||
"I participate": "אני משתתפ.ת",
|
||||
"I want to allow people to participate without an account.": "אני רוצה לאפשר לא.נשים להשתתף ללא חשבון.",
|
||||
"I want to approve every participation request": "אני רוצה לאשר כל בקשת השתתפות",
|
||||
"Identity {displayName} created": "הזהות {displayName} נוצרה",
|
||||
"Identity {displayName} deleted": "הזהות {displayName} נמחקה",
|
||||
"Identity {displayName} updated": "הזהות {displayName} עודכנה",
|
||||
"If an account with this email exists, we just sent another confirmation email to {email}": "אם קיים חשבון עם כתובת הדואר האלקטרוני הזו, שלחנו עוד הודעת אימות לכתובת {email}",
|
||||
"If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "אם הזהות הזו היא המנהלת היחידה של קבוצות כלשהן, עלייך למחוק אותן לפני שתוכלי למחוק את הזהות הזו.",
|
||||
"If you want, you may send a message to the event organizer here.": "אם את.ה רוצה, באפשרותך לשלוח כאן הודעה למארגנ.ת האירוע.",
|
||||
"Instance Name": "שם האתר",
|
||||
"Instance Terms": "תנאי השימוש של האתר",
|
||||
"Instance Terms Source": "תנאי השימוש של האתר",
|
||||
"Instance Terms URL": "קישור לתנאי השימוש של האתר",
|
||||
"Instance settings": "הגדרות האתר",
|
||||
"Instances": "אתרים",
|
||||
"Join <b>{instance}</b>, a Mobilizon instance": "הצטרפ.י ל־<b>{instance}</b>, אתר מוביליזון",
|
||||
"Last published event": "האירוע האחרון שפורסם",
|
||||
"Last week": "בשבוע שעבר",
|
||||
"Learn more": "למדו עוד",
|
||||
"Learn more about Mobilizon": "למדו עוד אודות מוביליזון",
|
||||
"Leave event": "עזיבת האירוע",
|
||||
"Leaving event \"{title}\"": "עוזב את האירוע \"{title}\"",
|
||||
"License": "רישיון",
|
||||
"Limited number of places": "מספר מוגבל של מקומות",
|
||||
"Load more": "לטעון עוד",
|
||||
"Locality": "מיקום",
|
||||
"Log in": "כניסה",
|
||||
"Log out": "יציאה",
|
||||
"Login": "כניסה",
|
||||
"Login on Mobilizon!": "כניסה למוביליזון!",
|
||||
"Login on {instance}": "כניסה לאתר {instance}",
|
||||
"Manage participations": "ניהול השתתפויות",
|
||||
"Mark as resolved": "סימון כנפתר",
|
||||
"Members": "חברים.ות",
|
||||
"Message": "הודעה",
|
||||
"Mobilizon is a federated network. You can interact with this event from a different server.": "מוביליזון היא רשת מבוזרת. ניתן לבצע פעולות בקשר לאירוע זה משרת אחר.",
|
||||
"Moderated comments (shown after approval)": "תגובות שממתינות לאישור",
|
||||
"Moderation": "אישור תגובות",
|
||||
"Moderation log": "היסטוריית אישור תגובות",
|
||||
"My account": "החשבון שלי",
|
||||
"My events": "האירועים שלי",
|
||||
"My identities": "הזהויות שלי",
|
||||
"Name": "שם",
|
||||
"New email": "הודעת דוא\"ל חדשה",
|
||||
"New note": "הערה חדשה",
|
||||
"New password": "ססמה חדשה",
|
||||
"New profile": "פרופיל חדש",
|
||||
"Next page": "הדף הבא",
|
||||
"No address defined": "לא הוגדרה כתובת",
|
||||
"No closed reports yet": "אין דיווחים סגורים עדיין",
|
||||
"No comment": "אין תגובות",
|
||||
"No comments yet": "אין תגובות עדיין",
|
||||
"No end date": "אין תאריך סיום",
|
||||
"No events found": "לא נמצאו אירועים",
|
||||
"No group found": "לא נמצאה קבוצה",
|
||||
"No groups found": "לא נמצאו קבוצות",
|
||||
"No instance follows your instance yet.": "עדיין אין אתר שעוקב אחרי האתר שלך.",
|
||||
"No instance to approve|Approve instance|Approve {number} instances": "אין אתרים לאשר|אישור האתר|אישור של {number} אתרים",
|
||||
"No instance to reject|Reject instance|Reject {number} instances": "אין אתר לדחות|דחיית האתר|דחיית {number} אתרים",
|
||||
"No instance to remove|Remove instance|Remove {number} instances": "אין אתרים להסיר|הסרת האתר|הסרת {number} אתרים",
|
||||
"No message": "אין הודעות",
|
||||
"No open reports yet": "אין דיווחים פתוחים עדיין",
|
||||
"No participant to approve|Approve participant|Approve {number} participants": "אין משתתפים.ות לאשר|אישור המשתתפ.ת|אישור של {number} משתתפים.ות",
|
||||
"No participant to reject|Reject participant|Reject {number} participants": "אין משתתפים.ות לדחות|דחיית המשתתפ.ת|דחיית {number} משתתפים.ות",
|
||||
"No resolved reports yet": "אין דיווחים פתורים עדיין",
|
||||
"No results for \"{queryText}\"": "אין תוצאות עבור \"{queryText}\"",
|
||||
"Notes": "הערות",
|
||||
"Number of places": "מספר מקומות",
|
||||
"OK": "אישור",
|
||||
"Old password": "ססמה ישנה",
|
||||
"On {date}": "בתאריך {date}",
|
||||
"On {date} ending at {endTime}": "בתאריך {date} מסתיים בשעה {endTime}",
|
||||
"On {date} from {startTime} to {endTime}": "בתאריך {date} מהשעה {startTime} עד השעה {endTime}",
|
||||
"On {date} starting at {startTime}": "בתאריך {date} החל מהשעה {startTime}",
|
||||
"Only accessible through link (private)": "נגיש רק דרך קישור (פרטי)",
|
||||
"Only alphanumeric lowercased characters and underscores are supported.": "רק אותיות קטנות באנגלית, ספרות וקו תחתי.",
|
||||
"Open": "פתיחה",
|
||||
"Opened reports": "דיווחים פתוחים",
|
||||
"Or": "או",
|
||||
"Organized": "מאורגן",
|
||||
"Organized by {name}": "מאורגן על־ידי {name}",
|
||||
"Organizer": "מארגנ.ת",
|
||||
"Other software may also support this.": "תוכנות אחרות עשויות גם הן לתמוך בזה.",
|
||||
"Otherwise this identity will just be removed from the group administrators.": "אחרת, זהות זו פשוט תוסר מניהול הקבוצה.",
|
||||
"Page": "דף",
|
||||
"Page limited to my group (asks for auth)": "הדף מוגבל לקבוצה שלי (מבקש להזדהות)",
|
||||
"Participant": "משתתפ.ת",
|
||||
"Participants": "משתתפים.ות",
|
||||
"Participate": "השתתפות",
|
||||
"Participate using your email address": "השתתפות בעזרת כתובת הדוא\"ל שלך",
|
||||
"Participation approval": "אישור השתתפות",
|
||||
"Participation confirmation": "אישור השתתפות",
|
||||
"Participation requested!": "נשלחה בקשת השתתפות!",
|
||||
"Password": "ססמה",
|
||||
"Password (confirmation)": "ססמה (וידוא)",
|
||||
"Password reset": "איפוס ססמה",
|
||||
"Past events": "אירועים שחלפו",
|
||||
"Pending": "ממתין",
|
||||
"Pick an identity": "בחירת זהות",
|
||||
"Please check your spam folder if you didn't receive the email.": "אנא בדק.י את תיקיית הספאם שלך אם לא קיבלת את הודעת הדוא\"ל.",
|
||||
"Please contact this instance's Mobilizon admin if you think this is a mistake.": "אנא צר.י קשר עם מנהל.ת האתר אם את.ה חושב.ת שזו טעות.",
|
||||
"Please enter your password to confirm this action.": "אנא הזינ.י את הסממה שלך כדי לאשר את הפעולה.",
|
||||
"Please make sure the address is correct and that the page hasn't been moved.": "אנא ודא.י שהכתובת נכונה ושהעמוד לא הוזז.",
|
||||
"Post a comment": "פרסום תגובה",
|
||||
"Post a reply": "פרסום תגובה",
|
||||
"Postal Code": "מיקוד",
|
||||
"Preferences": "העדפות",
|
||||
"Previous page": "הדף הקודם",
|
||||
"Privacy Policy": "מדיניות פרטיות",
|
||||
"Private event": "אירוע פרטי",
|
||||
"Private feeds": "היזנים פרטיים",
|
||||
"Profiles": "פרופילים",
|
||||
"Public RSS/Atom Feed": "ערוץ RSS/Atom פומבי",
|
||||
"Public comment moderation": "בקרת תגובות פומביות",
|
||||
"Public event": "אירוע פומבי",
|
||||
"Public feeds": "היזנים פומביים",
|
||||
"Public iCal Feed": "ערוץ iCal פומבי",
|
||||
"Publish": "פרסום",
|
||||
"Published events with <b>{comments}</b> comments and <b>{participations}</b> confirmed participations": "אירועים שפורסמו שיש להם <b>{comments}</b> תגובות ו־<b>{participations}</b> אישורי השתתפות",
|
||||
"RSS/Atom Feed": "היזן רסס/אטום",
|
||||
"Region": "אזור",
|
||||
"Registration is allowed, anyone can register.": "ההרשמה מאופשרת, כל אחד.ת יכול.ה להירשם.",
|
||||
"Registration is closed.": "ההרשמה סגורה.",
|
||||
"Registration is currently closed.": "ההרשמה סגורה כעת.",
|
||||
"Rejected": "נדחה",
|
||||
"Reopen": "פתיחה מחדש",
|
||||
"Reply": "תגובה",
|
||||
"Report": "דיווח",
|
||||
"Report this comment": "דיווח על תגובה זו",
|
||||
"Report this event": "דיווח על אירוע זה",
|
||||
"Reported": "מדווח",
|
||||
"Reported by": "דווח על־ידי",
|
||||
"Reported by someone on {domain}": "דווח על־ידי מישהו.י מהאתר {domain}",
|
||||
"Reported by {reporter}": "דווח על־ידי {reporter}",
|
||||
"Reported identity": "זהות מדווחת",
|
||||
"Reports": "דיווחים",
|
||||
"Reset my password": "איפוס הססמה שלי",
|
||||
"Resolved": "נפתר",
|
||||
"Resource provided is not an URL": "המשאב שהוזן אינו קישור תקין",
|
||||
"Role": "תפקיד",
|
||||
"Save": "שמירה",
|
||||
"Save draft": "שמירת טיוטה",
|
||||
"Search": "חיפוש",
|
||||
"Search events, groups, etc.": "חיפוש אירועים, קבוצות וכו'",
|
||||
"Searching…": "מחפש…",
|
||||
"Send email": "שליחת דוא\"ל",
|
||||
"Send the report": "שליחת הדיווח",
|
||||
"Set an URL to a page with your own terms.": "הגדרת קישור לעמוד עם תנאים משלך.",
|
||||
"Settings": "הגדרות",
|
||||
"Share this event": "שיתוף אירוע זה",
|
||||
"Show map": "הצגת מפה",
|
||||
"Show remaining number of places": "הצגת מספר המקומות שנותרו",
|
||||
"Show the time when the event begins": "הצגת זמן תחילת האירוע",
|
||||
"Show the time when the event ends": "הצגת זמן סיום האירוע",
|
||||
"Sign up": "הרשמה",
|
||||
"Starts on…": "מתחיל ב…",
|
||||
"Status": "מצב",
|
||||
"Street": "רחוב",
|
||||
"Tentative: Will be confirmed later": "לא סופי: יאושר בהמשך",
|
||||
"Terms": "תנאים",
|
||||
"The account's email address was changed. Check your emails to verify it.": "כתובת הדוא\"ל של החשבון שונתה. בדק.י את תיבת הדוא\"ל שלך כדי לאמת את השינוי.",
|
||||
"The actual number of participants may differ, as this event is hosted on another instance.": "מספר המשתתפים.ות האמיתי עשוי להיות שונה, כי האירוע מתפרסם דרך אתר מוביליזון אחר.",
|
||||
"The content came from another server. Transfer an anonymous copy of the report?": "התוכן הגיע משרת אחר. להעביר עותק אנונימי של הדיווח?",
|
||||
"The draft event has been updated": "טיוטת האירוע עודכנה",
|
||||
"The event has been created as a draft": "האירוע נוצר כטיוטה",
|
||||
"The event has been published": "האירוע פורסם",
|
||||
"The event has been updated": "האירוע עודכן",
|
||||
"The event has been updated and published": "האירוע עודכן ופורסם",
|
||||
"The event organiser has chosen to validate manually participations. Do you want to add a little note to explain why you want to participate to this event?": "בקשות השתתפות מאושרות ידנית על־ידי מארגנ.ת האירוע. האם ברצונך להוסיף הערה עם הסבר מדוע את.ה רוצה להשתתף באירוע זה?",
|
||||
"The event organizer didn't add any description.": "מארגנ.ת האירוע לא הוסיפ.ה תיאור.",
|
||||
"The event organizer manually approves participations. Since you've chosen to participate without an account, please explain why you want to participate to this event.": "בקשות השתתפות מאושרות ידנית על־ידי מארגנ.ת האירוע. היות ובחרת להשתתף ללא חשבון, אנא צרפ.י הסבר מדוע את.ה רוצה להשתתף באירוע זה.",
|
||||
"The event title will be ellipsed.": "כותרת האירוע תוצג באופן מקוצר עם שלוש נקודות בסוף.",
|
||||
"The page you're looking for doesn't exist.": "העמוד שחיפשת לא קיים.",
|
||||
"The password was successfully changed": "הססמה שונתה בהצלחה",
|
||||
"The report will be sent to the moderators of your instance. You can explain why you report this content below.": "הדיווח יישלח למנהלים.ות של השרת שלך. ניתן להסביר למטה את סיבת הדיווח של תוכן זה.",
|
||||
"The {default_terms} will be used. They will be translated in the user's language.": "ייעשה שימוש ב{default_terms}. הם יתורגמו לשפה של המשתמש.ת.",
|
||||
"There are {participants} participants.": "יש {participants} משתתפים.ות.",
|
||||
"There will be no way to recover your data.": "לא תהיה אפשרות לשחזר את המידע שלך.",
|
||||
"These events may interest you": "האירועים האלה עשויים לעניין אותך",
|
||||
"This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.": "שרת מוביליזון זה ואירוע זה מאפשרים בקשת השתתפות ללא חשבון, אך נדרש אימות באמצעות דואר אלקטרוני.",
|
||||
"This information is saved only on your computer. Click for details": "מידע זה נשמר רק על המחשב שלך. לפרטים לחצ.י",
|
||||
"This instance isn't opened to registrations, but you can register on other instances.": "שרת זה אינו פתוח להרשמה, אך ניתן להירשם בשרתים אחרים.",
|
||||
"This is a demonstration site to test Mobilizon.": "זהו אתר הדגמה לצורך בדיקה של מוביליזון.",
|
||||
"This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "הדבר ימחק / יהפוך לאנונימי את כל התוכן (אירועים, תגובות, הודעות, אישורי השתתפות…) שנוצר מתוך זהות זו.",
|
||||
"Title": "כותרת",
|
||||
"To confirm, type your event title \"{eventTitle}\"": "לאישור, נא להזין את כותרת האירוע \"{eventTitle}\"",
|
||||
"To confirm, type your identity username \"{preferredUsername}\"": "לאישור, נא להזין את שם המשתמש.ת שלך \"{preferredUsername}\"",
|
||||
"Transfer to {outsideDomain}": "העברה לשרת {outsideDomain}",
|
||||
"Type": "סוג",
|
||||
"URL": "קישור"
|
||||
}
|
1263
js/src/i18n/hr.json
Normal file
1263
js/src/i18n/hr.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1243
js/src/i18n/ja.json
1243
js/src/i18n/ja.json
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user