Skip to content

chore(cd): map dev branch to wire-builds branch #18828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4df6490
feat: creeate CellsRepository
olafsulich Feb 24, 2025
f167b5f
Merge branch 'dev' of github.com:wireapp/wire-webapp into feat/cells-…
olafsulich Feb 24, 2025
d81043a
feat: cells draft
olafsulich Feb 24, 2025
df9c184
chore: reverse webpack changes
olafsulich Feb 24, 2025
df97145
feat: remove unsued code
olafsulich Feb 26, 2025
09bbf74
feat: add loading state to preview cards
olafsulich Feb 27, 2025
b6fb146
feat(FilePrevious): add card states
olafsulich Feb 28, 2025
d4c3e42
chore: update packages
olafsulich Mar 4, 2025
9aba431
feat(Conversation): create ConversationFileDropzone for switching bet…
olafsulich Mar 4, 2025
7cec9f4
feat(Conversation): add file sharing permission check before upload
olafsulich Mar 4, 2025
64b0f84
feat: enhance file uploading errors
olafsulich Mar 4, 2025
d554cbe
feat(i18n): add localization for file preview error actions
olafsulich Mar 4, 2025
1543667
chore: merge dev
olafsulich Mar 4, 2025
a97dc2f
refactor: replace spinner with FilePreviewSpinner component in AudioP…
olafsulich Mar 4, 2025
a8b5419
refactor: update file preview components to use non-optional loading …
olafsulich Mar 4, 2025
5ace3b5
refactor: improve file preview error and loading state rendering
olafsulich Mar 4, 2025
12a46b2
feat(i18n): add aria-label for file preview error more options button
olafsulich Mar 4, 2025
6ac5f57
refactor: simplify file preview rendering condition
olafsulich Mar 4, 2025
8fdd8dd
refactor: add fallback values for API client configuration
olafsulich Mar 4, 2025
05d37ab
chore: update @wireapp/core and @wireapp/api-client dependencies
olafsulich Mar 4, 2025
48f6cf0
feat: improve file preview error state visualization
olafsulich Mar 4, 2025
b3f7697
refactor: simplify APIClient configuration access
olafsulich Mar 4, 2025
a6c65f9
test: mock auto-animate for testing
olafsulich Mar 4, 2025
1bbcc82
refactor: remove null coalescing for API client configuration
olafsulich Mar 4, 2025
f2a97ee
fix: disable cells feature in conversation file dropzone
olafsulich Mar 4, 2025
caf24a5
chore(cd): map dev branch to wire-builds branch
lwille Mar 4, 2025
fbf421a
chore(cd): run publish workflow for feature branch
lwille Mar 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Publish

on:
push:
branches: [master, dev, release/*, new-navigation]
branches: [master, dev, release/*, new-navigation, feat/cells-service-api-deploy-to-imai]
tags:
- '*q1-2024*'
- '*staging*'
Expand Down Expand Up @@ -196,6 +196,9 @@ jobs:
},
"q1-2024": {
"targets": "[\"q1-2024\"]"
},
"feat/cells-service-api": {
"targets": "[\"wire-cells-dev\"]"
}
}
export_to: log,output
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@wireapp/avs": "9.10.25",
"@wireapp/avs-debugger": "0.0.7",
"@wireapp/commons": "5.4.2",
"@wireapp/core": "46.19.5",
"@wireapp/core": "46.19.6",
"@wireapp/react-ui-kit": "9.38.0",
"@wireapp/store-engine-dexie": "2.1.15",
"@wireapp/telemetry": "0.3.1",
Expand Down
7 changes: 7 additions & 0 deletions server/config/client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ export function generateConfig(params: ConfigGeneratorParams, env: Env) {
BACKEND_REST: urls.api ?? '',
BACKEND_WS: urls.ws ?? '',
BRAND_NAME: env.BRAND_NAME,
CELLS_PYDIO_API_KEY: env.CELLS_PYDIO_API_KEY,
CELLS_PYDIO_SEGMENT: env.CELLS_PYDIO_SEGMENT,
CELLS_PYDIO_URL: env.CELLS_PYDIO_URL,
CELLS_S3_API_KEY: env.CELLS_S3_API_KEY,
CELLS_S3_BUCKET: env.CELLS_S3_BUCKET,
CELLS_S3_REGION: env.CELLS_S3_REGION,
CELLS_S3_ENDPOINT: env.CELLS_S3_ENDPOINT,
COUNTLY_API_KEY: env.COUNTLY_API_KEY,
COUNTLY_ENABLE_LOGGING: env.COUNTLY_ENABLE_LOGGING == 'true',
COUNTLY_FORCE_REPORTING: env.COUNTLY_FORCE_REPORTING == 'true',
Expand Down
9 changes: 9 additions & 0 deletions server/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ export type Env = {
/** Specifies the name of the application, e.g. Webapp */
APP_NAME: string;

/** Specifies configuration for Cells */
CELLS_PYDIO_API_KEY: string;
CELLS_PYDIO_SEGMENT: string;
CELLS_PYDIO_URL: string;
CELLS_S3_API_KEY: string;
CELLS_S3_BUCKET: string;
CELLS_S3_REGION: string;
CELLS_S3_ENDPOINT: string;

/** Specifies the name of the backend, e.g. Wire */
BACKEND_NAME: string;

Expand Down
2 changes: 1 addition & 1 deletion server/config/server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ROBOTS_ALLOW_FILE = path.join(ROBOTS_DIR, 'robots.txt');
const ROBOTS_DISALLOW_FILE = path.join(ROBOTS_DIR, 'robots-disallow.txt');

const defaultCSP = {
connectSrc: ["'self'", 'blob:', 'data:', 'https://*.giphy.com'],
connectSrc: ["'self'", 'blob:', 'data:', 'https://*.giphy.com', 'https://service.zeta.pydiocells.com'],
defaultSrc: ["'self'"],
fontSrc: ["'self'", 'data:'],
frameSrc: [
Expand Down
4 changes: 4 additions & 0 deletions setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ Object.defineProperty(document, 'elementFromPoint', {

const testLib = require('@testing-library/react');
testLib.configure({testIdAttribute: 'data-uie-name'});

jest.mock('@formkit/auto-animate/react', () => ({
useAutoAnimate: () => [null, () => {}],
}));
5 changes: 4 additions & 1 deletion src/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@
"conversationFileUploadFailedTooLargeImagesMessage": "Please select images smaller than {maxSize}MB.",
"conversationFileUploadFailedTooLargeFilesAndImagesMessage": "Please select files smaller than {maxImageSize}MB and images smaller than {maxFileSize}MB.",
"conversationFileUploadOverlayTitle": "Upload files",
"conversationFilePreviewErrorMoreOptions": "More options",
"conversationFilePreviewErrorRetry": "Retry",
"conversationFilePreviewErrorRemove": "Remove",
"conversationFileUploadOverlayDescription": "Drag & drop to add files",
"conversationFoldersEmptyText": "Add your conversations to folders to stay organized.",
"conversationFoldersEmptyTextLearnMore": "Learn more",
Expand Down Expand Up @@ -1754,4 +1757,4 @@
"paginationLeftArrowAriaLabel": "Go to previous page",
"paginationRightArrowAriaLabel": "Go to next page",
"paginationDotAriaLabel": "Go to page {page}"
}
}
47 changes: 47 additions & 0 deletions src/script/cells/CellsRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {container} from 'tsyringe';

import {createUuid} from 'Util/uuid';

import {APIClient} from '../service/APIClientSingleton';

export class CellsRepository {
private readonly basePath = 'wire-cells-web';
constructor(private readonly apiClient = container.resolve(APIClient)) {}

async uploadFile(file: File): Promise<{uuid: string; versionId: string}> {
const path = `${this.basePath}/${encodeURIComponent(file.name)}`;

const uuid = createUuid();
const versionId = createUuid();

await this.apiClient.api.cells.uploadFileDraft({filePath: path, file, uuid, versionId});

return {
uuid,
versionId,
};
}

async deleteFileDraft({uuid, versionId}: {uuid: string; versionId: string}) {
return this.apiClient.api.cells.deleteFileDraft({uuid, versionId});
}
}
17 changes: 8 additions & 9 deletions src/script/components/Conversation/Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@

import {UIEvent, useCallback, useEffect, useState} from 'react';

import cx from 'classnames';
import {container} from 'tsyringe';

import {useMatchMedia} from '@wireapp/react-ui-kit';

import {CallingCell} from 'Components/calling/CallingCell';
import {DropFileArea} from 'Components/DropFileArea';
import {Giphy} from 'Components/Giphy';
import {InputBar} from 'Components/InputBar';
import {MessagesList} from 'Components/MessagesList';
Expand All @@ -42,8 +40,9 @@ import {isHittingUploadLimit} from 'Util/isHittingUploadLimit';
import {t} from 'Util/LocalizerUtil';
import {getLogger} from 'Util/Logger';
import {safeMailOpen, safeWindowOpen} from 'Util/SanitizationUtil';
import {formatBytes, incomingCssClass, removeAnimationsClass} from 'Util/util';
import {formatBytes} from 'Util/util';

import {ConversationFileDropzone} from './ConversationFileDropzone/ConversationFileDropzone';
import {useReadReceiptSender} from './hooks/useReadReceipt';
import {ReadOnlyConversationMessage} from './ReadOnlyConversationMessage';
import {checkFileSharingPermission} from './utils/checkFileSharingPermission';
Expand Down Expand Up @@ -463,12 +462,12 @@ export const Conversation = ({
);

return (
<DropFileArea
<ConversationFileDropzone
inTeam={inTeam}
isCellsEnabled={false}
isConversationLoaded={isConversationLoaded}
activeConversationId={activeConversation?.id}
onFileDropped={checkFileSharingPermission(uploadDroppedFiles)}
id="conversation"
className={cx('conversation', {[incomingCssClass]: isConversationLoaded, loading: !isConversationLoaded})}
ref={removeAnimationsClass}
key={activeConversation?.id}
>
{activeConversation && (
<>
Expand Down Expand Up @@ -561,6 +560,6 @@ export const Conversation = ({
{isGiphyModalOpen && inputValue && (
<Giphy giphyRepository={repositories.giphy} inputValue={inputValue} onClose={closeGiphy} />
)}
</DropFileArea>
</ConversationFileDropzone>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {ReactNode} from 'react';

import cx from 'classnames';

import {DropFileArea} from 'Components/DropFileArea';
import {incomingCssClass, removeAnimationsClass} from 'Util/util';

import {FileDropzone} from './FileDropzone/FileDropzone';

interface ConversationFileDropzoneProps {
inTeam: boolean;
isCellsEnabled: boolean;
isConversationLoaded: boolean;
activeConversationId?: string;
onFileDropped: (files: File[]) => void;
children: ReactNode;
}

export const ConversationFileDropzone = ({
inTeam,
isCellsEnabled,
isConversationLoaded,
activeConversationId,
onFileDropped,
children,
}: ConversationFileDropzoneProps) => {
if (isCellsEnabled) {
return (
<FileDropzone isTeam={inTeam}>
<div
id="conversation"
className={cx('conversation', {[incomingCssClass]: isConversationLoaded, loading: !isConversationLoaded})}
ref={removeAnimationsClass}
key={activeConversationId}
>
{children}
</div>
</FileDropzone>
);
}

return (
<DropFileArea
onFileDropped={onFileDropped}
id="conversation"
className={cx('conversation', {[incomingCssClass]: isConversationLoaded, loading: !isConversationLoaded})}
ref={removeAnimationsClass}
key={activeConversationId}
>
{children}
</DropFileArea>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
import {ReactNode, useEffect} from 'react';

import {FileRejection, useDropzone} from 'react-dropzone';
import {container} from 'tsyringe';

import {CellsRepository} from 'src/script/cells/CellsRepository';
import {Config} from 'src/script/Config';
import {t} from 'Util/LocalizerUtil';
import {getLogger} from 'Util/Logger';
import {createUuid} from 'Util/uuid';

import {wrapperStyles} from './FileDropzone.styles';
Expand All @@ -31,25 +34,42 @@ import {FileDropzoneOverlay} from './FileDropzoneOverlay/FileDropzoneOverlay';
import {validateFiles, ValidationResult} from './fileValidation/fileValidation';
import {useIsDragging} from './useIsDragging/useIsDragging';

import {useFileUploadState} from '../useFiles/useFiles';
import {checkFileSharingPermission} from '../utils/checkFileSharingPermission';
import {FileWithPreview, useFileUploadState} from '../../useFiles/useFiles';
import {checkFileSharingPermission} from '../../utils/checkFileSharingPermission';

interface FileDropzoneProps {
children: ReactNode;
isTeam: boolean;
cellsRepository?: CellsRepository;
}

const MAX_FILES = 10;

const CONFIG = Config.getConfig();

export const FileDropzone = ({isTeam, children}: FileDropzoneProps) => {
const logger = getLogger('FileDropzone');

export const FileDropzone = ({
isTeam,
cellsRepository = container.resolve(CellsRepository),
children,
}: FileDropzoneProps) => {
const {isDragging, wrapperRef} = useIsDragging();

const {addFiles, files} = useFileUploadState();
const {addFiles, files, updateFile} = useFileUploadState();

const MAX_SIZE = isTeam ? CONFIG.MAXIMUM_ASSET_FILE_SIZE_TEAM : CONFIG.MAXIMUM_ASSET_FILE_SIZE_PERSONAL;

const uploadFile = async (file: FileWithPreview) => {
try {
const {uuid, versionId} = await cellsRepository.uploadFile(file);
updateFile(file.id, {remoteUuid: uuid, remoteVersionId: versionId, uploadStatus: 'success'});
} catch (error) {
logger.error('Uploading file failed', error);
updateFile(file.id, {uploadStatus: 'error'});
}
};

const {getRootProps, getInputProps, isDragAccept} = useDropzone({
maxSize: MAX_SIZE,
noClick: true,
Expand Down Expand Up @@ -78,12 +98,20 @@ export const FileDropzone = ({isTeam, children}: FileDropzoneProps) => {
return Object.assign(file, {
id: createUuid(),
preview: URL.createObjectURL(file),
remoteUuid: '',
remoteVersionId: '',
uploadStatus: 'uploading' as const,
});
});

addFiles(acceptedFilesWithPreview);

acceptedFilesWithPreview.forEach(file => {
void uploadFile(file);
});
}),
onError: () => {
onError: (error: Error) => {
logger.error('Dropping files failed', error);
showFileDropzoneErrorModal({
title: t('conversationFileUploadFailedHeading'),
message: t('conversationFileUploadFailedMessage'),
Expand Down
28 changes: 28 additions & 0 deletions src/script/components/Conversation/useFiles/useFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,32 @@

import {create} from 'zustand';

export type FileUploadStatus = 'pending' | 'uploading' | 'success' | 'error';

export interface FileWithPreview extends File {
id: string;
preview: string;
remoteUuid: string;
remoteVersionId: string;
uploadStatus: FileUploadStatus;
}

interface FileUploadState {
files: FileWithPreview[];
addFiles: (files: FileWithPreview[]) => void;
deleteFile: (fileId: string) => void;
updateFile: (
fileId: string,
{
remoteUuid,
remoteVersionId,
uploadStatus,
}: {
remoteUuid?: string;
remoteVersionId?: string;
uploadStatus?: FileUploadStatus;
},
) => void;
}

export const useFileUploadState = create<FileUploadState>(set => ({
Expand All @@ -40,4 +57,15 @@ export const useFileUploadState = create<FileUploadState>(set => ({
set(state => ({
files: state.files.filter(file => file.id !== fileId),
})),
updateFile: (fileId, {remoteUuid, remoteVersionId, uploadStatus}) =>
set(state => ({
files: state.files.map(file => {
if (file.id === fileId) {
file.remoteUuid = remoteUuid ?? file.remoteUuid;
file.remoteVersionId = remoteVersionId ?? file.remoteVersionId;
file.uploadStatus = uploadStatus ?? file.uploadStatus;
}
return file;
}),
})),
}));
Loading
Loading