Skip to content

Commit

Permalink
feat: add short links feature (graasp/graasp#664) (#861)
Browse files Browse the repository at this point in the history
* feat: add short links view (#664)
- The view is not responsive yet
- Contain problems yet with the SDK and the query-client

feat: improve UI, add translations and messages (graasp/graasp#664)
- Update the UI to be more responsive
- Update the UI to not allow to edit or create multiple short links at same time
- Add membership admin check to hide short links view if forbbiden
- Add notifier for short links actions and show error messages to the user

feat: add Context colours in ShortLink view and use last SDK types

test: add short links cypress tests (graasp/graasp#664)

chore: add ENV variable for redirection host

fix(test): remove shortLinkRenderId should exist to pass in CI

chore: improve code form PR (#861)
- Remove unnecessary nested cypress waits
- Check the item path too in the isItemAdminAllowedForMember
- Add Skeleton when loading short links
- Allow to use Library platform for published items only
- Update checkShortLink by shortLinkAvailable
- Split ManageShortLink into smaller components
- Remove not null assertions

test: try to debug cypress in CI

fix: add redirection host environment variable in cypress CI

feat: update short links to future merge with full links

feat: add shortlinks skeletons and move ManageShortLink dialog to parent

feat: allow readers to display short links in read only mode

feat: remove ShareItem component

chore: update query-client, sdk and translations NPM version
- query-client v2.1.0
- sdk v3.2.0
- translations v1.21.0

test: udpate the shortlink test for read only members

chore: improve the code from the PR #861
- Update the redirection host to the short link’s backend route (go.graasp.org for prod)
- Update mockGetShortLinksItem to filter by item id
- Update SDK version
- Adding changeVisibility test (part of tests from deleted shareItem)
- Update shareItem tests to test short links displayed links
- Moved short link test into share folder
- Replace alias by short link in translations
- Translates alias input
- Replace aliasUnchanged state by hasAliasChanged in ShortLinkDialogContent
- Regroup the useEffect in AliasValidation
- Set GraaspLogo as default icon when PlatformIcon get invalid platform
- Encapsulate debounce of API calls in a custom hooks
- Others minor improvements

chore: improve aliasAvailable check and make the item's platforms static
- Use Boolean wrapper to check the aliasAvailable in AliasValidation.tsx
- Set the item’s platforms static in the ShortLinkRenderer.tsx

* fix(test): use an id for custom app instead of translated name

* fix: use translated text for flag item button content

---------

Co-authored-by: spaenleh <[email protected]>
  • Loading branch information
ReidyT and spaenleh authored Dec 1, 2023
1 parent 14ecbee commit 946d8d8
Show file tree
Hide file tree
Showing 49 changed files with 2,412 additions and 2,030 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/cypress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
VITE_GRAASP_LIBRARY_HOST: ${{ vars.VITE_GRAASP_LIBRARY_HOST }}
VITE_GRAASP_ANALYZER_HOST: ${{ vars.VITE_GRAASP_ANALYZER_HOST }}
VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }}
VITE_GRAASP_REDIRECTION_HOST: ${{ vars.VITE_GRAASP_REDIRECTION_HOST }}

# use the Cypress GitHub Action to run Cypress tests within the chrome browser
- name: Cypress run
Expand All @@ -65,6 +66,7 @@ jobs:
VITE_GRAASP_LIBRARY_HOST: ${{ vars.VITE_GRAASP_LIBRARY_HOST }}
VITE_GRAASP_ANALYZER_HOST: ${{ vars.VITE_GRAASP_ANALYZER_HOST }}
VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }}
VITE_GRAASP_REDIRECTION_HOST: ${{ vars.VITE_GRAASP_REDIRECTION_HOST }}

# after the test run completes
# store any screenshots
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
# VITE_GA_MEASUREMENT_ID: ${{ secrets.VITE_GA_MEASUREMENT_ID }}
VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }}
VITE_GRAASP_REDIRECTION_HOST: ${{ vars.VITE_GRAASP_REDIRECTION_HOST }}
run: yarn build
shell: bash

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
VITE_GA_MEASUREMENT_ID: ${{ secrets.VITE_GA_MEASUREMENT_ID }}
VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }}
VITE_GRAASP_REDIRECTION_HOST: ${{ vars.VITE_GRAASP_REDIRECTION_HOST }}
run: yarn build
shell: bash

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
# un-comment to enable Google Analytics
# VITE_GA_MEASUREMENT_ID: ${{ secrets.VITE_GA_MEASUREMENT_ID }}
VITE_SHOW_NOTIFICATIONS: ${{ vars.VITE_SHOW_NOTIFICATIONS }}
VITE_GRAASP_REDIRECTION_HOST: ${{ vars.VITE_GRAASP_REDIRECTION_HOST }}
run: yarn build
shell: bash

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ VITE_PORT=3111
VITE_GRAASP_API_HOST=http://localhost:3000
VITE_SHOW_NOTIFICATIONS=true
VITE_GRAASP_AUTH_HOST=http://localhost:3001
# in prod, it is https://go.graasp.org
VITE_GRAASP_REDIRECTION_HOST=http://localhost:3000/items/short-links
VITE_H5P_INTEGRATION_URL=
VITE_VERSION=latest-dev
```
Expand Down Expand Up @@ -55,6 +57,8 @@ VITE_GRAASP_AUTH_HOST=http://localhost:3001
VITE_GRAASP_PLAYER_HOST=http://localhost:3112
VITE_GRAASP_LIBRARY_HOST=http://localhost:3005
VITE_GRAASP_ANALYZER_HOST=http://localhost:3113
# in prod, it is https://go.graasp.org who will redirect to the backend
VITE_GRAASP_REDIRECTION_HOST=http://localhost:3000/items/short-links
VITE_H5P_INTEGRATION_URL=
VITE_VERSION=cypress-tests
VITE_SHOW_NOTIFICATIONS=true
Expand Down
2 changes: 2 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export default defineConfig({
BUILDER_HOST: `http://localhost:${process.env.VITE_PORT}`,
PLAYER_HOST: process.env.VITE_GRAASP_PLAYER_HOST,
ANALYZER_HOST: process.env.VITE_GRAASP_ANALYZER_HOST,
LIBRARY_HOST: process.env.VITE_GRAASP_LIBRARY_HOST,
REDIRECTION_HOST: process.env.VITE_GRAASP_REDIRECTION_HOST,
},
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/item/flag/flagItem.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
buildItemMenu,
buildItemMenuButtonId,
} from '../../../../src/config/selectors';
import { BUILDER } from '../../../../src/langs/constants';
import { SAMPLE_ITEMS } from '../../../fixtures/items';
import { CURRENT_USER } from '../../../fixtures/members';

