v06.8 various bug fixes
This commit is contained in:
@@ -7,7 +7,7 @@ TZ=UTC
|
|||||||
# Copy this file to .env and customize
|
# Copy this file to .env and customize
|
||||||
|
|
||||||
# Image version to run (set by build.sh, or use 'latest')
|
# Image version to run (set by build.sh, or use 'latest')
|
||||||
JAMA_VERSION=0.6.7
|
JAMA_VERSION=0.6.8
|
||||||
|
|
||||||
# Default admin credentials (used on FIRST RUN only)
|
# Default admin credentials (used on FIRST RUN only)
|
||||||
ADMIN_NAME=Admin User
|
ADMIN_NAME=Admin User
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-backend",
|
"name": "jama-backend",
|
||||||
"version": "0.6.7",
|
"version": "0.6.8",
|
||||||
"description": "TeamChat backend server",
|
"description": "TeamChat backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ Welcome to **JAMA** — your private, self-hosted team messaging app.
|
|||||||
|
|
||||||
## Navigating JAMA
|
## Navigating JAMA
|
||||||
|
|
||||||
### PRIVACY ASSURED
|
|
||||||
The only people that can read your direct messages (person 2 person or group) are the members of the message group. No one else, including admins, know which message groups exist or which you are part of, unless an they are a member of a given group that you are.
|
|
||||||
|
|
||||||
Every user can, at minimum, read all public messages.
|
### 🛡️ Your Privacy Assured
|
||||||
|
The only people that can read your direct messages (person 2 person or group) are the members of the message group. No one else, including admins, know which message groups exist or which you are part of, unless an they are a member.
|
||||||
|
|
||||||
|
Every user, at minimum, can read all public messages.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ To create a group conversation:
|
|||||||
3. Enter a **Message Name**
|
3. Enter a **Message Name**
|
||||||
4. Click **Create**
|
4. Click **Create**
|
||||||
|
|
||||||
> If a group with the exact same members already exists, you will be redirected to it automatically to help avoid duplication.
|
> If a message group with the exact same members already exists, you will be redirected to it automatically. This helps to avoid duplication.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -97,8 +98,8 @@ Other members still see the original group name, unless they change to customise
|
|||||||
|
|
||||||
Admins can access **Settings** from the user menu to configure:
|
Admins can access **Settings** from the user menu to configure:
|
||||||
|
|
||||||
- Branding a new app name and logo
|
- Branding: a new app name and logo
|
||||||
- Set new user password
|
- User Manager: Set new user password
|
||||||
- Notification preferences
|
- Notification preferences
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.6.7}"
|
VERSION="${1:-0.6.8}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="jama"
|
IMAGE_NAME="jama"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-frontend",
|
"name": "jama-frontend",
|
||||||
"version": "0.6.7",
|
"version": "0.6.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export default function ProfileModal({ onClose }) {
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const [displayName, setDisplayName] = useState(user?.display_name || '');
|
const [displayName, setDisplayName] = useState(user?.display_name || '');
|
||||||
|
const [savedDisplayName, setSavedDisplayName] = useState(user?.display_name || '');
|
||||||
const [displayNameWarning, setDisplayNameWarning] = useState('');
|
const [displayNameWarning, setDisplayNameWarning] = useState('');
|
||||||
const [aboutMe, setAboutMe] = useState(user?.about_me || '');
|
const [aboutMe, setAboutMe] = useState(user?.about_me || '');
|
||||||
const [currentPw, setCurrentPw] = useState('');
|
const [currentPw, setCurrentPw] = useState('');
|
||||||
@@ -24,6 +25,7 @@ export default function ProfileModal({ onClose }) {
|
|||||||
try {
|
try {
|
||||||
const { user: updated } = await api.updateProfile({ displayName, aboutMe, hideAdminTag });
|
const { user: updated } = await api.updateProfile({ displayName, aboutMe, hideAdminTag });
|
||||||
updateUser(updated);
|
updateUser(updated);
|
||||||
|
setSavedDisplayName(displayName);
|
||||||
toast('Profile updated', 'success');
|
toast('Profile updated', 'success');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast(e.message, 'error');
|
toast(e.message, 'error');
|
||||||
@@ -100,24 +102,37 @@ export default function ProfileModal({ onClose }) {
|
|||||||
<div className="flex-col gap-3">
|
<div className="flex-col gap-3">
|
||||||
<div className="flex-col gap-1">
|
<div className="flex-col gap-1">
|
||||||
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)' }}>Display Name</label>
|
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)' }}>Display Name</label>
|
||||||
<input
|
<div className="flex gap-2">
|
||||||
className="input"
|
<input
|
||||||
value={displayName}
|
className="input flex-1"
|
||||||
onChange={async e => {
|
value={displayName}
|
||||||
const val = e.target.value;
|
onChange={async e => {
|
||||||
setDisplayName(val);
|
const val = e.target.value;
|
||||||
setDisplayNameWarning('');
|
setDisplayName(val);
|
||||||
if (val && val !== user?.display_name) {
|
setDisplayNameWarning('');
|
||||||
try {
|
if (val && val !== user?.display_name) {
|
||||||
const { taken } = await api.checkDisplayName(val);
|
try {
|
||||||
if (taken) setDisplayNameWarning('Display name is already in use');
|
const { taken } = await api.checkDisplayName(val);
|
||||||
} catch {}
|
if (taken) setDisplayNameWarning('Display name is already in use');
|
||||||
}
|
} catch {}
|
||||||
}}
|
}
|
||||||
placeholder={user?.name}
|
}}
|
||||||
style={{ borderColor: displayNameWarning ? '#e53935' : undefined }}
|
placeholder={user?.name}
|
||||||
/>
|
style={{ borderColor: displayNameWarning ? '#e53935' : undefined }}
|
||||||
|
/>
|
||||||
|
{displayName !== savedDisplayName ? null : savedDisplayName ? (
|
||||||
|
<button
|
||||||
|
className="btn btn-sm"
|
||||||
|
style={{ background: 'var(--surface-variant)', color: 'var(--text-secondary)', flexShrink: 0 }}
|
||||||
|
onClick={() => setDisplayName('')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
{displayNameWarning && <span className="text-xs" style={{ color: '#e53935' }}>{displayNameWarning}</span>}
|
{displayNameWarning && <span className="text-xs" style={{ color: '#e53935' }}>{displayNameWarning}</span>}
|
||||||
|
{savedDisplayName && <span className="text-xs" style={{ color: 'var(--text-tertiary)' }}>Username: {user?.name}</span>}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-col gap-1">
|
<div className="flex-col gap-1">
|
||||||
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)' }}>About Me</label>
|
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)' }}>About Me</label>
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ a { color: inherit; text-decoration: none; }
|
|||||||
--border: #2e2e45;
|
--border: #2e2e45;
|
||||||
--text-primary: #e2e2f0;
|
--text-primary: #e2e2f0;
|
||||||
--text-secondary: #9898b8;
|
--text-secondary: #9898b8;
|
||||||
--text-tertiary: #6060808;
|
--text-tertiary: #606080;
|
||||||
--bubble-out: #4d8fd4;
|
--bubble-out: #4d8fd4;
|
||||||
--bubble-in: #252535;
|
--bubble-in: #252535;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,11 +121,18 @@ export default function Chat() {
|
|||||||
// Update group preview text
|
// Update group preview text
|
||||||
setGroups(prev => {
|
setGroups(prev => {
|
||||||
const updateGroup = (g) => g.id === msg.group_id
|
const updateGroup = (g) => g.id === msg.group_id
|
||||||
? { ...g, last_message: msg.content || (msg.image_url ? '📷 Image' : ''), last_message_at: msg.created_at }
|
? { ...g, last_message: msg.content || (msg.image_url ? '📷 Image' : ''), last_message_at: msg.created_at, last_message_user_id: msg.user_id }
|
||||||
: g;
|
: g;
|
||||||
|
const updatedPrivate = prev.privateGroups.map(updateGroup)
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (!a.last_message_at && !b.last_message_at) return 0;
|
||||||
|
if (!a.last_message_at) return 1;
|
||||||
|
if (!b.last_message_at) return -1;
|
||||||
|
return new Date(b.last_message_at) - new Date(a.last_message_at);
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
publicGroups: prev.publicGroups.map(updateGroup),
|
publicGroups: prev.publicGroups.map(updateGroup),
|
||||||
privateGroups: prev.privateGroups.map(updateGroup),
|
privateGroups: updatedPrivate,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// Don't badge own messages
|
// Don't badge own messages
|
||||||
|
|||||||
Reference in New Issue
Block a user