Merge branch 'master' into stable24
commit
04bad3d020
|
@ -28,7 +28,7 @@ jobs:
|
|||
make build-js-production
|
||||
zip -r vue.zip js/
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: vue.zip
|
||||
path: vue.zip
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { login } from './login';
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { login } from "./login";
|
||||
|
||||
test.beforeEach(login('/folders'));
|
||||
test.beforeEach(login("/folders"));
|
||||
|
||||
test.describe('Open', () => {
|
||||
test('Look for Folders', async ({ page }) => {
|
||||
expect(await page.locator('.big-icon').count(), 'Number of folders').toBe(2);
|
||||
test.describe("Open", () => {
|
||||
test("Look for Folders", async ({ page }) => {
|
||||
expect(await page.locator(".big-icon").count(), "Number of folders").toBe(
|
||||
2
|
||||
);
|
||||
});
|
||||
|
||||
test('Open folder', async ({ page }) => {
|
||||
await page.locator('text=Local').click();
|
||||
test("Open folder", async ({ page }) => {
|
||||
await page.locator("text=Local").click();
|
||||
await page.waitForSelector('img[src*="core/preview"]');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
22
e2e/login.ts
22
e2e/login.ts
|
@ -1,16 +1,18 @@
|
|||
import { expect, PlaywrightTestArgs } from '@playwright/test';
|
||||
import { expect, PlaywrightTestArgs } from "@playwright/test";
|
||||
|
||||
export function login(route: string) {
|
||||
return async ({ page }: PlaywrightTestArgs) => {
|
||||
await page.setViewportSize({ width: 800, height: 600 })
|
||||
await page.goto('http://localhost:8080/index.php/apps/memories' + route)
|
||||
await page.setViewportSize({ width: 800, height: 600 });
|
||||
await page.goto("http://localhost:8080/index.php/apps/memories" + route);
|
||||
|
||||
await page.locator('#user').click();
|
||||
await page.locator('#user').fill('admin');
|
||||
await page.locator('#user').press('Tab');
|
||||
await page.locator('#password').fill('password');
|
||||
await page.locator("#user").click();
|
||||
await page.locator("#user").fill("admin");
|
||||
await page.locator("#user").press("Tab");
|
||||
await page.locator("#password").fill("password");
|
||||
await page.locator('button[type="submit"]').click();
|
||||
await expect(page).toHaveURL('http://localhost:8080/index.php/apps/memories' + route);
|
||||
await expect(page).toHaveURL(
|
||||
"http://localhost:8080/index.php/apps/memories" + route
|
||||
);
|
||||
await page.waitForSelector('img[src*="core/preview"]');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,26 +1,38 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { login } from './login';
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { login } from "./login";
|
||||
|
||||
test.beforeEach(login('/'));
|
||||
test.beforeEach(login("/"));
|
||||
|
||||
test.describe('Open', () => {
|
||||
test('Look for Images', async ({ page }) => {
|
||||
expect(await page.locator('img[src*="core/preview"]').count(), 'Number of previews').toBeGreaterThan(4);
|
||||
test.describe("Open", () => {
|
||||
test("Look for Images", async ({ page }) => {
|
||||
expect(
|
||||
await page.locator('img[src*="core/preview"]').count(),
|
||||
"Number of previews"
|
||||
).toBeGreaterThan(4);
|
||||
await page.waitForTimeout(1000);
|
||||
});
|
||||
|
||||
test('Open one image', async ({ page }) => {
|
||||
await page.locator('div:nth-child(2) > .p-outer > .img-outer > img').first().click();
|
||||
test("Open one image", async ({ page }) => {
|
||||
await page
|
||||
.locator("div:nth-child(2) > .p-outer > .img-outer > img")
|
||||
.first()
|
||||
.click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.locator('button.header-close').first().click();
|
||||
await page.locator('button[title="Close"]').first().click();
|
||||
});
|
||||
|
||||
test('Select two images and delete', async ({ page }) => {
|
||||
test("Select two images and delete", async ({ page }) => {
|
||||
const i1 = "div:nth-child(2) > div:nth-child(1) > .p-outer";
|
||||
const i2 = "div:nth-child(2) > div:nth-child(2) > .p-outer";
|
||||
|
||||
const src1 = await page.locator(`${i1} > .img-outer > img`).first().getAttribute('src');
|
||||
const src2 = await page.locator(`${i2} > .img-outer > img`).first().getAttribute('src');
|
||||
const src1 = await page
|
||||
.locator(`${i1} > .img-outer > img`)
|
||||
.first()
|
||||
.getAttribute("src");
|
||||
const src2 = await page
|
||||
.locator(`${i2} > .img-outer > img`)
|
||||
.first()
|
||||
.getAttribute("src");
|
||||
|
||||
expect(await page.locator(`img[src="${src1}"]`).count()).toBe(1);
|
||||
expect(await page.locator(`img[src="${src2}"]`).count()).toBe(1);
|
||||
|
@ -42,4 +54,4 @@ test.describe('Open', () => {
|
|||
expect(await page.locator(`img[src="${src1}"]`).count()).toBe(0);
|
||||
expect(await page.locator(`img[src="${src2}"]`).count()).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -348,7 +348,7 @@ export default class SelectionManager extends Mixins(GlobalMixin, UserConfig) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
await dav.downloadFilesByIds(Array.from(selection.values()));
|
||||
await dav.downloadFilesByPhotos(Array.from(selection.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -76,7 +76,7 @@ import { generateUrl } from "@nextcloud/router";
|
|||
import * as dav from "../services/DavRequests";
|
||||
import * as utils from "../services/Utils";
|
||||
import { getPreviewUrl } from "../services/FileUtils";
|
||||
import { getAlbumFileInfos } from "../services/DavRequests";
|
||||
import { getDownloadLink } from "../services/DavRequests";
|
||||
|
||||
import PhotoSwipe, { PhotoSwipeOptions } from "photoswipe";
|
||||
import "photoswipe/style.css";
|
||||
|
@ -213,7 +213,7 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
const klass = "has-viewer";
|
||||
this.photoswipe.on("beforeOpen", () => {
|
||||
document.body.classList.add(klass);
|
||||
navElem.style.zIndex = "0";
|
||||
if (navElem) navElem.style.zIndex = "0";
|
||||
});
|
||||
this.photoswipe.on("openingAnimationStart", () => {
|
||||
this.fullyOpened = false;
|
||||
|
@ -230,12 +230,9 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
this.opened = false;
|
||||
this.hideSidebar();
|
||||
});
|
||||
this.photoswipe.on("tapAction", () => {
|
||||
this.opened = !this.opened; // toggle-controls
|
||||
});
|
||||
this.photoswipe.on("destroy", () => {
|
||||
document.body.classList.remove(klass);
|
||||
navElem.style.zIndex = "";
|
||||
if (navElem) navElem.style.zIndex = "";
|
||||
|
||||
// reset everything
|
||||
this.show = false;
|
||||
|
@ -249,6 +246,11 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
this.globalAnchor = -1;
|
||||
});
|
||||
|
||||
// toggle-controls
|
||||
this.photoswipe.on("tapAction", () => {
|
||||
this.opened = !this.opened;
|
||||
});
|
||||
|
||||
// Video support
|
||||
this.photoswipe.on("contentLoad", (e) => {
|
||||
const { content, isLazy } = e;
|
||||
|
@ -262,19 +264,7 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
content.videoElement.classList.add("video-js");
|
||||
|
||||
// Get DAV URL for video
|
||||
let url = `remote.php/dav/${content.data.photo.filename}`; // normal route
|
||||
// Check if albums
|
||||
const route = vuerouter.currentRoute;
|
||||
if (route.name === "albums") {
|
||||
const fInfos = getAlbumFileInfos(
|
||||
[content.data.photo],
|
||||
route.params.user,
|
||||
route.params.name
|
||||
);
|
||||
if (fInfos.length) {
|
||||
url = `remote.php/dav/${fInfos[0].originalFilename}`;
|
||||
}
|
||||
}
|
||||
const url = getDownloadLink(content.data.photo);
|
||||
|
||||
// Add child with source element
|
||||
const source = document.createElement("source");
|
||||
|
@ -330,6 +320,8 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
|
||||
for (const r of rows) {
|
||||
if (r.type === IRowType.HEAD) {
|
||||
if (this.TagDayIDValueSet.has(r.dayId)) continue;
|
||||
|
||||
if (r.day.dayid == anchorPhoto.d.dayid) {
|
||||
startIndex = r.day.detail.findIndex(
|
||||
(p) => p.fileid === anchorPhoto.fileid
|
||||
|
@ -523,7 +515,7 @@ export default class Viewer extends Mixins(GlobalMixin) {
|
|||
private async downloadCurrent() {
|
||||
const photo = this.getCurrentPhoto();
|
||||
if (!photo) return;
|
||||
dav.downloadFilesByIds([photo]);
|
||||
dav.downloadFilesByPhotos([photo]);
|
||||
}
|
||||
|
||||
/** Open the sidebar */
|
||||
|
|
|
@ -69,9 +69,7 @@
|
|||
{{ t("photos", "Add collaborators") }}
|
||||
</NcButton>
|
||||
<NcButton
|
||||
:aria-label="
|
||||
editMode ? t('photos', 'Save.') : t('photos', 'Create the album.')
|
||||
"
|
||||
:aria-label="saveText"
|
||||
type="primary"
|
||||
:disabled="albumName === '' || loading"
|
||||
@click="submit()"
|
||||
|
@ -80,7 +78,7 @@
|
|||
<NcLoadingIcon v-if="loading" />
|
||||
<Send v-else />
|
||||
</template>
|
||||
{{ editMode ? t("photos", "Save") : t("photos", "Create album") }}
|
||||
{{ saveText }}
|
||||
</NcButton>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -103,9 +101,7 @@
|
|||
</span>
|
||||
<span class="right-buttons">
|
||||
<NcButton
|
||||
:aria-label="
|
||||
editMode ? t('photos', 'Save.') : t('photos', 'Create the album.')
|
||||
"
|
||||
:aria-label="saveText"
|
||||
type="primary"
|
||||
:disabled="albumName.trim() === '' || loading"
|
||||
@click="submit(collaborators)"
|
||||
|
@ -114,7 +110,7 @@
|
|||
<NcLoadingIcon v-if="loading" />
|
||||
<Send v-else />
|
||||
</template>
|
||||
{{ editMode ? t("photos", "Save") : t("photos", "Create album") }}
|
||||
{{ saveText }}
|
||||
</NcButton>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -162,6 +158,12 @@ export default class AlbumForm extends Mixins(GlobalMixin) {
|
|||
return Boolean(this.album);
|
||||
}
|
||||
|
||||
get saveText(): string {
|
||||
return this.editMode
|
||||
? this.t("photos", "Save")
|
||||
: this.t("photos", "Create album");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether sharing is enabled.
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@ import { generateUrl } from "@nextcloud/router";
|
|||
import { showError } from "@nextcloud/dialogs";
|
||||
import { translate as t } from "@nextcloud/l10n";
|
||||
import { IPhoto } from "../../types";
|
||||
import { getAlbumFileInfos } from "./albums";
|
||||
|
||||
/**
|
||||
* Download a file
|
||||
|
@ -16,7 +17,7 @@ export async function downloadFiles(fileNames: string[]): Promise<boolean> {
|
|||
params.append("files", JSON.stringify(fileNames));
|
||||
params.append("downloadStartSecret", randomToken);
|
||||
|
||||
const downloadURL = generateUrl(`/apps/files/ajax/download.php?${params}`);
|
||||
let downloadURL = generateUrl(`/apps/files/ajax/download.php?${params}`);
|
||||
|
||||
window.location.href = `${downloadURL}downloadStartSecret=${randomToken}`;
|
||||
|
||||
|
@ -38,15 +39,31 @@ export async function downloadFiles(fileNames: string[]): Promise<boolean> {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Download public photo
|
||||
* @param photo - The photo to download
|
||||
*/
|
||||
export async function downloadPublicPhoto(photo: IPhoto) {
|
||||
window.location.href = getDownloadLink(photo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the files given by the fileIds
|
||||
* @param photos list of photos
|
||||
*/
|
||||
export async function downloadFilesByIds(photos: IPhoto[]) {
|
||||
export async function downloadFilesByPhotos(photos: IPhoto[]) {
|
||||
if (photos.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Public files
|
||||
if (vuerouter.currentRoute.name === "folder-share") {
|
||||
for (const photo of photos) {
|
||||
await downloadPublicPhoto(photo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get files to download
|
||||
const fileInfos = await base.getFiles(photos);
|
||||
if (fileInfos.length !== photos.length) {
|
||||
|
@ -58,3 +75,32 @@ export async function downloadFilesByIds(photos: IPhoto[]) {
|
|||
|
||||
await downloadFiles(fileInfos.map((f) => f.filename));
|
||||
}
|
||||
|
||||
/** Get URL to download one file (e.g. for video streaming) */
|
||||
export function getDownloadLink(photo: IPhoto) {
|
||||
// Check if public
|
||||
if (vuerouter.currentRoute.name === "folder-share") {
|
||||
const token = window.vuerouter.currentRoute.params.token;
|
||||
// TODO: allow proper dav access without the need of basic auth
|
||||
// https://github.com/nextcloud/server/issues/19700
|
||||
return generateUrl(`/s/${token}/download?path={dirname}&files={basename}`, {
|
||||
dirname: photo.filename.split("/").slice(0, -1).join("/"),
|
||||
basename: photo.basename,
|
||||
});
|
||||
}
|
||||
|
||||
// Check if albums
|
||||
const route = vuerouter.currentRoute;
|
||||
if (route.name === "albums") {
|
||||
const fInfos = getAlbumFileInfos(
|
||||
[photo],
|
||||
route.params.user,
|
||||
route.params.name
|
||||
);
|
||||
if (fInfos.length) {
|
||||
return `remote.php/dav/${fInfos[0].originalFilename}`;
|
||||
}
|
||||
}
|
||||
|
||||
return `remote.php/dav/${photo.filename}`; // normal route
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue