Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion src/Bones.UI/abstractions/inotifyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ export type AllEvent = NotifyEvent | "all";
export type AddOrUpdateCallback<TDetails> = (ev: AddOrUpdateEvent, payload: TDetails) => void;
export type DeleteCallback = (ev: DeleteEvent, id: any) => void;
export type ResetCallback = (ev: ResetEvent) => void;
export type AllCallback<TDetails> = AddOrUpdateCallback<TDetails> | DeleteCallback | ResetCallback;
export type AllCallback<TDetails> = AddOrUpdateCallback<TDetails> | DeleteCallback | ResetCallback;

export type SubscribeCall<TDetails> = [AddOrUpdateEvent, AddOrUpdateCallback<TDetails>] | [DeleteEvent, DeleteCallback] | [ResetEvent, ResetCallback] | [AllEvent, AllCallback<TDetails>];
24 changes: 24 additions & 0 deletions src/Bones.UI/composables/useDevMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ref, computed } from "vue";

import { EventQueue } from "../core/eventQueue";

const DEV_MODE_TOPIC = 'devMode';
const devMode = ref(false);

EventQueue.instance.subscribe(DEV_MODE_TOPIC, (_topic: string, payload: boolean) => {
devMode.value = payload;
console.log(`Dev mode is now ${devMode.value ? 'enabled' : 'disabled'}`);
});

export function useDevMode() {
const toggleDevMode = () => {
EventQueue.instance.publish(DEV_MODE_TOPIC, !devMode.value);
};

const isDevMode = computed(() => devMode.value);

return {
toggleDevMode,
isDevMode
};
}
11 changes: 9 additions & 2 deletions src/Bones.UI/composables/useTranslations.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { ref } from 'vue'
import { useDevMode } from './useDevMode';

const _translations = ref<{ code: string, value: string }[]>([]);

