Skip to content
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

CRISTAL-274: Allow attachments to be previewed #426

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
6 changes: 5 additions & 1 deletion api/src/api/cristalApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,18 @@ export interface CristalApp {
*/
getCurrentSyntax(): string;

setCurrentPage(page: string, mode: string): void;
setCurrentPage(page: string, mode?: string): void;

/**
* @deprecated use the document-api instead
* @param ref - the reactive reference holding the reference to a page data.
*/
setContentRef(ref: Ref): void;

/**
*
* @deprecated since XXX, use YYY instead
*/
loadPageFromURL(url: string): Promise<void>;

loadPage(options?: { requeue: boolean }): Promise<void>;
Expand Down
1 change: 1 addition & 0 deletions core/attachments/attachments-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"lint": "eslint \"./src/**/*.{ts,tsx}\" --max-warnings=0"
},
"dependencies": {
"@xwiki/cristal-model-api": "workspace:*",
"vue": "3.5.12"
},
"publishConfig": {
Expand Down
14 changes: 14 additions & 0 deletions core/attachments/attachments-api/src/attachment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @since 0.9
*/
interface Attachment {
id: string;
name: string;
mimetype: string;
href: string;
date: Date;
size: number;
author: string; // TODO: replace with a user reference
}

export { type Attachment };
13 changes: 13 additions & 0 deletions core/attachments/attachments-api/src/attachmentsPreview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AttachmentReference } from "@xwiki/cristal-model-api";
import { Ref } from "vue";

/**
* @since 0.12
*/
interface AttachmentPreview {
preview(attachment: AttachmentReference): void;
attachment(): Ref<AttachmentReference | undefined>;
loading(): Ref<boolean>;
}

export { type AttachmentPreview };
34 changes: 34 additions & 0 deletions core/attachments/attachments-api/src/attachmentsService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Attachment } from "./attachment";
import { Ref } from "vue";

/**
* @since 0.9
*/
interface AttachmentsService {
list(): Ref<Attachment[]>;

count(): Ref<number>;

isLoading(): Ref<boolean>;

/**
* True while an attachment is uploading.
*/
isUploading(): Ref<boolean>;

getError(): Ref<string | undefined>;

/**
* Load the initial state of the attachments.
*/
refresh(page: string): Promise<void>;

/**
* Upload the provided list of files to a given page
* @param page - the page where to save the files
* @param files - the list of files to upload
*/
upload(page: string, files: File[]): Promise<void>;
}

export { type AttachmentsService };
44 changes: 4 additions & 40 deletions core/attachments/attachments-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,8 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
import { Attachment } from "./attachment";
import { AttachmentPreview } from "./attachmentsPreview";
import { AttachmentsService } from "./attachmentsService";

import { Ref } from "vue";

/**
* @since 0.9
*/
interface Attachment {
id: string;
name: string;
mimetype: string;
href: string;
}

/**
* @since 0.9
*/
interface AttachmentsService {
list(): Ref<Attachment[]>;
count(): Ref<number>;
isLoading(): Ref<boolean>;

/**
* True while an attachment is uploading.
*/
isUploading(): Ref<boolean>;
getError(): Ref<string | undefined>;

/**
* Load the initial state of the attachments.
*/
refresh(page: string): Promise<void>;

/**
* Upload the provided list of files to a given page
* @param page - the page where to save the files
* @param files - the list of files to upload
*/
upload(page: string, files: File[]): Promise<void>;
}

export type { Attachment, AttachmentsService };
export type { Attachment, AttachmentPreview, AttachmentsService };
1 change: 1 addition & 0 deletions core/attachments/attachments-default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"dependencies": {
"@xwiki/cristal-api": "workspace:*",
"@xwiki/cristal-attachments-api": "workspace:*",
"@xwiki/cristal-model-api": "workspace:*",
"inversify": "6.0.3",
"pinia": "2.2.6",
"vue": "3.5.12"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { AttachmentPreview } from "@xwiki/cristal-attachments-api";
import { AttachmentReference } from "@xwiki/cristal-model-api";
import { injectable } from "inversify";
import { Store, StoreDefinition, defineStore, storeToRefs } from "pinia";
import { Ref } from "vue";

type Id = "attachment-preview";
type State = {
loading: boolean;
attachment: AttachmentReference | undefined;
};
/**
* Take a given type "Type" and wraps each of its fields in a readonly Ref.
*/
type WrappedRefs<Type> = {
readonly [Property in keyof Type]: Ref<Type[Property]>;
};
type StateRefs = WrappedRefs<State>;
type Getters = Record<string, never>;
type Actions = {
openAttachment(attachment: AttachmentReference): void;
startLoading(): void;
};
type AttachmentPreviewStoreDefinition = StoreDefinition<
Id,
State,
Getters,
Actions
>;
type AttachmentPreviewStore = Store<Id, State, Getters, Actions>;

const attachmentPreviewStore: AttachmentPreviewStoreDefinition = defineStore<
Id,
State,
Getters,
Actions
>("attachment-preview", {
state() {
return {
loading: false,
attachment: undefined,
};
},
actions: {
startLoading() {
this.loading = true;
},
openAttachment(attachment: AttachmentReference) {
this.startLoading();
try {
this.attachment = attachment;
// TODO: add complementary details from the backend.
} finally {
this.loading = false;
}
},
},
});

@injectable()
class DefaultAttachmentPreview implements AttachmentPreview {
private readonly refs: StateRefs;
private readonly store: AttachmentPreviewStore;
constructor() {
this.store = attachmentPreviewStore();
this.refs = storeToRefs(this.store);
}

preview(attachment: AttachmentReference): void {
this.store.openAttachment(attachment);
}

attachment(): StateRefs["attachment"] {
return this.refs.attachment;
}

loading(): StateRefs["loading"] {
return this.refs.loading;
}
}

export { DefaultAttachmentPreview };
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,18 @@ export class DefaultAttachmentsService implements AttachmentsService {
const { attachments, count } = attachmentData;
this.store.updateAttachments(
attachments?.map(({ id, reference, mimetype, href }) => {
return { id, name: reference, mimetype, href };
return {
id,
name: reference,
mimetype,
href,
// TODO
date: new Date(),
// TODO
size: 42,
// TODO
author: "XWiki.TODO",
};
}),
count,
);
Expand Down
10 changes: 9 additions & 1 deletion core/attachments/attachments-default/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,23 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

import { DefaultAttachmentPreview } from "./defaultAttachmentPreview";
import { DefaultAttachmentsService } from "./defaultAttachmentsService";
import { Container } from "inversify";
import type { AttachmentsService } from "@xwiki/cristal-attachments-api";
import type {
AttachmentPreview,
AttachmentsService,
} from "@xwiki/cristal-attachments-api";

export class ComponentInit {
constructor(container: Container) {
container
.bind<AttachmentsService>("AttachmentsService")
.to(DefaultAttachmentsService)
.inSingletonScope();
container
.bind<AttachmentPreview>("AttachmentPreview")
.to(DefaultAttachmentPreview)
.inSingletonScope();
}
}
3 changes: 3 additions & 0 deletions core/attachments/attachments-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
"@xwiki/cristal-dsapi": "workspace:*",
"@xwiki/cristal-extra-tabs-api": "workspace:*",
"@xwiki/cristal-info-actions-api": "workspace:*",
"@xwiki/cristal-uiextension-api": "workspace:*",
"dayjs": "1.11.13",
"filesize.js": "2.0.0",
"inversify": "6.0.3",
"vue": "3.5.12",
"vue-i18n": "10.0.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* See the LICENSE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
import { UIExtension } from "@xwiki/cristal-uiextension-api";
import { injectable } from "inversify";
import { Component } from "vue";

/**
* @since 0.12
*/
@injectable()
class AttachmentPreviewContentAfterUIExtension implements UIExtension {
id = "attachment.preview.content.after";
order = 1000;
parameters = {};
uixpName = "content.after";

async component(): Promise<Component> {
return (await import("./vue/AttachmentPreview.vue")).default;
}

async enabled(): Promise<boolean> {
// TODO: find a way to identify if the backend supports attachments.
return true;
}
}

export { AttachmentPreviewContentAfterUIExtension };
6 changes: 6 additions & 0 deletions core/attachments/attachments-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
*/

import { AttachmentExtraTab } from "./AttachmentExtraTab";
import { AttachmentPreviewContentAfterUIExtension } from "./AttachmentPreviewContentAfterUIExtension";
import { AttachmentsInfoAction } from "./AttachmentsInfoAction";
import { ExtraTab } from "@xwiki/cristal-extra-tabs-api";
import { InfoAction } from "@xwiki/cristal-info-actions-api";
import { UIExtension } from "@xwiki/cristal-uiextension-api";
import { Container } from "inversify";

export class ComponentInit {
Expand All @@ -34,5 +36,9 @@ export class ComponentInit {
.bind<InfoAction>("InfoAction")
.to(AttachmentsInfoAction)
.inSingletonScope();
container
.bind<UIExtension>("UIExtension")
.to(AttachmentPreviewContentAfterUIExtension)
.inSingletonScope();
}
}
Loading