mirror of
https://github.com/mattermost/mattermost-mobile.git
synced 2026-11-09 04:30:14 +00:00
* Expo-Router partial migration * Full migration to ExpoRouter * i18n * add tests * library hardware-keyboard android new arch support fix * library rnshare android new arch support fix * library rnutils android new arch support fix * library secure-pdf-viewer add new arch support * Enable new arch on iOS and Android * update emm and network client with new-arch * update intune to use new-arch * performance improvements * fix tests * fixes post input on new-arch * Merge branch 'main' into expo-router * fix android emoji picker * align package-lock.json * i18n * feedback review * feedback review * android 16kb patch * Refactored emoji picker keyboard using a state machine * set android launch_screen in drawables instead of layout * no conditional hooks * remove duplicate call in test * address feedback * fix tests and address more feedback * small corrections * small corrections * small corrections * fix draft test * fix draft test 2 * remove navigateToScreen in draff test * fix nit in draft test * remove doc file * remove doc * run tests in parallel * Feedback review * fix snapshots * improve test coverage * fix i18n * upgrade to React Native 0.83.9, Expo 55, React 19, and New Architecture Bumps core dependencies to their latest versions: - React Native 0.77.3 → 0.83.9 (New Architecture enabled) - React 18.3.1 → 19.2.5 - Expo SDK 52 → 55 - TypeScript 5.8.3 → 6.0.3 - Node.js 22.16.0 → 24.15.0 - react-native-reanimated 3.17.3 → 4.3.0 - Various other dependency upgrades Migrates iOS AppDelegate from Objective-C to Swift, updates Android build tooling and Gradle wrapper, refreshes all patches and font assets, and adapts app code, tests, and CI workflows throughout for API changes introduced by these upgrades. * remove unecessary dismissKeyboard in notifications * feedback review * update intune to use new-arch * update @mattermost deps * missing i18n string * additional fixes * update fastlane * Re-implementing global classification banners on top of rn83 * Refactoring to de-couple the classification banner from the layout * Implementing per-channel banners on mobile * Removing custom header in favor of common component * Making fixes for coderabbit * Improving padding calculation * Converting global classification banner to use portals * Removing dead code, adding deletion check * Addressing dryrun securit concerns * Removing call for template field, improving consistency * MM-68208 Storing system property values in WatermelonDB (#9781) * Added persistence layer to system properties * Making debounce behavior more consistent * Cleaning up debounce logic from store persistence * Addressing PR feedback * Removing ephemeral store usage and employing observables - Changing name of group to access_control * Updating unit tests * Refactoring to improve code consistency - Removing any patterns introduced that weren't already established in the repo - Removing hooks with database reads in favor of withObservables and withDatabase pattern - Simplifying _layout.tsx by removing inset modification, now handled in the Container HoC component - Moved some repeated hook logic into its own utils file * Refactoring to use propertyfield and propertyvalue tables instead of system - Simplified remote actions to purely perform API call, and call a local action to sync values - Using local action layer to perform syncing and removal operations of property fields and values - Observables now pre-filter for active fields / values via querying for delete_at=0 * Improving consistency of local actions - Added unit tests for syncPropertyFieldsByGroupId, syncPropertyValuesByTargetId, clearClassificationData * Replacing local actions with operator handlers * Removing needless mocks from unit tests * Consolidating operator handlers - Leaving 1 handler for fields and 1 for values, each of them evaluating whether to delete or upsert values received in the function call * MM-68208 Making changes based on feedback - Removing !visible guard in global classification container - Increasing clarity of comment for clearing of stale fields - Updating log messages to be more clear * Batching database operations together for fields and values * Consolidating API call for fetching classification data - Preparation for caching mechanism * Updating field names to the unified classification * Updating E2E test values to match current field names --------- Co-authored-by: Elias Nahum <nahumhbl@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com>
95 lines
4.4 KiB
TypeScript
95 lines
4.4 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {
|
|
CLASSIFICATIONS_CHANNEL_OBJECT_TYPE,
|
|
CLASSIFICATIONS_FIELD_TARGET_ID,
|
|
CLASSIFICATIONS_FIELD_TARGET_TYPE,
|
|
CLASSIFICATIONS_FIELD_NAME,
|
|
CLASSIFICATIONS_GROUP_NAME,
|
|
CLASSIFICATIONS_SYSTEM_OBJECT_TYPE,
|
|
CLASSIFICATIONS_SYSTEM_VALUE_TARGET_ID,
|
|
} from '@constants/classification';
|
|
import DatabaseManager from '@database/manager';
|
|
import NetworkManager from '@managers/network_manager';
|
|
import {getPropertyFieldsByNames} from '@queries/servers/properties';
|
|
import {getConfigValue} from '@queries/servers/system';
|
|
import {logDebug, logError} from '@utils/log';
|
|
|
|
import {forceLogoutIfNecessary} from './session';
|
|
|
|
export async function fetchClassificationBanner(serverUrl: string): Promise<{error?: unknown}> {
|
|
try {
|
|
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const featureFlag = await getConfigValue(database, 'FeatureFlagClassificationMarkings');
|
|
|
|
if (featureFlag === 'true') {
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
|
|
const [systemFields, channelFields] = await Promise.all([
|
|
client.getPropertyFields(CLASSIFICATIONS_GROUP_NAME, CLASSIFICATIONS_SYSTEM_OBJECT_TYPE, CLASSIFICATIONS_FIELD_TARGET_TYPE, CLASSIFICATIONS_FIELD_TARGET_ID),
|
|
client.getPropertyFields(CLASSIFICATIONS_GROUP_NAME, CLASSIFICATIONS_CHANNEL_OBJECT_TYPE, CLASSIFICATIONS_FIELD_TARGET_TYPE, CLASSIFICATIONS_FIELD_TARGET_ID),
|
|
]);
|
|
|
|
const allFields = [...systemFields, ...channelFields];
|
|
|
|
if (allFields.length > 0) {
|
|
const groupId = allFields[0].group_id;
|
|
if (!groupId || allFields.some((f) => f.group_id !== groupId)) {
|
|
logError('fetchClassificationBanner', 'Unexpected classification fields');
|
|
return {};
|
|
}
|
|
|
|
const values = await client.getSystemPropertyValues<string>(CLASSIFICATIONS_GROUP_NAME);
|
|
|
|
const fieldModels = await operator.handlePropertyFields({groupId, fields: allFields, prepareRecordsOnly: true});
|
|
const valueModels = await operator.handlePropertyValues({targetId: CLASSIFICATIONS_SYSTEM_VALUE_TARGET_ID, values, prepareRecordsOnly: true});
|
|
await operator.batchRecords([...fieldModels, ...valueModels], 'fetchClassificationBanner');
|
|
|
|
return {};
|
|
}
|
|
|
|
logDebug('fetchClassificationBanner', 'No classification fields returned');
|
|
}
|
|
|
|
// Feature disabled or no active fields returned: remove any locally stored classification data.
|
|
// We look up the stored fields by name and re-submit them stamped with a non-zero delete_at.
|
|
// handlePropertyFields treats a non-zero delete_at as a deletion, so the operator removes those
|
|
// fields and cascades the removal to each field's property values in a single batch.
|
|
const stale = await getPropertyFieldsByNames(database, [CLASSIFICATIONS_FIELD_NAME]);
|
|
if (stale.length) {
|
|
await operator.handlePropertyFields({
|
|
fields: stale.map((f) => ({id: f.id, delete_at: Date.now()} as PropertyField)),
|
|
prepareRecordsOnly: false,
|
|
});
|
|
}
|
|
|
|
return {};
|
|
} catch (error) {
|
|
logError('fetchClassificationBanner', 'Failed to fetch classification banner data', error);
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
}
|
|
|
|
export async function fetchChannelClassificationValue(serverUrl: string, channelId: string): Promise<{error?: unknown}> {
|
|
try {
|
|
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const featureFlag = await getConfigValue(database, 'FeatureFlagClassificationMarkings');
|
|
if (featureFlag !== 'true') {
|
|
return {};
|
|
}
|
|
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
const values = await client.getPropertyValues<string>(CLASSIFICATIONS_GROUP_NAME, CLASSIFICATIONS_CHANNEL_OBJECT_TYPE, channelId);
|
|
|
|
await operator.handlePropertyValues({targetId: channelId, values, prepareRecordsOnly: false});
|
|
|
|
return {};
|
|
} catch (error) {
|
|
logError('fetchChannelClassificationValue', 'Failed to fetch channel classification value', error);
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
}
|