export function useTranslations() {

const { isDevMode } = useDevMode();

const $tr = (code: string, defaultValue: string, ...parameters: (string | number)[]): string => {
if (isDevMode.value) {
return code;
}

let translation = _translations.value.find(t => t.code === code)?.value ?? defaultValue;
if (translation && parameters.length) {
for (let p of parameters) {
translation = translation.replace(`{${parameters.indexOf(p)}}`, p.toString());
for (let i = 0; i < parameters.length; i++) {
translation = translation.replace(`{${i}}`, parameters[i].toString());
}
}
return translation;
Expand Down
21 changes: 21 additions & 0 deletions src/Bones.UI/core/composableFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ export class ComposableFactory {
return ComposableFactory.customRemove(service.remove);
}

public static subscribe<TDetails>(service: INotifyService<TDetails>) {
return () => {
let subscribersIds: number[] = [];

onUnmounted(() => {
subscribersIds.forEach(id => service.unsubscribe(id));
subscribersIds = [];
});

const subscribe: INotifyService<TDetails>["subscribe"] = (ev: any, callback: any) => {
const subscriberId = service.subscribe(ev, callback);
subscribersIds.push(subscriberId);
return subscriberId;
}

return {
subscribe
}
}
}

public static custom<TDetails, TArgs extends any[]>(method: (...args: TArgs) => Promise<TDetails>, applyFactory?: () => (entity: Ref<TDetails>) => void) {
return () => {
const apply = applyFactory ? applyFactory() : () => { };
Expand Down
6 changes: 4 additions & 2 deletions src/Bones.UI/core/eventQueue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import _ from "lodash";
import Ajv, { JSONSchemaType, ValidateFunction } from "ajv";

import { uuidv4 } from "../tools";

interface WindowsMessage {
id: string;
topic: string;
Expand Down Expand Up @@ -55,8 +57,7 @@ export class EventQueue {
this.publishInternal(topic, payload);

if (window.top && window.top !== window.self) {
this.messageCounter++;
const id = "remote_" + this.messageCounter;
const id = uuidv4();

const message: WindowsMessage = {
id,
Expand All @@ -65,6 +66,7 @@ export class EventQueue {
};

this.buffer[this.messageCounter % bufferSize] = message.id;
this.messageCounter++;

window.top.postMessage(JSON.stringify(message), "*");
}
Expand Down
17 changes: 14 additions & 3 deletions src/Bones.UI/core/serviceFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { INotifyService } from "../abstractions";

export class ServiceFactory<TDetailsDTO, TDetails> {
static http: AxiosInstance = axios;
static getAsPost = false;

private notifyService: NotifyService<TDetails>;
EntityDetails: new (dto: TDetailsDTO) => TDetails;
Expand Down Expand Up @@ -40,7 +41,17 @@ export class ServiceFactory<TDetailsDTO, TDetails> {
const getMany = async (filter?: TFilter) => {
const realUrl = typeof url === "string" ? url : url();

const response = await ServiceFactory.http.get(buildURL(realUrl, filter));
let response;

// If the service is configured to use GET as POST to prevent issues with large query strings,
// we send the filter as a POST request with a "_method" parameter to indicate it's a GET request.
if (ServiceFactory.getAsPost && filter) {
response = await ServiceFactory.http.post(buildURL(realUrl, { "_method": "GET" }), filter);
}
else {
response = await ServiceFactory.http.get(buildURL(realUrl, filter));
}

const dtos: TInfosDTO[] = response.data;

return dtos.map(dto => new entity(dto));
Expand Down Expand Up @@ -145,8 +156,8 @@ export class ServiceFactory<TDetailsDTO, TDetails> {
build<T, U, V, W, X>(target: T, source1: U, source2: V, source3: W, source4: X): T & U & V & W & X
build<T, U, V, W, X, Y>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y): T & U & V & W & X & Y
build<T, U, V, W, X, Y, Z>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z): T & U & V & W & X & Y & Z
build<T, U, V, W, X, Y, Z, Z1>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1 ): T & U & V & W & X & Y & Z & Z1
build<T, U, V, W, X, Y, Z, Z1, Z2>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1, source8: Z2 ): T & U & V & W & X & Y & Z & Z1 & Z2
build<T, U, V, W, X, Y, Z, Z1>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1): T & U & V & W & X & Y & Z & Z1
build<T, U, V, W, X, Y, Z, Z1, Z2>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1, source8: Z2): T & U & V & W & X & Y & Z & Z1 & Z2
build<T, U, V, W, X, Y, Z, Z1, Z2, Z3>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1, source8: Z2, source9: Z3): T & U & V & W & X & Y & Z & Z1 & Z2 & Z3
build<T, U, V, W, X, Y, Z, Z1, Z2, Z3, Z4>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1, source8: Z2, source9: Z3, source10: Z4): T & U & V & W & X & Y & Z & Z1 & Z2 & Z3 & Z4
build<T, U, V, W, X, Y, Z, Z1, Z2, Z3, Z4, Z5>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z, source7: Z1, source8: Z2, source9: Z3, source10: Z4, source11: Z5): T & U & V & W & X & Y & Z & Z1 & Z2 & Z3 & Z4 & Z5
Expand Down
2 changes: 1 addition & 1 deletion tests/Bones.UI.Tests/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
testEnvironment: 'jsdom',
};
7 changes: 7 additions & 0 deletions tests/Bones.UI.Tests/services/testUserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ const AccountLoginFactory = new ServiceFactory<TestUserDetailsDTO, TestUserDetai
export const useTestUsersSync = ComposableFactory.sync<TestUserDetails, TestUserInfos>(testUserServiceFactory);
export const useTestUserTrack = ComposableFactory.trackRef(testUserServiceFactory);

export const useTestUserSubscribe = ComposableFactory.subscribe(testUserServiceFactory);

const { subscribe } = useTestUserSubscribe();

subscribe("add", (ev, payload) => {
console.log(ev, payload);
});

export const useLogin = ComposableFactory.custom(AccountLoginFactory.login, () => {
const { sync } = useTestUsersSync();
Expand Down
21 changes: 21 additions & 0 deletions tests/Bones.UI.Tests/tests/plugins.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useTranslations } from '@dative-gpi/bones-ui';

describe('Translation plugin', () => {
const { $tr } = useTranslations();

it('should return the correct default value with formatted parameter', () => {
const result = $tr('code', 'default value : {0}m', "72");
expect(result).toBe('default value : 72m');
});

it('should return the correct default value with formatted parameters', () => {
const result = $tr('code', 'default value : {0}m, {1}°C', "72", 85);
expect(result).toBe('default value : 72m, 85°C');
});

it('should return the correct default value with equals formatted parameters', () => {
const result = $tr('code', 'default value : {0}m, {1}°C', "72", "72");
expect(result).toBe('default value : 72m, 72°C');
});
});

Loading