forked from potsda.mn/mobilizon
Merge branch 'fixes' into 'main'
Various fixes Closes #1321 See merge request framasoft/mobilizon!1448
This commit is contained in:
commit
1c1afcb069
|
@ -392,6 +392,9 @@ config :mobilizon, Mobilizon.Service.GlobalSearch.SearchMobilizon,
|
||||||
|
|
||||||
config :mobilizon, Mobilizon.Service.AntiSpam, service: Mobilizon.Service.AntiSpam.Akismet
|
config :mobilizon, Mobilizon.Service.AntiSpam, service: Mobilizon.Service.AntiSpam.Akismet
|
||||||
|
|
||||||
|
config :mobilizon, Mobilizon.Service.SiteMap,
|
||||||
|
path: System.get_env("MOBILIZON_SITEMAP_PATH", "/var/lib/mobilizon/sitemap")
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
# Import environment specific config. This must remain at the bottom
|
||||||
# of this file so it overrides the configuration defined above.
|
# of this file so it overrides the configuration defined above.
|
||||||
import_config "#{config_env()}.exs"
|
import_config "#{config_env()}.exs"
|
||||||
|
|
|
@ -92,6 +92,9 @@ config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "uploads"
|
||||||
|
|
||||||
config :mobilizon, :exports, path: "uploads/exports"
|
config :mobilizon, :exports, path: "uploads/exports"
|
||||||
|
|
||||||
|
config :mobilizon, Mobilizon.Service.SiteMap,
|
||||||
|
path: System.get_env("MOBILIZON_SITEMAP_PATH", "priv/static")
|
||||||
|
|
||||||
config :tz_world, data_dir: "_build/dev/lib/tz_world/priv"
|
config :tz_world, data_dir: "_build/dev/lib/tz_world/priv"
|
||||||
|
|
||||||
config :mobilizon, :anonymous,
|
config :mobilizon, :anonymous,
|
||||||
|
|
|
@ -62,6 +62,9 @@ config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "test/uploads"
|
||||||
|
|
||||||
config :mobilizon, :exports, path: "test/uploads/exports"
|
config :mobilizon, :exports, path: "test/uploads/exports"
|
||||||
|
|
||||||
|
config :mobilizon, Mobilizon.Service.SiteMap,
|
||||||
|
path: System.get_env("MOBILIZON_SITEMAP_PATH", "test/sitemap")
|
||||||
|
|
||||||
config :tz_world, data_dir: "_build/test/lib/tz_world/priv"
|
config :tz_world, data_dir: "_build/test/lib/tz_world/priv"
|
||||||
|
|
||||||
config :tesla, Mobilizon.Service.HTTP.ActivityPub,
|
config :tesla, Mobilizon.Service.HTTP.ActivityPub,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM elixir as build
|
FROM elixir:1.15 as build
|
||||||
SHELL ["/bin/bash", "-c"]
|
SHELL ["/bin/bash", "-c"]
|
||||||
ENV MIX_ENV prod
|
ENV MIX_ENV prod
|
||||||
# ENV LANG en_US.UTF-8
|
# ENV LANG en_US.UTF-8
|
||||||
|
@ -12,7 +12,7 @@ ENV ERL_FLAGS=$ERL_FLAGS
|
||||||
# Set the right versions
|
# Set the right versions
|
||||||
ENV ELIXIR_VERSION latest
|
ENV ELIXIR_VERSION latest
|
||||||
ENV ERLANG_VERSION latest
|
ENV ERLANG_VERSION latest
|
||||||
ENV NODE_VERSION 16
|
ENV NODE_VERSION 18
|
||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN apt-get update -yq && apt-get install -yq build-essential cmake postgresql-client git curl gnupg unzip exiftool webp imagemagick gifsicle
|
RUN apt-get update -yq && apt-get install -yq build-essential cmake postgresql-client git curl gnupg unzip exiftool webp imagemagick gifsicle
|
||||||
|
|
|
@ -10,7 +10,7 @@ RUN yarn install --network-timeout 100000 \
|
||||||
&& yarn run build
|
&& yarn run build
|
||||||
|
|
||||||
# Then, build the application binary
|
# Then, build the application binary
|
||||||
FROM elixir:1.14-alpine AS builder
|
FROM elixir:1.15-alpine AS builder
|
||||||
|
|
||||||
# Fix qemu segfault on arm64
|
# Fix qemu segfault on arm64
|
||||||
# See https://github.com/plausible/analytics/pull/2879 and https://github.com/erlang/otp/pull/6340
|
# See https://github.com/plausible/analytics/pull/2879 and https://github.com/erlang/otp/pull/6340
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "-- Waiting for database..."
|
echo "-- Waiting for database..."
|
||||||
while ! pg_isready -U ${MOBILIZON_DATABASE_USERNAME} -d postgres://${MOBILIZON_DATABASE_HOST}:5432/${MOBILIZON_DATABASE_DBNAME} -t 1; do
|
while ! pg_isready -U ${MOBILIZON_DATABASE_USERNAME} -d postgres://${MOBILIZON_DATABASE_HOST}:${MOBILIZON_DATABASE_PORT:-5432}/${MOBILIZON_DATABASE_DBNAME} -t 1; do
|
||||||
sleep 1s
|
sleep 1s
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -2,37 +2,32 @@ import { SEARCH_PERSONS } from "@/graphql/search";
|
||||||
import { VueRenderer } from "@tiptap/vue-3";
|
import { VueRenderer } from "@tiptap/vue-3";
|
||||||
import tippy from "tippy.js";
|
import tippy from "tippy.js";
|
||||||
import MentionList from "./MentionList.vue";
|
import MentionList from "./MentionList.vue";
|
||||||
import { apolloClient } from "@/vue-apollo";
|
import { apolloClient, waitApolloQuery } from "@/vue-apollo";
|
||||||
import { IPerson } from "@/types/actor";
|
import { IPerson } from "@/types/actor";
|
||||||
import pDebounce from "p-debounce";
|
import pDebounce from "p-debounce";
|
||||||
import { MentionOptions } from "@tiptap/extension-mention";
|
import { MentionOptions } from "@tiptap/extension-mention";
|
||||||
import { Editor } from "@tiptap/core";
|
import { Editor } from "@tiptap/core";
|
||||||
import { provideApolloClient, useQuery } from "@vue/apollo-composable";
|
import { provideApolloClient, useQuery } from "@vue/apollo-composable";
|
||||||
import { Paginate } from "@/types/paginate";
|
import { Paginate } from "@/types/paginate";
|
||||||
import { onError } from "@apollo/client/link/error";
|
|
||||||
|
|
||||||
const fetchItems = (query: string): Promise<IPerson[]> => {
|
const fetchItems = async (query: string): Promise<IPerson[]> => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
const { onResult } = provideApolloClient(apolloClient)(() => {
|
if (query === "") return [];
|
||||||
return useQuery<{ searchPersons: Paginate<IPerson> }>(
|
const res = await waitApolloQuery(
|
||||||
SEARCH_PERSONS,
|
provideApolloClient(apolloClient)(() => {
|
||||||
() => ({
|
return useQuery<
|
||||||
variables: {
|
{ searchPersons: Paginate<IPerson> },
|
||||||
|
{ searchText: string }
|
||||||
|
>(SEARCH_PERSONS, () => ({
|
||||||
searchText: query,
|
searchText: query,
|
||||||
},
|
}));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
return res.data.searchPersons.elements;
|
||||||
|
} catch (e) {
|
||||||
onResult(({ data }) => {
|
console.error(e);
|
||||||
resolve(data.searchPersons.elements);
|
return [];
|
||||||
});
|
}
|
||||||
|
|
||||||
onError(reject);
|
|
||||||
});
|
|
||||||
|
|
||||||
// // TipTap doesn't handle async for onFilter, hence the following line.
|
|
||||||
// return result.data.searchPersons.elements;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const debouncedFetchItems = pDebounce(fetchItems, 200);
|
const debouncedFetchItems = pDebounce(fetchItems, 200);
|
||||||
|
@ -68,6 +63,10 @@ const mentionOptions: MentionOptions = {
|
||||||
editor: props.editor,
|
editor: props.editor,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!props.clientRect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
popup = tippy("body", {
|
popup = tippy("body", {
|
||||||
getReferenceClientRect: props.clientRect,
|
getReferenceClientRect: props.clientRect,
|
||||||
appendTo: () => document.body,
|
appendTo: () => document.body,
|
||||||
|
@ -86,6 +85,12 @@ const mentionOptions: MentionOptions = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onKeyDown(props: any) {
|
onKeyDown(props: any) {
|
||||||
|
if (props.event.key === "Escape") {
|
||||||
|
popup[0].hide();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return component.ref?.onKeyDown(props);
|
return component.ref?.onKeyDown(props);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="items">
|
<div class="relative border overflow-hidden dark:border-transparent">
|
||||||
<button
|
<button
|
||||||
class="item"
|
class="block w-full text-start bg-white dark:bg-violet-1 border py-1 px-2 rounded dark:border-transparent"
|
||||||
:class="{ 'is-selected': index === selectedIndex }"
|
:class="{ 'border-black dark:!border-white': index === selectedIndex }"
|
||||||
v-for="(item, index) in items"
|
v-for="(item, index) in items"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="selectItem(index)"
|
@click="selectItem(index)"
|
||||||
|
@ -34,37 +34,37 @@ watch(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// const onKeyDown = ({ event }: { event: KeyboardEvent }): boolean => {
|
const onKeyDown = ({ event }: { event: KeyboardEvent }): boolean => {
|
||||||
// if (event.key === "ArrowUp") {
|
if (event.key === "ArrowUp") {
|
||||||
// upHandler();
|
upHandler();
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (event.key === "ArrowDown") {
|
if (event.key === "ArrowDown") {
|
||||||
// downHandler();
|
downHandler();
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
// enterHandler();
|
enterHandler();
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return false;
|
return false;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const upHandler = (): void => {
|
const upHandler = (): void => {
|
||||||
// selectedIndex.value =
|
selectedIndex.value =
|
||||||
// (selectedIndex.value + props.items.length - 1) % props.items.length;
|
(selectedIndex.value + props.items.length - 1) % props.items.length;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const downHandler = (): void => {
|
const downHandler = (): void => {
|
||||||
// selectedIndex.value = (selectedIndex.value + 1) % props.items.length;
|
selectedIndex.value = (selectedIndex.value + 1) % props.items.length;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const enterHandler = (): void => {
|
const enterHandler = (): void => {
|
||||||
// selectItem(selectedIndex.value);
|
selectItem(selectedIndex.value);
|
||||||
// };
|
};
|
||||||
|
|
||||||
const selectItem = (index: number): void => {
|
const selectItem = (index: number): void => {
|
||||||
const item = props.items[index];
|
const item = props.items[index];
|
||||||
|
@ -73,27 +73,8 @@ const selectItem = (index: number): void => {
|
||||||
props.command({ id: usernameWithDomain(item) });
|
props.command({ id: usernameWithDomain(item) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
onKeyDown,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.items {
|
|
||||||
position: relative;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
background: white;
|
|
||||||
color: rgba(black, 0.8);
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 1px rgba(0, 0, 0, 0.1),
|
|
||||||
0px 10px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
text-align: left;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -657,4 +657,8 @@ onBeforeUnmount(() => {
|
||||||
.menubar__button.is-active {
|
.menubar__button.is-active {
|
||||||
@apply bg-zinc-300 dark:bg-zinc-500;
|
@apply bg-zinc-300 dark:bg-zinc-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mention[data-id] {
|
||||||
|
@apply inline-block border border-zinc-600 dark:border-zinc-300 rounded py-0.5 px-1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
import { FILTER_TAGS } from "@/graphql/tags";
|
import { FILTER_TAGS } from "@/graphql/tags";
|
||||||
import { ITag } from "@/types/tag.model";
|
import { ITag } from "@/types/tag.model";
|
||||||
import { apolloClient } from "@/vue-apollo";
|
import { apolloClient, waitApolloQuery } from "@/vue-apollo";
|
||||||
import { provideApolloClient, useQuery } from "@vue/apollo-composable";
|
import { provideApolloClient, useQuery } from "@vue/apollo-composable";
|
||||||
|
|
||||||
export function fetchTags(text: string): Promise<ITag[]> {
|
export async function fetchTags(text: string): Promise<ITag[]> {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
const { onResult, onError } = provideApolloClient(apolloClient)(() =>
|
const res = await waitApolloQuery(
|
||||||
|
provideApolloClient(apolloClient)(() =>
|
||||||
useQuery<{ tags: ITag[] }, { filter: string }>(FILTER_TAGS, {
|
useQuery<{ tags: ITag[] }, { filter: string }>(FILTER_TAGS, {
|
||||||
filter: text,
|
filter: text,
|
||||||
})
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
return res.data.tags;
|
||||||
onResult((result) => {
|
} catch (e) {
|
||||||
if (result.loading) {
|
console.error(e);
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
return resolve(result.data.tags);
|
|
||||||
});
|
|
||||||
|
|
||||||
onError((error) => reject(error));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -620,4 +620,8 @@ useHead({
|
||||||
.event-description a {
|
.event-description a {
|
||||||
@apply inline-block p-1 bg-mbz-yellow-alt-200 text-black;
|
@apply inline-block p-1 bg-mbz-yellow-alt-200 text-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.event-description .mention.h-card {
|
||||||
|
@apply inline-block border border-zinc-600 dark:border-zinc-300 rounded py-0.5 px-1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -24,7 +24,7 @@ defmodule Mobilizon.Service.SiteMap do
|
||||||
|
|
||||||
config = [
|
config = [
|
||||||
store: Sitemapper.FileStore,
|
store: Sitemapper.FileStore,
|
||||||
store_config: [path: Application.app_dir(:mobilizon, "priv/static")],
|
store_config: [path: Application.get_env(:mobilizon, __MODULE__) |> get_in([:path])],
|
||||||
sitemap_url: Endpoint.url(),
|
sitemap_url: Endpoint.url(),
|
||||||
gzip: false
|
gzip: false
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue