mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-06-30 12:33:31 +00:00
New test: Add location (#2222)
* New test: Add location - Add script to download some test files to allows tests to have a stable path for creating locations - Improve onboarding test - Add custom Cypress commands for fastOnboarding and deleteLibrary - Add some documentation related to tests to CONTRIBUTING.md - Update some deps * Download small test-data for Cypress CI * Replace globstar with find to make it compatible with bash 3.x * Fix react too many re-renders - add-location test should now pass successfully * Make job model task text match less flaky * Check if we were redirected to onboarding after Library was deleted - Check if sidebar entry was created after adding a location - Put route regex's into a separate file - Make onboarding test ensure that no Library exists before running * Enable test retries - Log cypress default config during test run * Run tests under webkit - Pass CI envvar to tests to ensure correct cypress config * Attempt fix CI config again * Remove single use checkUrlIsLibrary function
This commit is contained in:
parent
904f210fc1
commit
e5b57aa0ea
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -72,11 +72,15 @@ jobs:
|
|||
runTests: false
|
||||
working-directory: .
|
||||
|
||||
- name: Download test data
|
||||
run: pnpm test-data small
|
||||
|
||||
- name: E2E test
|
||||
uses: cypress-io/github-action@v6
|
||||
with:
|
||||
build: npx cypress info
|
||||
install: false
|
||||
command: pnpm test:e2e
|
||||
command: env CI=true pnpm test:e2e
|
||||
working-directory: apps/web
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -83,3 +83,5 @@ spacedrive
|
|||
.github/scripts/deps
|
||||
.vite-inspect
|
||||
vite.config.ts.*
|
||||
|
||||
/test-data
|
||||
|
|
|
@ -58,6 +58,13 @@ To quickly run only the desktop app after `prep`, you can use:
|
|||
Also, the react-devtools can be launched using `pnpm dlx react-devtools`.
|
||||
However, it must be executed before starting the desktop app for it to connect.
|
||||
|
||||
You can download a bundle with sample files to test the app by running:
|
||||
|
||||
- `pnpm test-data`
|
||||
|
||||
Only for Linux and macOS (Requires curl and tar).
|
||||
The test files will be located in a directory called `test-data` in the root of the spacedrive repo.
|
||||
|
||||
To run the web app:
|
||||
|
||||
- `pnpm dev:web`
|
||||
|
@ -68,15 +75,23 @@ You can launch these individually if you'd prefer:
|
|||
- `cargo run -p sd-server` (server)
|
||||
- `pnpm web dev` (web interface)
|
||||
|
||||
To run the e2e tests for the web app:
|
||||
|
||||
- `pnpm web test:e2e`
|
||||
|
||||
If you are developing a new test, you can execute Cypress in interactive mode with:
|
||||
|
||||
- `pnpm web test:interactive`
|
||||
|
||||
To run the landing page:
|
||||
|
||||
- `pnpm landing dev`
|
||||
|
||||
If you encounter any issues, ensure that you are using the following versions of Rust, Node and Pnpm:
|
||||
|
||||
- Rust version: **1.75.0**
|
||||
- Node version: **18.17**
|
||||
- Pnpm version: **8.0.0**
|
||||
- Rust version: **1.75**
|
||||
- Node version: **18.18**
|
||||
- Pnpm version: **8.15**
|
||||
|
||||
After cleaning out your build artifacts using `pnpm clean`, `git clean`, or `cargo clean`, it is necessary to re-run the `setup-system` script.
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"@octokit/openapi-types": "^20.0.0",
|
||||
"@sd/config": "workspace:*",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@types/node": ">18.x",
|
||||
"@types/node": ">18.18.x",
|
||||
"@types/react": "^18.2.67",
|
||||
"@types/react-burger-menu": "^2.8.7",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
|
|
|
@ -4,5 +4,5 @@ module.exports = {
|
|||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
},
|
||||
ignorePatterns: ['playwright.config.ts', 'tests/**/*', 'cypress/**/*']
|
||||
ignorePatterns: ['playwright.config.ts', 'tests/**/*', 'cypress/**/*', 'cypress.config.ts']
|
||||
};
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { inspect } from 'node:util';
|
||||
import { defineConfig } from 'cypress';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const ci_specific = {
|
||||
// Double all the default timeouts
|
||||
// https://docs.cypress.io/guides/references/configuration#Timeouts
|
||||
|
@ -8,16 +14,28 @@ const ci_specific = {
|
|||
taskTimeout: 60000 * 2,
|
||||
pageLoadTimeout: 60000 * 2,
|
||||
requestTimeout: 5000 * 2,
|
||||
responseTimeout: 30000 * 2
|
||||
responseTimeout: 30000 * 2,
|
||||
// Enable test retries
|
||||
// https://docs.cypress.io/guides/guides/test-retries#Configure-retry-attempts-for-all-modes
|
||||
retries: 2
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
const config = defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:8002',
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
setupNodeEvents(on) {
|
||||
on('task', {
|
||||
repoRoot: () => {
|
||||
return resolve(join(__dirname, '../../'));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
video: true,
|
||||
experimentalWebKitSupport: true,
|
||||
...(process.env.CI === 'true' ? ci_specific : {})
|
||||
});
|
||||
|
||||
console.log('Cypress default config:', inspect(config, { depth: null, colors: true }));
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { discord, libraryName } from '../fixtures/onboarding.json';
|
||||
import { discordUrl, libraryName, privacyUrl } from '../fixtures/onboarding.json';
|
||||
import { libraryRegex, onboardingRegex } from '../fixtures/routes';
|
||||
|
||||
describe('Onboarding', () => {
|
||||
// TODO: Create debug flag to bypass auto language detection
|
||||
|
@ -9,8 +10,13 @@ describe('Onboarding', () => {
|
|||
}
|
||||
});
|
||||
|
||||
// Delete previous library if it exists
|
||||
cy.url()
|
||||
.should('match', new RegExp(`${libraryRegex.source}|${onboardingRegex.source}`))
|
||||
.then((url) => (onboardingRegex.test(url) ? url : cy.deleteLibrary(libraryName)));
|
||||
|
||||
// Check redirect to initial alpha onboarding screen
|
||||
cy.url().should('contain', '/onboarding/alpha');
|
||||
cy.url().should('match', /\/onboarding\/alpha$/);
|
||||
|
||||
// Check application name is present
|
||||
cy.get('h1').should('contain', 'Spacedrive');
|
||||
|
@ -26,7 +32,7 @@ describe('Onboarding', () => {
|
|||
|
||||
// Check Join Discord button exists and point to a valid discord invite
|
||||
cy.get('button').contains('Join Discord').click();
|
||||
cy.get('@winOpen').should('be.calledWith', discord);
|
||||
cy.get('@winOpen').should('be.calledWith', discordUrl);
|
||||
|
||||
// Check we have a button to continue to the Library creation
|
||||
cy.get('a')
|
||||
|
@ -35,7 +41,7 @@ describe('Onboarding', () => {
|
|||
.click();
|
||||
|
||||
// Check we were redirect to Library creation screen
|
||||
cy.url().should('contain', '/onboarding/new-library');
|
||||
cy.url().should('match', /\/onboarding\/new-library$/);
|
||||
|
||||
// Check create library screen title
|
||||
cy.get('h2').should('contain', 'Create a Library');
|
||||
|
@ -61,10 +67,10 @@ describe('Onboarding', () => {
|
|||
cy.get('@libraryNameInput').type(libraryName);
|
||||
|
||||
// Check we have a button to continue to the add default locations screen
|
||||
cy.get('button').contains('New library').click();
|
||||
cy.get('@newLibraryButton').click();
|
||||
|
||||
// Check redirect to add default locations
|
||||
cy.url().should('contain', '/onboarding/locations');
|
||||
cy.url().should('match', /\/onboarding\/locations$/);
|
||||
|
||||
// Check we have a Toggle All button
|
||||
cy.get('#toggle-all').as('toggleAllButton');
|
||||
|
@ -107,7 +113,7 @@ describe('Onboarding', () => {
|
|||
cy.get('button').contains('Continue').click();
|
||||
|
||||
// Check redirect to privacy screen
|
||||
cy.url().should('contain', '/onboarding/privacy');
|
||||
cy.url().should('match', /\/onboarding\/privacy$/);
|
||||
|
||||
// Check privacy screen title
|
||||
cy.get('h2').should('contain', 'Your Privacy');
|
||||
|
@ -122,56 +128,22 @@ describe('Onboarding', () => {
|
|||
|
||||
// Check More info button exists and point to the valid pravacy policy
|
||||
cy.get('button').contains('More info').click();
|
||||
cy.get('@winOpen').should(
|
||||
'be.calledWith',
|
||||
'https://www.spacedrive.com/docs/product/resources/privacy'
|
||||
);
|
||||
cy.get('@winOpen').should('be.calledWith', privacyUrl);
|
||||
|
||||
// Check we have a button to finish onboarding
|
||||
cy.get('button[type="submit"]').contains('Continue').click();
|
||||
|
||||
// Check redirect to privacy screen
|
||||
cy.url().should('contain', '/onboarding/creating-library');
|
||||
cy.url().should('match', /\/onboarding\/creating-library$/);
|
||||
|
||||
// FIX-ME: This fails a lot, due to the creating library screen only being show for a short time
|
||||
// Check creating library screen title
|
||||
// cy.get('h2').should('contain', 'Creating your library');
|
||||
|
||||
// Check redirect to Library
|
||||
cy.url().should((url) => {
|
||||
expect(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\//.test(url)).to
|
||||
.be.true;
|
||||
});
|
||||
cy.checkUrlIsLibrary();
|
||||
|
||||
// Click on the library submenu
|
||||
cy.get('button[aria-haspopup="menu"]').contains(libraryName).click();
|
||||
cy.get('a').contains('Manage Library').click();
|
||||
|
||||
// Check redirect to Library settings
|
||||
cy.url().should('contain', '/settings/library/general');
|
||||
|
||||
// Check Library seetings screen title
|
||||
cy.get('h1').should('contain', 'Library Settings');
|
||||
|
||||
// Check Library name is correct
|
||||
cy.get('label')
|
||||
.contains('Name')
|
||||
.parent()
|
||||
.find('input')
|
||||
.should((input) => {
|
||||
expect(input.val()).to.eq(libraryName);
|
||||
});
|
||||
|
||||
// Delete Library
|
||||
cy.get('button').contains('Delete').click();
|
||||
|
||||
// Check confirmation modal for deleting appears
|
||||
cy.get('body > div[role="dialog"]').as('deleteModal');
|
||||
|
||||
// Check modal title
|
||||
cy.get('@deleteModal').find('h2').should('contain', 'Delete Library');
|
||||
|
||||
// Confirm delete
|
||||
cy.get('@deleteModal').find('button').contains('Delete').click();
|
||||
// Delete library
|
||||
cy.deleteLibrary(libraryName);
|
||||
});
|
||||
});
|
88
apps/web/cypress/e2e/2-location.spec.cy.ts
Normal file
88
apps/web/cypress/e2e/2-location.spec.cy.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import { locationName } from '../fixtures/location.json';
|
||||
import { libraryName } from '../fixtures/onboarding.json';
|
||||
import { locationRegex } from '../fixtures/routes';
|
||||
|
||||
describe('Location', () => {
|
||||
before(() => {
|
||||
cy.fastOnboarding(libraryName);
|
||||
});
|
||||
|
||||
it('Add Location', () => {
|
||||
// Click on the "Add Location" button
|
||||
cy.get('button').contains('Add Location').click();
|
||||
|
||||
// Get the input field for the new location inside modal
|
||||
cy.get('h2')
|
||||
.contains('New location')
|
||||
.parent()
|
||||
.find('input[name="path"]')
|
||||
.as('newLocationInput');
|
||||
|
||||
// Get the form for the new location inside modal
|
||||
cy.get('@newLocationInput')
|
||||
.should('have.value', '')
|
||||
.then(($input) =>
|
||||
cy.window().then((win) => {
|
||||
const input = $input[0];
|
||||
if (input == null || !(input instanceof win.HTMLInputElement)) {
|
||||
throw new Error('Input not found');
|
||||
}
|
||||
|
||||
return input.form;
|
||||
})
|
||||
)
|
||||
.as('newLocationForm');
|
||||
|
||||
cy.get('@newLocationForm').within(() => {
|
||||
// Check if the "Open new location once added" checkbox is checked by default
|
||||
cy.get('label')
|
||||
.contains('Open new location once added')
|
||||
.parent()
|
||||
.find('input[type="checkbox"]')
|
||||
.should('be.checked');
|
||||
|
||||
// Check if the "Add" button is disabled
|
||||
cy.get('button').contains('Add').as('addLocationButton');
|
||||
cy.get('@addLocationButton').should('be.disabled');
|
||||
|
||||
// Check if the "Add" button is enabled after typing a valid location
|
||||
cy.get('@newLocationInput').type('/');
|
||||
cy.get('@addLocationButton').should('be.enabled');
|
||||
|
||||
// Check if the "Add" button goes back to disabled after clearing the input
|
||||
cy.get('@newLocationInput').clear();
|
||||
cy.get('@addLocationButton').should('be.disabled');
|
||||
|
||||
// Check if the "Add" is disabled and an error message is shown after typing an invalid location
|
||||
cy.get('@newLocationInput').type('nonExisting/path/I/hope');
|
||||
cy.get('@addLocationButton').should('be.disabled');
|
||||
cy.get('div > p').contains("location not found <path='nonExisting/path/I/hope'>");
|
||||
|
||||
// Get location and add it as a new location
|
||||
cy.task<string>('repoRoot').then((repoRoot) => {
|
||||
cy.get('@newLocationInput').clear().type(`${repoRoot}/${locationName}`);
|
||||
cy.get('@addLocationButton').click();
|
||||
});
|
||||
});
|
||||
|
||||
// Check if location was added to sidebar
|
||||
cy.get('div.group').children('div:contains("Locations") + a').contains(locationName);
|
||||
|
||||
// Check if location is being scanned
|
||||
cy.get('button[id="job-manager-button"]').click();
|
||||
cy.get('span')
|
||||
.contains('Recent Jobs')
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() =>
|
||||
cy
|
||||
.get('p')
|
||||
.invoke('text')
|
||||
.should('match', new RegExp(`^(Adding|Added) location "${locationName}"$`))
|
||||
.should('exist')
|
||||
);
|
||||
|
||||
// Check redirect to location root page
|
||||
cy.url().should('match', locationRegex);
|
||||
});
|
||||
});
|
3
apps/web/cypress/fixtures/location.json
Normal file
3
apps/web/cypress/fixtures/location.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"locationName": "test-data"
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"discord": "https://discord.gg/ukRnWSnAbG",
|
||||
"discordUrl": "https://discord.gg/ukRnWSnAbG",
|
||||
"privacyUrl": "https://www.spacedrive.com/docs/product/resources/privacy",
|
||||
"libraryName": "Test Library"
|
||||
}
|
||||
|
|
8
apps/web/cypress/fixtures/routes.ts
Normal file
8
apps/web/cypress/fixtures/routes.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export const onboardingRegex = /\/onboarding\/alpha$/;
|
||||
export const libraryRegex = /\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\//;
|
||||
export const newLibraryRegex = /\/onboarding\/new-library$/;
|
||||
export const onboardingLocationRegex = /\/onboarding\/locations$/;
|
||||
export const onboardingPrivacyRegex = /\/onboarding\/privacy$/;
|
||||
export const librarySettingsRegex = /\/settings\/library\/general$/;
|
||||
export const onboardingLibraryRegex = /\/onboarding\/new-library$/;
|
||||
export const locationRegex = /\/location\/1$/;
|
|
@ -1,37 +1,97 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************
|
||||
// This example commands.ts shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
import {
|
||||
libraryRegex,
|
||||
librarySettingsRegex,
|
||||
onboardingLibraryRegex,
|
||||
onboardingLocationRegex,
|
||||
onboardingPrivacyRegex,
|
||||
onboardingRegex
|
||||
} from '../fixtures/routes';
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
deleteLibrary(libraryName: string): Chainable<void>;
|
||||
fastOnboarding(libraryName: string): Chainable<void>;
|
||||
checkUrlIsLibrary(): Chainable<string>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cypress.Commands.add('checkUrlIsLibrary', () =>
|
||||
cy.url().should((url) => expect(libraryRegex.test(url)).to.be.true)
|
||||
);
|
||||
|
||||
Cypress.Commands.add('fastOnboarding', (libraryName: string) => {
|
||||
// Initial alpha onboarding screen
|
||||
cy.visit('/');
|
||||
|
||||
// Delete previous library if it exists
|
||||
cy.url()
|
||||
.should('match', new RegExp(`${libraryRegex.source}|${onboardingRegex.source}`))
|
||||
.then((url) => (onboardingRegex.test(url) ? url : cy.deleteLibrary(libraryName)));
|
||||
|
||||
cy.get('a').contains('Continue').should('have.attr', 'href', '/onboarding/new-library').click();
|
||||
|
||||
// Library name screen
|
||||
cy.url().should('match', onboardingLibraryRegex);
|
||||
cy.get('input[placeholder="e.g. \\"James\' Library\\""]').type(libraryName);
|
||||
cy.get('button').contains('New library').click();
|
||||
|
||||
// Default locations screen
|
||||
cy.url().should('match', onboardingLocationRegex);
|
||||
cy.get('button').contains('Continue').click();
|
||||
|
||||
// Privacy screen
|
||||
cy.url().should('match', onboardingPrivacyRegex);
|
||||
cy.get('button[type="submit"]').contains('Continue').click();
|
||||
|
||||
// Check redirect to Library
|
||||
cy.checkUrlIsLibrary();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('deleteLibrary', (libraryName: string) => {
|
||||
// Click on the library submenu
|
||||
cy.get('button[aria-haspopup="menu"]').contains(libraryName).click();
|
||||
cy.get('a').contains('Manage Library').click();
|
||||
|
||||
// Check redirect to Library settings
|
||||
cy.url().should('match', librarySettingsRegex);
|
||||
|
||||
// Check Library seetings screen title
|
||||
cy.get('h1').should('contain', 'Library Settings');
|
||||
|
||||
// Check Library name is correct
|
||||
cy.get('label')
|
||||
.contains('Name')
|
||||
.parent()
|
||||
.find('input')
|
||||
.should((input) => {
|
||||
expect(input.val()).to.eq(libraryName);
|
||||
});
|
||||
|
||||
// Delete Library
|
||||
cy.get('button').contains('Delete').click();
|
||||
|
||||
// Check confirmation modal for deleting appears
|
||||
cy.get('body > div[role="dialog"]').as('deleteModal');
|
||||
|
||||
// Check modal title
|
||||
cy.get('@deleteModal').find('h2').should('contain', 'Delete Library');
|
||||
|
||||
cy.on('uncaught:exception', (err, runnable) => {
|
||||
// These errors are expected to occour right after the Library is deleted
|
||||
if (err.message.includes('Attempted to do library operation with no library set')) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Confirm delete
|
||||
cy.get('@deleteModal').find('button').contains('Delete').click();
|
||||
|
||||
// After deleting a library check we are redirected back to onboarding);
|
||||
cy.url().should('match', onboardingRegex);
|
||||
});
|
||||
|
||||
export {};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress", "node"],
|
||||
"resolveJsonModule": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev:api": "env E2E_TEST=1 cargo run -p sd-server",
|
||||
"dev:web": "env WAIT_ON_TIMEOUT=1800000 start-test dev:api http://localhost:8080 dev",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "VITE_SD_DEMO_MODE=true playwright test",
|
||||
"test:e2e": "env WAIT_ON_TIMEOUT=1800000 start-test dev:api http://localhost:8080 dev http://localhost:8002 cy:run",
|
||||
"test:interactive": "env WAIT_ON_TIMEOUT=1800000 start-test dev:api http://localhost:8080 dev http://localhost:8002 cy:open",
|
||||
"cy:run": "env ELECTRON_EXTRA_LAUNCH_ARGS=--lang=en cypress run",
|
||||
"cy:run": "cypress run --browser webkit",
|
||||
"cy:open": "env ELECTRON_EXTRA_LAUNCH_ARGS=--lang=en cypress open --e2e",
|
||||
"typecheck": "tsc -b",
|
||||
"lint": "eslint src --cache"
|
||||
|
@ -35,6 +36,7 @@
|
|||
"autoprefixer": "^10.4.18",
|
||||
"cypress": "^13.7.0",
|
||||
"eslint-plugin-cypress": "^2.15.1",
|
||||
"playwright-webkit": "^1.42.1",
|
||||
"postcss": "^8.4.36",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"start-server-and-test": "^2.0.3",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"declarationDir": "dist",
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"include": ["src", "src/demoData.json"],
|
||||
"include": ["src", "src/demoData.json", ".eslintrc.cjs"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../interface"
|
||||
|
|
|
@ -61,24 +61,25 @@ export const View = ({ emptyNotice, ...contextProps }: ExplorerViewProps) => {
|
|||
// Can stay here until we add columns view
|
||||
// Once added, the provided parent related logic should move to useExplorerDroppable
|
||||
// that way we don't have to re-use the same logic for each view
|
||||
const { parent } = explorer;
|
||||
const { setDroppableRef } = useExplorerDroppable({
|
||||
...(explorer.parent?.type === 'Location' && {
|
||||
...(parent?.type === 'Location' && {
|
||||
allow: ['Path', 'NonIndexedPath'],
|
||||
data: { type: 'location', path: path ?? '/', data: explorer.parent.location },
|
||||
data: { type: 'location', path: path ?? '/', data: parent.location },
|
||||
disabled:
|
||||
drag?.type === 'dragging' &&
|
||||
explorer.parent.location.id === drag.sourceLocationId &&
|
||||
parent.location.id === drag.sourceLocationId &&
|
||||
(path ?? '/') === drag.sourcePath
|
||||
}),
|
||||
...(explorer.parent?.type === 'Ephemeral' && {
|
||||
...(parent?.type === 'Ephemeral' && {
|
||||
allow: ['Path', 'NonIndexedPath'],
|
||||
data: { type: 'location', path: explorer.parent.path },
|
||||
disabled: drag?.type === 'dragging' && explorer.parent.path === drag.sourcePath
|
||||
data: { type: 'location', path: parent.path },
|
||||
disabled: drag?.type === 'dragging' && parent.path === drag.sourcePath
|
||||
}),
|
||||
...(explorer.parent?.type === 'Tag' && {
|
||||
...(parent?.type === 'Tag' && {
|
||||
allow: 'Path',
|
||||
data: { type: 'tag', data: explorer.parent.tag },
|
||||
disabled: drag?.type === 'dragging' && explorer.parent.tag.id === drag.sourceTagId
|
||||
data: { type: 'tag', data: parent.tag },
|
||||
disabled: drag?.type === 'dragging' && parent.tag.id === drag.sourceTagId
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ export default () => {
|
|||
popover={jobManagerPopover}
|
||||
trigger={
|
||||
<Button
|
||||
id="job-manager-button"
|
||||
size="icon"
|
||||
variant="subtle"
|
||||
className="text-sidebar-inkFaint ring-offset-sidebar radix-state-open:bg-sidebar-selected/50"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
import { Suspense, useEffect, useMemo, useRef } from 'react';
|
||||
import { Navigate, Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Navigate, Outlet, useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
ClientContextProvider,
|
||||
initPlausible,
|
||||
|
@ -31,6 +31,8 @@ import { DndContext } from './DndContext';
|
|||
import Sidebar from './Sidebar';
|
||||
|
||||
const Layout = () => {
|
||||
useRedirectToNewLocation();
|
||||
|
||||
const { libraries, library } = useClientContext();
|
||||
const os = useOperatingSystem();
|
||||
const showControls = useShowControls();
|
||||
|
@ -40,8 +42,6 @@ const Layout = () => {
|
|||
|
||||
const layoutRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useRedirectToNewLocation();
|
||||
|
||||
const ctxValue = useMemo(() => ({ ref: layoutRef }), [layoutRef]);
|
||||
|
||||
usePlausible();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useLibraryQuery, useSelector } from '@sd/client';
|
||||
import { explorerStore } from '~/app/$libraryId/Explorer/store';
|
||||
|
@ -29,8 +30,10 @@ export const useRedirectToNewLocation = () => {
|
|||
(j.completed_task_count > 0 || j.completed_at != null)
|
||||
);
|
||||
|
||||
if (hasIndexerJob) {
|
||||
navigate(`/${libraryId}/location/${newLocation}`);
|
||||
explorerStore.newLocationToRedirect = null;
|
||||
}
|
||||
useEffect(() => {
|
||||
if (hasIndexerJob) {
|
||||
navigate(`/${libraryId}/location/${newLocation}`);
|
||||
explorerStore.newLocationToRedirect = null;
|
||||
}
|
||||
}, [hasIndexerJob, libraryId, newLocation, navigate]);
|
||||
};
|
||||
|
|
|
@ -70,12 +70,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@sd/config": "workspace:*",
|
||||
"@types/node": ">18.x",
|
||||
"@types/node": ">18.18.x",
|
||||
"@types/react": "^18.2.67",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"type-fest": "^4.12.0",
|
||||
"type-fest": "^4.13.0",
|
||||
"typescript": "^5.4.2",
|
||||
"vite": "^5.1.6",
|
||||
"vite-plugin-svgr": "^3.3.0"
|
||||
|
|
12
package.json
12
package.json
|
@ -22,14 +22,15 @@
|
|||
"client": "pnpm --filter @sd/client -- ",
|
||||
"storybook": "pnpm --filter @sd/storybook -- ",
|
||||
"prisma": "cd core && cargo prisma",
|
||||
"dev:web": "turbo run dev --filter @sd/web --filter @sd/server",
|
||||
"dev:web": "pnpm --filter @sd/web dev:web",
|
||||
"dev:desktop": "pnpm run --filter @sd/desktop tauri dev",
|
||||
"bootstrap:desktop": "cargo clean && ./scripts/setup.sh && pnpm i && pnpm prep && pnpm tauri dev",
|
||||
"codegen": "cargo test -p sd-core api::tests::test_and_export_rspc_bindings -- --exact",
|
||||
"typecheck": "pnpm -r typecheck",
|
||||
"lint": "turbo run lint",
|
||||
"lint:fix": "turbo run lint -- --fix",
|
||||
"clean": "cargo clean; git clean -qfX ."
|
||||
"clean": "cargo clean; git clean -qfX .",
|
||||
"test-data": "./scripts/test-data.sh"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
|
@ -37,16 +38,15 @@
|
|||
"@contentlayer/cli@0.3.4": "patches/@contentlayer__cli@0.3.4.patch"
|
||||
},
|
||||
"overrides": {
|
||||
"@types/node": ">18.x",
|
||||
"@types/node": ">18.18.x",
|
||||
"react-router": "=6.20.1",
|
||||
"react-router-dom": "=6.20.1",
|
||||
"@remix-run/router": "=1.13.1",
|
||||
"@contentlayer/cli": "=0.3.4",
|
||||
"@typescript-eslint/parser": "^7.1.1"
|
||||
"@contentlayer/cli": "=0.3.4"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-syntax-import-assertions": "^7.23.3",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.24.1",
|
||||
"@cspell/dict-rust": "^4.0.2",
|
||||
"@cspell/dict-typescript": "^3.1.2",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
|
||||
|
|
|
@ -4,7 +4,7 @@ import { createContext, PropsWithChildren, useContext, useEffect, useMemo } from
|
|||
import { NormalisedCache, useCache, useNodes } from '../cache';
|
||||
import { LibraryConfigWrapped, Procedures } from '../core';
|
||||
import { valtioPersist } from '../lib';
|
||||
import { nonLibraryClient, useBridgeQuery } from '../rspc';
|
||||
import { useBridgeQuery } from '../rspc';
|
||||
|
||||
// The name of the localStorage key for caching library data
|
||||
const libraryCacheLocalStorageKey = 'sd-library-list2'; // `2` is because the format of this underwent a breaking change when introducing normalised caching
|
||||
|
@ -42,7 +42,7 @@ export const useCachedLibraries = () => {
|
|||
export async function getCachedLibraries(cache: NormalisedCache, client: AlphaClient<Procedures>) {
|
||||
const cachedData = localStorage.getItem(libraryCacheLocalStorageKey);
|
||||
|
||||
const libraries = client.query(['library.list']).then(result => {
|
||||
const libraries = client.query(['library.list']).then((result) => {
|
||||
cache.withNodes(result.nodes);
|
||||
const libraries = cache.withCache(result.items);
|
||||
|
||||
|
@ -62,7 +62,6 @@ export async function getCachedLibraries(cache: NormalisedCache, client: AlphaCl
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return await libraries;
|
||||
}
|
||||
|
||||
|
@ -105,6 +104,7 @@ export const ClientContextProvider = ({
|
|||
);
|
||||
};
|
||||
|
||||
// million-ignore
|
||||
export const useClientContext = () => {
|
||||
const ctx = useContext(ClientContext);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
"@storybook/types": "^8.0.1",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/node": ">18.x",
|
||||
"@types/node": ">18.18.x",
|
||||
"@types/react": "^18.2.67",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"autoprefixer": "^10.4.18",
|
||||
|
|
145
pnpm-lock.yaml
145
pnpm-lock.yaml
|
@ -5,12 +5,11 @@ settings:
|
|||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
'@types/node': '>18.x'
|
||||
'@types/node': '>18.18.x'
|
||||
react-router: '=6.20.1'
|
||||
react-router-dom: '=6.20.1'
|
||||
'@remix-run/router': '=1.13.1'
|
||||
'@contentlayer/cli': '=0.3.4'
|
||||
'@typescript-eslint/parser': ^7.1.1
|
||||
|
||||
patchedDependencies:
|
||||
'@contentlayer/cli@0.3.4':
|
||||
|
@ -25,8 +24,8 @@ importers:
|
|||
.:
|
||||
devDependencies:
|
||||
'@babel/plugin-syntax-import-assertions':
|
||||
specifier: ^7.23.3
|
||||
version: 7.23.3(@babel/core@7.24.0)
|
||||
specifier: ^7.24.1
|
||||
version: 7.24.1(@babel/core@7.24.0)
|
||||
'@cspell/dict-rust':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
|
@ -292,7 +291,7 @@ importers:
|
|||
specifier: ^8.1.0
|
||||
version: 8.1.0(typescript@5.4.2)
|
||||
'@types/node':
|
||||
specifier: '>18.x'
|
||||
specifier: '>18.18.x'
|
||||
version: 20.11.29
|
||||
'@types/react':
|
||||
specifier: ^18.2.67
|
||||
|
@ -641,6 +640,9 @@ importers:
|
|||
eslint-plugin-cypress:
|
||||
specifier: ^2.15.1
|
||||
version: 2.15.1(eslint@8.57.0)
|
||||
playwright-webkit:
|
||||
specifier: ^1.42.1
|
||||
version: 1.42.1
|
||||
postcss:
|
||||
specifier: ^8.4.36
|
||||
version: 8.4.36
|
||||
|
@ -841,7 +843,7 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../packages/config
|
||||
'@types/node':
|
||||
specifier: '>18.x'
|
||||
specifier: '>18.18.x'
|
||||
version: 20.11.29
|
||||
'@types/react':
|
||||
specifier: ^18.2.67
|
||||
|
@ -856,8 +858,8 @@ importers:
|
|||
specifier: ^3.4.1
|
||||
version: 3.4.1
|
||||
type-fest:
|
||||
specifier: ^4.12.0
|
||||
version: 4.12.0
|
||||
specifier: ^4.13.0
|
||||
version: 4.13.0
|
||||
typescript:
|
||||
specifier: ^5.4.2
|
||||
version: 5.4.2
|
||||
|
@ -935,7 +937,7 @@ importers:
|
|||
specifier: ^7.3.1
|
||||
version: 7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.2)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^7.1.1
|
||||
specifier: ^7.3.1
|
||||
version: 7.3.1(eslint@8.57.0)(typescript@5.4.2)
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: ^3.6.0
|
||||
|
@ -1086,7 +1088,7 @@ importers:
|
|||
specifier: ^0.5.10
|
||||
version: 0.5.10(tailwindcss@3.4.1)
|
||||
'@types/node':
|
||||
specifier: '>18.x'
|
||||
specifier: '>18.18.x'
|
||||
version: 20.11.29
|
||||
'@types/react':
|
||||
specifier: ^18.2.67
|
||||
|
@ -1138,22 +1140,22 @@ importers:
|
|||
specifier: ^7.24.0
|
||||
version: 7.24.0
|
||||
'@babel/eslint-parser':
|
||||
specifier: ^7.23.10
|
||||
version: 7.23.10(@babel/core@7.24.0)(eslint@8.57.0)
|
||||
specifier: ^7.24.1
|
||||
version: 7.24.1(@babel/core@7.24.0)(eslint@8.57.0)
|
||||
'@babel/eslint-plugin':
|
||||
specifier: ^7.23.5
|
||||
version: 7.23.5(@babel/eslint-parser@7.23.10)(eslint@8.57.0)
|
||||
version: 7.23.5(@babel/eslint-parser@7.24.1)(eslint@8.57.0)
|
||||
'@types/mustache':
|
||||
specifier: ^4.2.5
|
||||
version: 4.2.5
|
||||
'@types/node':
|
||||
specifier: '>18.x'
|
||||
specifier: '>18.18.x'
|
||||
version: 20.11.29
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^7.3.1
|
||||
version: 7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.2)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^7.1.1
|
||||
specifier: ^7.3.1
|
||||
version: 7.3.1(eslint@8.57.0)(typescript@5.4.2)
|
||||
eslint:
|
||||
specifier: ^8.57.0
|
||||
|
@ -1586,8 +1588,8 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
/@babel/eslint-parser@7.23.10(@babel/core@7.24.0)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==}
|
||||
/@babel/eslint-parser@7.24.1(@babel/core@7.24.0)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==}
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.11.0
|
||||
|
@ -1600,14 +1602,14 @@ packages:
|
|||
semver: 6.3.1
|
||||
dev: true
|
||||
|
||||
/@babel/eslint-plugin@7.23.5(@babel/eslint-parser@7.23.10)(eslint@8.57.0):
|
||||
/@babel/eslint-plugin@7.23.5(@babel/eslint-parser@7.24.1)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g==}
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0}
|
||||
peerDependencies:
|
||||
'@babel/eslint-parser': ^7.11.0
|
||||
eslint: ^7.5.0 || ^8.0.0
|
||||
dependencies:
|
||||
'@babel/eslint-parser': 7.23.10(@babel/core@7.24.0)(eslint@8.57.0)
|
||||
'@babel/eslint-parser': 7.24.1(@babel/core@7.24.0)(eslint@8.57.0)
|
||||
eslint: 8.57.0
|
||||
eslint-rule-composer: 0.3.0
|
||||
dev: true
|
||||
|
@ -2054,8 +2056,8 @@ packages:
|
|||
'@babel/core': 7.24.0
|
||||
'@babel/helper-plugin-utils': 7.24.0
|
||||
|
||||
/@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0):
|
||||
resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==}
|
||||
/@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.0):
|
||||
resolution: {integrity: sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
@ -2803,7 +2805,7 @@ packages:
|
|||
'@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0)
|
||||
'@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
|
||||
|
@ -3087,10 +3089,6 @@ packages:
|
|||
peerDependencies:
|
||||
'@effect-ts/otel-node': '*'
|
||||
peerDependenciesMeta:
|
||||
'@effect-ts/core':
|
||||
optional: true
|
||||
'@effect-ts/otel':
|
||||
optional: true
|
||||
'@effect-ts/otel-node':
|
||||
optional: true
|
||||
dependencies:
|
||||
|
@ -10335,7 +10333,7 @@ packages:
|
|||
resolution: {integrity: sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^7.1.1
|
||||
'@typescript-eslint/parser': ^7.0.0
|
||||
eslint: ^8.56.0
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
|
@ -10360,6 +10358,27 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.2):
|
||||
resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 6.21.0
|
||||
'@typescript-eslint/types': 6.21.0
|
||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2)
|
||||
'@typescript-eslint/visitor-keys': 6.21.0
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
eslint: 8.57.0
|
||||
typescript: 5.4.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.2):
|
||||
resolution: {integrity: sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
|
@ -13937,11 +13956,11 @@ packages:
|
|||
dependencies:
|
||||
'@next/eslint-plugin-next': 14.1.3
|
||||
'@rushstack/eslint-patch': 1.7.2
|
||||
'@typescript-eslint/parser': 7.3.1(eslint@8.57.0)(typescript@5.4.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)
|
||||
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
||||
eslint-plugin-react: 7.34.1(eslint@8.57.0)
|
||||
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
|
||||
|
@ -13970,7 +13989,7 @@ packages:
|
|||
eslint-plugin-promise: ^6.0.0
|
||||
dependencies:
|
||||
eslint: 8.57.0
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)
|
||||
eslint-plugin-n: 16.6.2(eslint@8.57.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.57.0)
|
||||
dev: true
|
||||
|
@ -13994,7 +14013,7 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0):
|
||||
/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
|
@ -14004,8 +14023,8 @@ packages:
|
|||
debug: 4.3.4(supports-color@8.1.1)
|
||||
enhanced-resolve: 5.16.0
|
||||
eslint: 8.57.0
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.3
|
||||
is-core-module: 2.13.1
|
||||
|
@ -14017,7 +14036,37 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils@2.8.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
/eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint: '*'
|
||||
eslint-import-resolver-node: '*'
|
||||
eslint-import-resolver-typescript: '*'
|
||||
eslint-import-resolver-webpack: '*'
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
eslint:
|
||||
optional: true
|
||||
eslint-import-resolver-node:
|
||||
optional: true
|
||||
eslint-import-resolver-typescript:
|
||||
optional: true
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2)
|
||||
debug: 3.2.7(supports-color@8.1.1)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils@2.8.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
|
@ -14042,7 +14091,6 @@ packages:
|
|||
debug: 3.2.7(supports-color@8.1.1)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -14068,7 +14116,7 @@ packages:
|
|||
eslint-compat-utils: 0.1.2(eslint@8.57.0)
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
|
@ -14087,7 +14135,7 @@ packages:
|
|||
doctrine: 2.1.0
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.3.1)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.13.1
|
||||
is-glob: 4.0.3
|
||||
|
@ -20037,6 +20085,15 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/playwright-webkit@1.42.1:
|
||||
resolution: {integrity: sha512-NKgCwBlmHQZmM5a6q36nUQ1/nIfJLyblioxfiHIrPU4JHUqVrwx5+uWg2xZp010+vTSx4IicscT4hCiPWQx5zA==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
playwright-core: 1.42.1
|
||||
dev: true
|
||||
|
||||
/playwright@1.42.1:
|
||||
resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==}
|
||||
engines: {node: '>=16'}
|
||||
|
@ -23545,8 +23602,8 @@ packages:
|
|||
resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
/type-fest@4.12.0:
|
||||
resolution: {integrity: sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==}
|
||||
/type-fest@4.13.0:
|
||||
resolution: {integrity: sha512-nKO1N9IFeTec3jnNe/3nZlX+RzwZsvT3c4akWC3IlhYGQbRSPFMBe87vmoaymS3hW2l/rs+4ptDDTxzcbqAcmA==}
|
||||
engines: {node: '>=16'}
|
||||
dev: true
|
||||
|
||||
|
@ -24339,7 +24396,7 @@ packages:
|
|||
debug: 4.3.4(supports-color@8.1.1)
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.4.2)
|
||||
vite: 5.1.6(sass@1.72.0)
|
||||
vite: 5.1.6(@types/node@20.11.29)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
@ -24350,7 +24407,7 @@ packages:
|
|||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': '>18.x'
|
||||
'@types/node': '>18.18.x'
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
|
@ -24385,7 +24442,7 @@ packages:
|
|||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': '>18.x'
|
||||
'@types/node': '>18.18.x'
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
|
@ -24420,7 +24477,7 @@ packages:
|
|||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': '>18.x'
|
||||
'@types/node': '>18.18.x'
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
|
|
|
@ -26,10 +26,10 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
"@babel/eslint-parser": "^7.23.10",
|
||||
"@babel/eslint-parser": "^7.24.1",
|
||||
"@babel/eslint-plugin": "^7.23.5",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": ">18.x",
|
||||
"@types/node": ">18.18.x",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"eslint": "^8.57.0",
|
||||
|
|
86
scripts/test-data.sh
Executable file
86
scripts/test-data.sh
Executable file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euEo pipefail
|
||||
|
||||
# This script is used to download test data for Spacedrive e2e tests.
|
||||
|
||||
_root="$(CDPATH='' cd "$(dirname "$0")/.." && pwd -P)"
|
||||
_test_data_dir="${_root}/test-data"
|
||||
|
||||
# Check if curl and tar are available
|
||||
if ! command -v curl &>/dev/null; then
|
||||
echo "curl is required to download test data" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v tar &>/dev/null; then
|
||||
echo "tar is required to extract test data" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$_test_data_dir"
|
||||
mkdir "$_test_data_dir"
|
||||
|
||||
if [ "${1:-}" == "small" ]; then
|
||||
echo "Downloading WPT test resources..."
|
||||
curl -L# 'https://github.com/web-platform-tests/wpt/archive/refs/heads/master.tar.gz' \
|
||||
| tar -xzf - -C "$_test_data_dir" \
|
||||
wpt-master/images
|
||||
else
|
||||
echo "Downloading WPT test resources..."
|
||||
curl -L# 'https://github.com/web-platform-tests/wpt/archive/refs/heads/master.tar.gz' \
|
||||
| tar -xzf - -C "$_test_data_dir" \
|
||||
wpt-master/images \
|
||||
wpt-master/jpegxl/resources
|
||||
|
||||
echo "Downloading HEIF test resources..."
|
||||
curl -L# 'https://github.com/nokiatech/heif_conformance/archive/refs/heads/master.tar.gz' \
|
||||
| tar -xzf - -C "$_test_data_dir" \
|
||||
heif_conformance-master/conformance_files
|
||||
|
||||
echo "Downloading WEBP test resources..."
|
||||
curl -L# 'https://github.com/webmproject/libwebp-test-data/archive/refs/heads/main.tar.gz' \
|
||||
| tar -xzf - -C "$_test_data_dir"
|
||||
|
||||
echo "Downloading PNG test resources..."
|
||||
mkdir -p "${_test_data_dir}/png-test-suite"
|
||||
curl -L# 'http://www.schaik.com/pngsuite/PngSuite-2017jul19.tgz' \
|
||||
| tar -xzf - -C "${_test_data_dir}/png-test-suite"
|
||||
|
||||
echo "Downloading image-rs test resources..."
|
||||
curl -L# 'https://github.com/image-rs/image/archive/refs/heads/main.tar.gz' \
|
||||
| tar -xzf - -C "$_test_data_dir" \
|
||||
image-main/tests/images/bmp \
|
||||
image-main/tests/images/gif \
|
||||
image-main/tests/images/ico \
|
||||
image-main/tests/images/tiff
|
||||
|
||||
echo "Downloading chromium media test resources..."
|
||||
mkdir -p "${_test_data_dir}/chromium-media"
|
||||
curl -L# 'https://chromium.googlesource.com/chromium/src/+archive/refs/heads/main/media/test/data.tar.gz' \
|
||||
| tar -xzf - -C "${_test_data_dir}/chromium-media"
|
||||
|
||||
echo "Downloading chromium pdf test resources..."
|
||||
mkdir -p "${_test_data_dir}/chromium-pdf"
|
||||
curl -L# 'https://chromium.googlesource.com/chromium/src/+archive/refs/heads/main/pdf/test/data.tar.gz' \
|
||||
| tar -xzf - -C "${_test_data_dir}/chromium-pdf"
|
||||
fi
|
||||
|
||||
while IFS= read -r -d '' _test_file; do
|
||||
_mime_type="$(file -b --mime-type "$_test_file")"
|
||||
case "$_mime_type" in
|
||||
image/* | audio/* | video/*)
|
||||
_type_dir="${_test_data_dir}/${_mime_type%%/*}"
|
||||
;;
|
||||
application/pdf)
|
||||
_type_dir="${_test_data_dir}/pdf"
|
||||
;;
|
||||
*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p "$_type_dir"
|
||||
mv "$_test_file" "$_type_dir"
|
||||
done < <(find "$_test_data_dir" -type f -print0)
|
||||
|
||||
rm -rf "${_test_data_dir}"/{wpt-master,heif_conformance-master,libwebp-test-data-main,png-test-suite,image-main,chromium-media,chromium-pdf}
|
Loading…
Reference in a new issue