Expand All @@ -30,7 +31,7 @@ const flagItem = (itemId: string, type: FlagType) => {
flagListItem.click();

i18n.changeLanguage(CURRENT_USER.extra.lang as string);
const text = i18n.t('Flag', { ns: BUILDER_NAMESPACE });
const text = i18n.t(BUILDER.FLAG_ITEM_BUTTON, { ns: BUILDER_NAMESPACE });
const flagItemButton = cy.get(`button:contains("${text}")`);

flagItemButton.click();
Expand Down
7 changes: 6 additions & 1 deletion cypress/e2e/item/publish/coEditorSettings.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ import { buildItemPath } from '../../../../src/config/paths';
import {
CO_EDITOR_SETTINGS_RADIO_GROUP_ID,
ITEM_HEADER_ID,
SHARE_ITEM_VISIBILITY_SELECT_ID,
buildCoEditorSettingsRadioButtonId,
buildPublishButtonId,
} from '../../../../src/config/selectors';
import { ITEM_WITH_CATEGORIES_CONTEXT } from '../../../fixtures/categories';
import { PUBLISHED_ITEM } from '../../../fixtures/items';
import { MEMBERS, SIGNED_OUT_MEMBER } from '../../../fixtures/members';
import { EDIT_TAG_REQUEST_TIMEOUT } from '../../../support/constants';
import { changeVisibility } from '../share/shareItem.cy';

const openPublishItemTab = (id: string) => {
cy.get(`#${buildPublishButtonId(id)}`).click();
};

const changeVisibility = (value: string): void => {
cy.get(`#${SHARE_ITEM_VISIBILITY_SELECT_ID}`).click();
cy.get(`li[data-value="${value}"]`, { timeout: 1000 }).click();
};

const visitItemPage = () => {
cy.setUpApi(ITEM_WITH_CATEGORIES_CONTEXT);
const item = ITEM_WITH_CATEGORIES_CONTEXT.items[0];
Expand Down
119 changes: 119 additions & 0 deletions cypress/e2e/item/share/changeVisibility.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { ItemLoginSchemaType, ItemTagType } from '@graasp/sdk';

import { buildItemPath } from '@/config/paths';

import { SETTINGS } from '../../../../src/config/constants';
import {
SHARE_ITEM_PSEUDONYMIZED_SCHEMA_ID,
SHARE_ITEM_VISIBILITY_SELECT_ID,
buildShareButtonId,
} from '../../../../src/config/selectors';
import {
ITEM_LOGIN_ITEMS,
SAMPLE_ITEMS,
SAMPLE_PUBLIC_ITEMS,
} from '../../../fixtures/items';

const changeVisibility = (value: string): void => {
cy.get(`#${SHARE_ITEM_VISIBILITY_SELECT_ID}`).click();
cy.get(`li[data-value="${value}"]`, { timeout: 1000 }).click();
};

describe('Visibility of an Item', () => {
it('Change Private Item to Public', () => {
const item = SAMPLE_ITEMS.items[0];
cy.setUpApi({ ...SAMPLE_ITEMS });
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

const visiblitySelect = cy.get(
`#${SHARE_ITEM_VISIBILITY_SELECT_ID} + input`,
);

// visibility select default value
visiblitySelect.should('have.value', SETTINGS.ITEM_PRIVATE.name);

// change private -> public
changeVisibility(SETTINGS.ITEM_PUBLIC.name);
cy.wait(`@postItemTag-${ItemTagType.Public}`).then(
({ request: { url } }) => {
expect(url).to.contain(item.id);
},
);
});

it('Change Public Item to Private', () => {
const item = SAMPLE_PUBLIC_ITEMS.items[0];
cy.setUpApi({ ...SAMPLE_PUBLIC_ITEMS });
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();
cy.wait(1000);
const visiblitySelect = cy.get(
`#${SHARE_ITEM_VISIBILITY_SELECT_ID} + input`,
);

// visibility select default value
visiblitySelect.should('have.value', SETTINGS.ITEM_PUBLIC.name);

// change public -> private
changeVisibility(SETTINGS.ITEM_PRIVATE.name);
cy.wait(`@deleteItemTag-${ItemTagType.Public}`).then(
({ request: { url } }) => {
expect(url).to.contain(item.id);
},
);
});

it('Change Public Item to Item Login', () => {
const item = SAMPLE_PUBLIC_ITEMS.items[0];
cy.setUpApi({ ...SAMPLE_PUBLIC_ITEMS });
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();
cy.wait(1000);
const visiblitySelect = cy.get(
`#${SHARE_ITEM_VISIBILITY_SELECT_ID} + input`,
);

// visibility select default value
visiblitySelect.should('have.value', SETTINGS.ITEM_PUBLIC.name);

// change public -> item login
changeVisibility(SETTINGS.ITEM_LOGIN.name);
cy.wait([
`@deleteItemTag-${ItemTagType.Public}`,
'@putItemLoginSchema',
]).then((data) => {
const {
request: { url },
} = data[0];
expect(url).to.contain(item.id);
expect(url).to.contain(ItemTagType.Public); // originally item login
});
});

it('Change Pseudonymized Item to Private Item', () => {
const item = ITEM_LOGIN_ITEMS.items[0];
cy.setUpApi({ items: [item] });
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

// visibility select default value
cy.get(`#${SHARE_ITEM_VISIBILITY_SELECT_ID} + input`).should(
'have.value',
SETTINGS.ITEM_LOGIN.name,
);

// change item login schema
cy.get(`#${SHARE_ITEM_PSEUDONYMIZED_SCHEMA_ID} + input`).should(
'have.value',
ItemLoginSchemaType.Username,
);
// item login edition is done in itemLogin.cy.js

// change pseudonymized -> private
changeVisibility(SETTINGS.ITEM_PRIVATE.name);
cy.wait(`@deleteItemLoginSchema`).then(({ request: { url } }) => {
expect(url).to.include(item.id);
});
});
});
Loading

0 comments on commit 946d8d8

Please sign in to comment.