mirror of
https://github.com/immich-app/immich.git
synced 2026-06-23 23:18:26 -07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11f61f23ba | |||
| 226fab849c | |||
| d39bd2e6cc | |||
| e4cf79263b |
@@ -5,25 +5,32 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/presentation/actions/partner.action.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||
import 'package:immich_mobile/providers/user.provider.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import '../../factories/user_factory.dart';
|
||||
import '../../mocks.dart';
|
||||
import '../../presentation_context.dart';
|
||||
|
||||
void main() {
|
||||
late PresentationContext context;
|
||||
late UserDto currentUser;
|
||||
final mocks = ServiceMocks();
|
||||
|
||||
setUp(() async {
|
||||
currentUser = UserFactory.createDto();
|
||||
context = await PresentationContext.create();
|
||||
when(mocks.user.tryGetMyUser).thenReturn(currentUser);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
context.dispose();
|
||||
tearDown(() async {
|
||||
mocks.resetAll();
|
||||
await context.dispose();
|
||||
});
|
||||
|
||||
List<Override> overrides({List<User> candidates = const []}) => [
|
||||
...context.overrides,
|
||||
partnerServiceProvider.overrideWithValue(context.mocks.partner.service),
|
||||
currentUserProvider.overrideWith((ref) => CurrentUserProvider(mocks.user.service)),
|
||||
partnerServiceProvider.overrideWithValue(mocks.partner.service),
|
||||
candidatesStateProvider.overrideWith((ref) => Stream<Iterable<User>>.value(candidates)),
|
||||
];
|
||||
|
||||
@@ -36,9 +43,7 @@ void main() {
|
||||
await tester.tap(find.text(candidate.name));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verify(
|
||||
() => context.mocks.partner.service.create(sharedById: context.currentUser.id, sharedWithId: candidate.id),
|
||||
).called(1);
|
||||
verify(() => mocks.partner.service.create(sharedById: currentUser.id, sharedWithId: candidate.id)).called(1);
|
||||
});
|
||||
|
||||
testWidgets('creates nothing when the selection dialog is dismissed', (tester) async {
|
||||
@@ -46,7 +51,7 @@ void main() {
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape); // dismiss without selecting
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verifyNever(context.mocks.partner.create);
|
||||
verifyNever(mocks.partner.create);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,9 +65,7 @@ void main() {
|
||||
await tester.tap(find.byType(TextButton).last); // confirm
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verify(
|
||||
() => context.mocks.partner.service.delete(sharedById: context.currentUser.id, sharedWithId: partner.id),
|
||||
).called(1);
|
||||
verify(() => mocks.partner.service.delete(sharedById: currentUser.id, sharedWithId: partner.id)).called(1);
|
||||
});
|
||||
|
||||
testWidgets('deletes nothing when the confirmation is cancelled', (tester) async {
|
||||
@@ -74,7 +77,7 @@ void main() {
|
||||
await tester.tap(find.byType(TextButton).first); // cancel
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verifyNever(context.mocks.partner.delete);
|
||||
verifyNever(mocks.partner.delete);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ void main() {
|
||||
late PresentationContext context;
|
||||
|
||||
setUp(() async => context = await PresentationContext.create());
|
||||
tearDown(() => context.dispose());
|
||||
tearDown(() async => await context.dispose());
|
||||
|
||||
group('PartnerSharedByList', () {
|
||||
testWidgets('shows the empty-state add button when there are no partners', (tester) async {
|
||||
|
||||
@@ -23,7 +23,7 @@ import 'mocks.dart';
|
||||
|
||||
class PresentationContext {
|
||||
PresentationContext._({required UserDto user}) : currentUser = user, mocks = ServiceMocks() {
|
||||
setup();
|
||||
when(mocks.user.tryGetMyUser).thenReturn(currentUser);
|
||||
}
|
||||
|
||||
static const String serverEndpoint = 'http://localhost:3000';
|
||||
@@ -46,14 +46,10 @@ class PresentationContext {
|
||||
return PresentationContext._(user: UserFactory.createDto());
|
||||
}
|
||||
|
||||
void setup() {
|
||||
when(mocks.user.tryGetMyUser).thenReturn(currentUser);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
addTearDown(() {
|
||||
mocks.resetAll();
|
||||
});
|
||||
Future<void> dispose() async {
|
||||
// TODO: Dispose the store and database after each test.
|
||||
// This is currently not possible because the store is a singleton and is used across tests.
|
||||
// Refactor the store to be created per test to allow proper disposal.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,6 +291,40 @@
|
||||
"required": ["albumIds"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "assetDataWebhook",
|
||||
"title": "Trigger Webhook",
|
||||
"description": "POST/PUT event data to any URL",
|
||||
"types": ["AssetV1"],
|
||||
"hostFunctions": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "URL",
|
||||
"description": "Event data will be PUT/POSTed to this URL as a JSON object"
|
||||
},
|
||||
"headerName": {
|
||||
"type": "string",
|
||||
"title": "Header name",
|
||||
"description": "The name of an additional header to include with the request (e.g. authentication)"
|
||||
},
|
||||
"headerValue": {
|
||||
"type": "string",
|
||||
"title": "Header value",
|
||||
"description": "The value of the additional header"
|
||||
},
|
||||
"method": {
|
||||
"type": "string",
|
||||
"title": "Method",
|
||||
"description": "The HTTP method to use in the request",
|
||||
"enum": ["POST", "PUT"]
|
||||
}
|
||||
},
|
||||
"required": ["url"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "noop1",
|
||||
"title": "DEV: Nested properties",
|
||||
|
||||
Vendored
+1
@@ -24,4 +24,5 @@ declare module 'main' {
|
||||
export function assetTimeline(): I32;
|
||||
export function assetTrash(): I32;
|
||||
export function assetAddToAlbums(): I32;
|
||||
export function assetDataWebhook(): I32;
|
||||
}
|
||||
|
||||
@@ -181,3 +181,23 @@ export const assetAddToAlbums = () => {
|
||||
return {};
|
||||
});
|
||||
};
|
||||
|
||||
export const assetDataWebhook = () => {
|
||||
return wrapper<WorkflowType.AssetV1, { url: string; headerName?: string; headerValue?: string; method?: string }>(
|
||||
({ config, data }) => {
|
||||
const headers = new Headers({ 'Content-Type': 'application/json' });
|
||||
|
||||
if (config.headerName && config.headerValue) {
|
||||
headers.set(config.headerName, config.headerValue);
|
||||
}
|
||||
|
||||
fetch(config.url, {
|
||||
method: config.method ?? 'POST',
|
||||
body: JSON.stringify(data.asset),
|
||||
headers,
|
||||
});
|
||||
|
||||
return {};
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"esModuleInterop": true, // Enables compatibility with Babel-style module imports
|
||||
"lib": ["es2020"], // Specify a list of library files to be included in the compilation
|
||||
"lib": ["es2020", "DOM"], // Specify a list of library files to be included in the compilation
|
||||
"module": "nodenext", // Specify module code generation
|
||||
"moduleResolution": "nodenext",
|
||||
"noEmit": true, // Do not emit outputs (no .js or .d.ts files)
|
||||
|
||||
@@ -33,6 +33,11 @@ type HostFunctionResult<T> =
|
||||
|
||||
type QueryParams<T extends (...args: any) => any> = Parameters<T>[0];
|
||||
type AlbumSearchDto = QueryParams<typeof getAllAlbums>;
|
||||
type HttpRequestOptions = {
|
||||
method?: string;
|
||||
headers?: Record<string, string>;
|
||||
body?: string;
|
||||
};
|
||||
|
||||
export const hostFunctions = (authToken: string) => {
|
||||
const host = Host.getFunctions();
|
||||
|
||||
@@ -216,6 +216,7 @@ export class PluginRepository {
|
||||
functions: {
|
||||
'extism:host/user': functions ?? {},
|
||||
},
|
||||
allowedHosts: runInWorker ? ['*'] : [],
|
||||
logger: {
|
||||
trace: (message) => logger.verbose(message),
|
||||
info: (message) => logger.log(message),
|
||||
|
||||
Reference in New Issue
Block a user