├── .dockerignore ├── tests ├── jsconfig.json ├── Asset │ ├── Mock │ │ ├── Media │ │ │ └── test_image.png │ │ └── AssetMockData.js │ ├── assets_test.js │ └── Step │ │ └── AssetSteps.js ├── .prettierrc ├── Setting │ ├── Mock │ │ └── SettingMockData.js │ ├── Page │ │ └── SettingPage.js │ ├── setting_test.js │ └── Step │ │ └── SettingStep.js ├── Authentication │ ├── Mock │ │ └── Authentication.data.js │ ├── login_test.js │ ├── Page │ │ └── LoginPage.js │ └── Step │ │ └── LoginSteps.js ├── steps_file.js ├── Collection │ ├── Mock │ │ └── CollectionMockData.js │ ├── collection_test.js │ ├── Page │ │ └── CollectionPage.js │ └── Step │ │ └── CollectionStep.js ├── Profile │ ├── Mock │ │ └── ProfileMockData.js │ ├── Page │ │ └── ProfilePage.js │ ├── profile_test.js │ └── Step │ │ └── ProfileStep.js ├── steps.d.ts ├── README.MD ├── codecept.conf.js └── package.json ├── packages └── aesirx-dam-app │ ├── src │ ├── env.js │ ├── integration │ │ ├── index.js │ │ └── lib │ │ │ ├── AesirXDamStorage.jsx │ │ │ ├── index.jsx │ │ │ ├── AesirXDamLayout.jsx │ │ │ └── index.module.scss │ ├── components │ │ ├── Storage │ │ │ ├── index.scss │ │ │ └── storage.svg │ │ ├── Search │ │ │ ├── index.module.scss │ │ │ └── index.jsx │ │ ├── MoveToFolder │ │ │ └── index.module.scss │ │ ├── ChooseAnAction │ │ │ ├── index.module.scss │ │ │ └── index.jsx │ │ ├── SbarLeft │ │ │ ├── index.scss │ │ │ └── index.jsx │ │ ├── ImageEditor │ │ │ └── index.jsx │ │ ├── Breadcrumbs │ │ │ └── index.module.scss │ │ ├── Dropzone │ │ │ ├── index.module.scss │ │ │ └── index.jsx │ │ ├── Table │ │ │ ├── ThumbDragPreview.jsx │ │ │ ├── table.module.scss │ │ │ └── ThumbDragLayer.jsx │ │ ├── ComponentNoData │ │ │ └── index.jsx │ │ ├── Menu │ │ │ └── index.scss │ │ └── Menu2 │ │ │ └── index.jsx │ ├── constants │ │ ├── DamConstant.js │ │ └── PageStatus.js │ ├── setupTests.js │ ├── store │ │ └── DamStore │ │ │ ├── DamUtils.js │ │ │ ├── DamViewModelContextProvider.js │ │ │ ├── DamViewModel.js │ │ │ └── DamFormViewModel.js │ ├── svg │ │ ├── Dot.jsx │ │ ├── DownloadIcon.jsx │ │ ├── EyeIcon.jsx │ │ ├── MoveFolderIcon.jsx │ │ ├── TrashIcon.jsx │ │ ├── ArrowBack.jsx │ │ ├── Folder.jsx │ │ ├── Storage.jsx │ │ ├── Word.jsx │ │ ├── EddingIcon.jsx │ │ ├── File.jsx │ │ ├── Xlsx.jsx │ │ ├── CloudUpload.jsx │ │ ├── ThemeMode.jsx │ │ ├── Warn.jsx │ │ └── Pdf.jsx │ ├── reportWebVitals.js │ ├── routes │ │ ├── menu.js │ │ └── routes.js │ ├── translations │ │ ├── index.js │ │ ├── tr │ │ │ └── common.json │ │ ├── th │ │ │ └── common.json │ │ ├── hr │ │ │ └── common.json │ │ ├── en │ │ │ └── common.json │ │ ├── ua │ │ │ └── common.json │ │ ├── vi │ │ │ └── common.json │ │ ├── dk │ │ │ └── common.json │ │ └── es │ │ │ └── common.json │ ├── index.jsx │ ├── scss │ │ └── app.scss │ ├── containers │ │ └── Homepage │ │ │ ├── index.jsx │ │ │ ├── index.scss │ │ │ ├── HomeUtils │ │ │ └── HomeUtils.js │ │ │ ├── index.module.scss │ │ │ └── HomeForm │ │ │ └── CollectionName.jsx │ ├── App.jsx │ └── logo.svg │ ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── assets │ │ └── images │ │ │ ├── SSO.png │ │ │ ├── Profile.png │ │ │ ├── folder-big.png │ │ │ ├── user_default.png │ │ │ ├── ep_circle-close.png │ │ │ ├── install_guide_1.jpeg │ │ │ ├── install_guide_6.png │ │ │ ├── akar-icons_folder.png │ │ │ ├── caret-right.svg │ │ │ ├── download.svg │ │ │ ├── eye.svg │ │ │ ├── pptx.svg │ │ │ ├── folder-outline.svg │ │ │ ├── document-text-outline.svg │ │ │ ├── move-to-folder.svg │ │ │ ├── icon-quote.svg │ │ │ ├── ion_trash-outline.svg │ │ │ ├── trash.svg │ │ │ ├── member.svg │ │ │ ├── folder.svg │ │ │ ├── storage.svg │ │ │ ├── import.svg │ │ │ ├── editing.svg │ │ │ ├── file.svg │ │ │ ├── assets.svg │ │ │ ├── word.svg │ │ │ ├── file_default.svg │ │ │ ├── xlsx.svg │ │ │ ├── setting.svg │ │ │ ├── collection_transfer.svg │ │ │ ├── help-icon.svg │ │ │ └── pdf.svg │ ├── manifest.json │ ├── index.html │ └── .htaccess │ ├── jsconfig.json │ ├── .env.dist │ ├── babel.config.json │ ├── craco.config.js │ ├── .gitignore │ ├── tsup.config.ts │ ├── .eslintrc │ └── package.json ├── .prettierrc ├── nx.json ├── docker-compose.yml ├── .gitmodules ├── .github ├── workflows │ ├── test.yml │ ├── demo.yml │ ├── codeql-analysis.yml │ └── release.yml └── dependabot.yml ├── .gitignore ├── package.json ├── README.md └── Dockerfile /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/npm-debug.log 3 | **/build 4 | **/dist -------------------------------------------------------------------------------- /tests/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true 4 | } 5 | } -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/env.js: -------------------------------------------------------------------------------- 1 | export const env = { ...process.env, ...window['env'] }; 2 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/Asset/Mock/Media/test_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/tests/Asset/Mock/Media/test_image.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/favicon.ico -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/logo192.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/logo512.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src/" 4 | }, 5 | "exclude": ["node_modules"] 6 | 7 | } 8 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/SSO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/SSO.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/Profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/Profile.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/folder-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/folder-big.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/user_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/user_default.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/integration/index.js: -------------------------------------------------------------------------------- 1 | export { default as AesirXDam } from './lib/index'; 2 | export { default as AesirXDamStorage } from './lib/AesirXDamStorage'; 3 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/ep_circle-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/ep_circle-close.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/install_guide_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/install_guide_1.jpeg -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/install_guide_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/install_guide_6.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/akar-icons_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aesirxio/dam-app/HEAD/packages/aesirx-dam-app/public/assets/images/akar-icons_folder.png -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Storage/index.scss: -------------------------------------------------------------------------------- 1 | .mini_left { 2 | .damstorage { 3 | display: none; 4 | } 5 | } 6 | 7 | .damstorage { 8 | position: relative; 9 | } 10 | -------------------------------------------------------------------------------- /tests/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "useTabs": true, 5 | "tabWidth": 2, 6 | "semi": false, 7 | "trailingComma": "es5", 8 | "bracketSameLine": true 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "trailingComma": "es5", 5 | "tabWidth": 2, 6 | "semi": true, 7 | "singleQuote": true, 8 | "printWidth": 100 9 | } 10 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Search/index.module.scss: -------------------------------------------------------------------------------- 1 | .width { 2 | max-width: 656px; 3 | } 4 | input { 5 | &::placeholder { 6 | color: #c0c0c0; 7 | font-weight: 400; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Setting/Mock/SettingMockData.js: -------------------------------------------------------------------------------- 1 | class SettingMockData { 2 | static getInfoToUpdateStoreAWS() { 3 | const storeAWS = { 4 | 5 | } 6 | return storeAWS 7 | } 8 | } 9 | export default SettingMockData 10 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/constants/DamConstant.js: -------------------------------------------------------------------------------- 1 | const DAM_COLUMN_INDICATOR = { 2 | ID: 'id', 3 | NAME: 'name', 4 | FILE_SIZE: 'file_size', 5 | OWNER: 'owner', 6 | LAST_MODIFIED: 'modified_date', 7 | }; 8 | export { DAM_COLUMN_INDICATOR }; 9 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/.env.dist: -------------------------------------------------------------------------------- 1 | REACT_APP_SSO_CLIENT_ID=[REPLACE THIS WITH THE PROVIDED REACT_APP_SSO_CLIENT_ID from https://dam.aesirx.io] 2 | REACT_APP_SSO_CLIENT_SECRET=[REPLACE THIS WITH THE PROVIDED REACT_APP_SSO_CLIENT_SECRET from https://dam.aesirx.io] 3 | PORT=3000 -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasksRunnerOptions": { 3 | "default": { 4 | "runner": "nx/tasks-runners/default", 5 | "options": { 6 | "cacheableOperations": [] 7 | } 8 | } 9 | }, 10 | "affected": { 11 | "defaultBase": "develop" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Authentication/Mock/Authentication.data.js: -------------------------------------------------------------------------------- 1 | class AuthenticationMockData { 2 | static getInformationForLogin() { 3 | const Info = { 4 | email: 'demo-dam@aesirx.io', 5 | password: 'demo-dam', 6 | } 7 | return Info 8 | } 9 | } 10 | export default AuthenticationMockData 11 | -------------------------------------------------------------------------------- /tests/steps_file.js: -------------------------------------------------------------------------------- 1 | // in this file you can append custom step methods to 'I' object 2 | 3 | module.exports = function() { 4 | return actor({ 5 | 6 | // Define custom steps here, use 'this' to access default methods of I. 7 | // It is recommended to place a general 'login' function here. 8 | 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/constants/PageStatus.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | const PAGE_STATUS = { 7 | LOADING: 1, 8 | READY: 2, 9 | ERROR: 3, 10 | }; 11 | 12 | export default PAGE_STATUS; 13 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | app: 5 | image: aesirxio/dam-app:latest 6 | pull_policy: always 7 | environment: 8 | REACT_APP_SSO_CLIENT_ID: ${REACT_APP_SSO_CLIENT_ID} 9 | REACT_APP_SSO_CLIENT_SECRET: ${REACT_APP_SSO_CLIENT_SECRET} 10 | ports: 11 | - '${PORT-3000}:3000' 12 | -------------------------------------------------------------------------------- /tests/Collection/Mock/CollectionMockData.js: -------------------------------------------------------------------------------- 1 | class CollectionMockData { 2 | static getInformationCollectionForCreate() { 3 | const collection = { 4 | name: 'Collection test automation', 5 | nameUpdate: 'Collection test automation update', 6 | } 7 | return collection 8 | } 9 | } 10 | export default CollectionMockData 11 | -------------------------------------------------------------------------------- /tests/Profile/Mock/ProfileMockData.js: -------------------------------------------------------------------------------- 1 | class ProfileMockData { 2 | static getUserInformationForUpdate() { 3 | const profile = { 4 | fullName: 'Demo-dam', 5 | phone: '(+84) 28 3838 9052', 6 | currentPassword: 'demo-dam', 7 | newPassword: '123456', 8 | } 9 | return profile 10 | } 11 | } 12 | export default ProfileMockData 13 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/caret-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/steps.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | type steps_file = typeof import('./steps_file.js'); 3 | 4 | declare namespace CodeceptJS { 5 | interface SupportObject { I: I, current: any } 6 | interface Methods extends Puppeteer {} 7 | interface I extends ReturnType {} 8 | namespace Translation { 9 | interface Actions {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/MoveToFolder/index.module.scss: -------------------------------------------------------------------------------- 1 | .list { 2 | max-height: 200px; 3 | overflow-y: auto; 4 | transition: 0.5s all ease-in-out; 5 | } 6 | 7 | .item { 8 | &:hover { 9 | background-color: var(--aesirxui-bg-color-blue-9); 10 | } 11 | &.active { 12 | &:hover { 13 | background-color: var(--aesirxui-bg-color-blue-9); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/Authentication/login_test.js: -------------------------------------------------------------------------------- 1 | import LoginSteps from './Step/LoginSteps' 2 | import AuthenticationMockData from './Mock/Authentication.data' 3 | 4 | Feature('Login') 5 | 6 | Scenario('Login on app', ({ Data }) => { 7 | let login = new LoginSteps() 8 | login.loginOnApp(Data.email, Data.password) 9 | }).injectDependencies({ 10 | Data: AuthenticationMockData.getInformationForLogin(), 11 | }) 12 | -------------------------------------------------------------------------------- /tests/Asset/Mock/AssetMockData.js: -------------------------------------------------------------------------------- 1 | class AssetMockData { 2 | static getInformationForUploadAsset() { 3 | const asset = { 4 | name: 'test_image.png', 5 | file: 'Asset/Mock/Media/test_image.png', 6 | } 7 | return asset 8 | } 9 | static getInformationForUpdateAsset() { 10 | const asset = { 11 | name: 'Image update', 12 | } 13 | return asset 14 | } 15 | } 16 | export default AssetMockData 17 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-react", 4 | ["@babel/preset-env" , { "modules": false }] 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-syntax-dynamic-import", 8 | [ 9 | "module-resolver", { 10 | "root": ["./src"] 11 | }], 12 | [ 13 | "inline-react-svg" 14 | ], 15 | ["file-loader"] 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "packages/aesirx-uikit"] 2 | path = packages/aesirx-uikit 3 | url = https://github.com/aesirxio/aesirx-uikit.git 4 | branch = master 5 | [submodule "packages/aesirx-lib"] 6 | path = packages/aesirx-lib 7 | url = https://github.com/aesirxio/aesirx-lib.git 8 | branch = master 9 | [submodule "packages/aesirx-sso"] 10 | path = packages/aesirx-sso 11 | url = https://github.com/aesirxio/sso.git 12 | branch = master 13 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/setupTests.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 7 | // allows you to do things like: 8 | // expect(element).toHaveTextContent(/react/i) 9 | // learn more: https://github.com/testing-library/jest-dom 10 | import '@testing-library/jest-dom'; 11 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/ChooseAnAction/index.module.scss: -------------------------------------------------------------------------------- 1 | .dropdown_item { 2 | &:hover { 3 | background-color: transparent; 4 | color: var(--bs-green) !important; 5 | } 6 | } 7 | 8 | .border_top { 9 | &::after { 10 | content: ''; 11 | position: absolute; 12 | top: 0; 13 | left: 50%; 14 | width: 80%; 15 | transform: translateX(-50%); 16 | height: 1px; 17 | background-color: var(--bs-gray-900); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/craco.config.js: -------------------------------------------------------------------------------- 1 | const { DefinePlugin } = require('webpack'); 2 | const { GitRevisionPlugin } = require('git-revision-webpack-plugin'); 3 | const gitRevisionPlugin = new GitRevisionPlugin(); 4 | 5 | module.exports = { 6 | eslint: { 7 | enable: false, 8 | }, 9 | 10 | webpack: { 11 | plugins: { 12 | add: [ 13 | new DefinePlugin({ 14 | VERSION: JSON.stringify(gitRevisionPlugin.version()), 15 | }), 16 | ], 17 | }, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /tests/Setting/Page/SettingPage.js: -------------------------------------------------------------------------------- 1 | class SettingPage { 2 | locators = { 3 | urlSetting: 'setting', 4 | configurationStorageText: 'Configuration Storage', 5 | storageLabel: 'Storage*', 6 | saveSettingButton: '.btn-success', 7 | storageSelect: '(//div[@class=" css-hlgwow"])[2]', 8 | storageInput: '(//div[@class=" css-hlgwow"])[2]//input', 9 | saveSuccessMessage: 'Success', 10 | clientIdInput: '#key', 11 | secretInput: '#secret', 12 | regionInput: '#region', 13 | bucketInput: '#bucket', 14 | } 15 | } 16 | export default SettingPage 17 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/SbarLeft/index.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | .progress { 7 | height: 4px; 8 | } 9 | .sidebar { 10 | padding-bottom: 234px; 11 | } 12 | 13 | .caret-toggle { 14 | left: 0; 15 | cursor: s-resize; 16 | &.index { 17 | right: 10px; 18 | left: unset; 19 | } 20 | &.down { 21 | transform: translate(-50%, -50%) rotate(90deg) !important; 22 | cursor: n-resize; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /tests/node_modules 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | #dist 16 | /dist 17 | 18 | #vscode 19 | .vscode 20 | 21 | /.idea 22 | 23 | # misc 24 | .DS_Store 25 | .env 26 | .env.local 27 | .env.development.local 28 | .env.test.local 29 | .env.production.local 30 | 31 | npm-debug.log* 32 | yarn-debug.log* 33 | yarn-error.log* 34 | .yalc 35 | yalc.lock -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/store/DamStore/DamUtils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | class DamUtils { 7 | transformPersonaResponseIntoModel = (response) => { 8 | return response; 9 | }; 10 | 11 | transformResponseIntoSearchItems = (response) => { 12 | return response; 13 | }; 14 | 15 | transformDataToApiMoveToFolder = (data) => { 16 | return data; 17 | }; 18 | } 19 | 20 | const utils = new DamUtils(); 21 | 22 | export default utils; 23 | -------------------------------------------------------------------------------- /tests/README.MD: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | After cloning the repository, you need go to tests folder 4 | ```bash 5 | cd tests 6 | ``` 7 | After that it should be enough to `npm install` all the dependencies and then proceed to the **Development** step. 8 | 9 | ```bash 10 | npm install 11 | ``` 12 | 13 | ## Development 14 | 15 | Running `npm run test-dam-app-collection` will start the demo flow. 16 | 17 | 18 | ```bash 19 | npm run test-dam-app-login 20 | npm run test-dam-app-collection 21 | npm run test-dam-app-asset 22 | npm run test-dam-app-profile 23 | npm run test-dam-app-setting 24 | ``` -------------------------------------------------------------------------------- /tests/Authentication/Page/LoginPage.js: -------------------------------------------------------------------------------- 1 | class LoginPage { 2 | locators = { 3 | url: 'login', 4 | signInText: 'Sign In to getting started.', 5 | emailInput: '//input[@name="username"]', 6 | emailLabel: 'Email *', 7 | passwordInput: '//input[@name="password"]', 8 | passwordLabel: 'Password *', 9 | signInButton: '.btn-success', 10 | forGotPasswordText: "//a[contains(text(),'Forgot Password?')]", 11 | adminText: 'Your digital Assets', 12 | signOutSpan: "//span[contains(text(),'Sign Out')]", 13 | spinner: "//div[@class='spinner-border']" 14 | } 15 | } 16 | export default LoginPage 17 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Dot.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Dot = (props) => { 4 | return ( 5 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default Dot; 21 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | const reportWebVitals = (onPerfEntry) => { 7 | if (onPerfEntry && onPerfEntry instanceof Function) { 8 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 9 | getCLS(onPerfEntry); 10 | getFID(onPerfEntry); 11 | getFCP(onPerfEntry); 12 | getLCP(onPerfEntry); 13 | getTTFB(onPerfEntry); 14 | }); 15 | } 16 | }; 17 | 18 | export default reportWebVitals; 19 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/routes/menu.js: -------------------------------------------------------------------------------- 1 | const settingMenu = [ 2 | { 3 | name: 'profile', 4 | text: 'txt_menu_profile', 5 | link: '/profile', 6 | icons_color: '/assets/images/Profile.png', 7 | }, 8 | { 9 | name: 'SSO', 10 | text: 'txt_sso', 11 | link: '/sso', 12 | icons_color: '/assets/images/SSO.png', 13 | }, 14 | ]; 15 | 16 | const profileMenu = [ 17 | { 18 | key: 1, 19 | text: 'txt_profile', 20 | link: '/profile', 21 | }, 22 | { 23 | key: 2, 24 | text: 'txt_sso', 25 | link: '/sso', 26 | }, 27 | ]; 28 | 29 | export { profileMenu, settingMenu }; 30 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "AesirX - DMA", 3 | "name": "AesirX - DMA", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/integration/lib/AesirXDamStorage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Storage from 'components/Storage'; 4 | import appLanguages from 'translations'; 5 | import { AesirXI18nextProvider, ErrorBoundary } from 'aesirx-uikit'; 6 | 7 | const AesirXDamStorage = (props) => { 8 | return ( 9 | 10 | 11 |
12 | 13 |
14 |
15 |
16 | ); 17 | }; 18 | 19 | export default AesirXDamStorage; 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: 16.x 15 | 16 | - run: git submodule update --init --recursive 17 | - name: Install dependencies 18 | run: yarn install 19 | 20 | - name: Run build 21 | run: CI=false yarn build 22 | 23 | - name: Run publish 24 | run: CI=false yarn prepublishOnly 25 | 26 | - name: Run Prettier 27 | run: yarn run format:check 28 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/translations/index.js: -------------------------------------------------------------------------------- 1 | import common_dk from './dk/common.json'; 2 | import common_en from './en/common.json'; 3 | import common_es from './es/common.json'; 4 | import common_hr from './hr/common.json'; 5 | import common_th from './th/common.json'; 6 | import common_ua from './ua/common.json'; 7 | import common_vn from './vi/common.json'; 8 | import common_fr from './fr/common.json'; 9 | 10 | const appLanguages = { 11 | en: common_en, 12 | da: common_dk, 13 | vi: common_vn, 14 | th: common_th, 15 | hr: common_hr, 16 | uk: common_ua, 17 | es: common_es, 18 | fr: common_fr, 19 | }; 20 | 21 | export default appLanguages; 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: 'npm' # See documentation for possible values 9 | directory: '/' # Location of package manifests 10 | schedule: 11 | interval: 'monthly' 12 | 13 | - package-ecosystem: 'github-actions' 14 | directory: '/' 15 | schedule: 16 | interval: 'monthly' 17 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/integration/lib/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AesirXDamLayout from './AesirXDamLayout'; 3 | import { Toast, AesirXI18nextProvider, ErrorBoundary } from 'aesirx-uikit'; 4 | 5 | import appLanguages from 'translations'; 6 | class AesirXDam extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | } 10 | 11 | render() { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | } 22 | export default AesirXDam; 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 5 | 6 | # dependencies 7 | /tests/node_modules 8 | **/node_modules 9 | /.pnp 10 | .pnp.js 11 | 12 | # testing 13 | /coverage 14 | 15 | # production 16 | /build 17 | 18 | #dist 19 | /dist 20 | 21 | #vscode 22 | .vscode 23 | 24 | /.idea 25 | 26 | # misc 27 | .DS_Store 28 | .env 29 | .env.local 30 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | npm-debug.log* 35 | yarn-debug.log* 36 | yarn-error.log* 37 | .yalc 38 | yalc.lock 39 | .nx/installation 40 | .nx/cache -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/pptx.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | import * as ReactDOMClient from 'react-dom/client'; 8 | import App from 'App'; 9 | import reportWebVitals from 'reportWebVitals'; 10 | 11 | const container = document.getElementById('root'); 12 | 13 | // Create a root. 14 | const root = ReactDOMClient.createRoot(container); 15 | 16 | // Initial render: Render an element to the root. 17 | root.render(); 18 | 19 | reportWebVitals(); 20 | 21 | if (process.env.NODE_ENV === 'production') { 22 | console.log = () => {}; 23 | console.error = () => {}; 24 | console.debug = () => {}; 25 | } 26 | -------------------------------------------------------------------------------- /tests/codecept.conf.js: -------------------------------------------------------------------------------- 1 | const { setHeadlessWhen, setCommonPlugins } = require('@codeceptjs/configure') 2 | // turn on headless mode when running with HEADLESS=true environment variable 3 | // export HEADLESS=true && npx codeceptjs run 4 | setHeadlessWhen(process.env.HEADLESS) 5 | 6 | // enable all common plugins https://github.com/codeceptjs/configure#setcommonplugins 7 | setCommonPlugins() 8 | 9 | /** @type {CodeceptJS.MainConfig} */ 10 | exports.config = { 11 | tests: './*_test.js', 12 | output: './output', 13 | helpers: { 14 | Puppeteer: { 15 | url: 'https://dev.dam.aesirx.io/', 16 | show: true, 17 | windowSize: '1200x900', 18 | }, 19 | }, 20 | include: { 21 | I: './steps_file.js', 22 | }, 23 | name: 'tests', 24 | } 25 | require('import-export') 26 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/DownloadIcon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Edding = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 20 | ); 21 | }; 22 | 23 | export default Edding; 24 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/scss/app.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | @import 'aesirx-uikit/dist/utils/bootstrap.scss'; 7 | @import 'bootstrap/scss/root'; 8 | @import 'bootstrap/scss/reboot'; 9 | 10 | .progress { 11 | height: 4px; 12 | } 13 | 14 | .caret-toggle { 15 | left: 0; 16 | cursor: s-resize; 17 | &.index { 18 | right: 10px; 19 | left: unset; 20 | } 21 | &.down { 22 | transform: translate(-50%, -50%) rotate(90deg) !important; 23 | cursor: n-resize; 24 | } 25 | } 26 | 27 | .svg_ic-menu { 28 | vertical-align: baseline; 29 | } 30 | 31 | .tui-image-editor-container .tui-image-editor-header-logo { 32 | display: none; 33 | } 34 | -------------------------------------------------------------------------------- /tests/Profile/Page/ProfilePage.js: -------------------------------------------------------------------------------- 1 | class ProfilePage { 2 | locators = { 3 | urlProfile: 'profile', 4 | generalInformationText: 'General Information', 5 | fullNameInput: "//input[@id='fullname']", 6 | phoneInput: "//input[@id='phone']", 7 | updateGeneralButton: "(//span[contains(text(),'Update')])[1]", 8 | profileSpan: "//span[contains(text(),'Profile')]", 9 | passwordSection: "//h2[contains(text(),'Password')]", 10 | passwordText: 'Password', 11 | currentPasswordInput: '#curr_password', 12 | newPasswordInput: '#new_password', 13 | confirmNewPasswordInput: '#new_checked_password', 14 | updatePasswordButton: "(//span[contains(text(),'Update')])[2]", 15 | messageSuccess: 'Success', 16 | welcomeText: 'Sign In to getting started.', 17 | } 18 | } 19 | export default ProfilePage 20 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/folder-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/store/DamStore/DamViewModelContextProvider.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | export const DamStore = React.createContext(); 8 | 9 | export const DamStoreProvider = ({ children, viewModel }) => { 10 | return {children}; 11 | }; 12 | 13 | /* Hook to use store in any functional component */ 14 | export const useDamViewModel = () => React.useContext(DamStore); 15 | 16 | /* HOC to inject store to any functional or class component */ 17 | export const withDamViewModel = (Component) => (props) => { 18 | return ; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/document-text-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/containers/Homepage/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React, { Suspense } from 'react'; 7 | import { Spinner } from 'aesirx-uikit'; 8 | 9 | import HomeActionBar from './HomeForm/HomeActionBar'; 10 | import HomeList from './HomeList/HomeList'; 11 | 12 | const HomePage = (props) => { 13 | return ( 14 |
15 |
16 | 17 |
18 | }> 19 | 20 | 21 |
22 | ); 23 | }; 24 | 25 | export default HomePage; 26 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/move-to-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/Setting/setting_test.js: -------------------------------------------------------------------------------- 1 | import AuthenticationMockData from '../Authentication/Mock/Authentication.data' 2 | import SettingStep from './Step/SettingStep' 3 | import LoginSteps from '../Authentication/Step/LoginSteps' 4 | import SettingMockData from './Mock/SettingMockData' 5 | 6 | const setting = new SettingStep() 7 | const login = new LoginSteps() 8 | Feature('Setting') 9 | Scenario('Setting Storage default', ({ Data }) => { 10 | login.loginOnApp(Data.email, Data.password) 11 | setting.settingStorageDefault() 12 | }).injectDependencies({ 13 | Data: AuthenticationMockData.getInformationForLogin(), 14 | }) 15 | Scenario('Setting Storage AWS', ({ Data, Setting }) => { 16 | login.loginOnApp(Data.email, Data.password) 17 | setting.settingStorageAWS(Setting) 18 | }).injectDependencies({ 19 | Data: AuthenticationMockData.getInformationForLogin(), 20 | Setting: SettingMockData.getInfoToUpdateStoreAWS(), 21 | }) 22 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/icon-quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/Collection/collection_test.js: -------------------------------------------------------------------------------- 1 | import LoginSteps from '../Authentication/Step/LoginSteps' 2 | import CollectionStep from './Step/CollectionStep' 3 | import AuthenticationMockData from '../Authentication/Mock/Authentication.data' 4 | import CollectionMockData from './Mock/CollectionMockData' 5 | 6 | const login = new LoginSteps() 7 | const collection = new CollectionStep() 8 | 9 | Feature('Collection') 10 | 11 | Scenario('Create collection', ({ Data, Collection }) => { 12 | login.loginOnApp(Data.email, Data.password) 13 | collection.createCollection(Collection.name) 14 | collection.searchCollection(Collection.name) 15 | collection.updateCollectionName(Collection.name, Collection.nameUpdate) 16 | collection.deleteCollection(Collection.nameUpdate) 17 | }).injectDependencies({ 18 | Data: AuthenticationMockData.getInformationForLogin(), 19 | Collection: CollectionMockData.getInformationCollectionForCreate(), 20 | }) 21 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/store/DamStore/DamViewModel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import DamListViewModel from './DamListViewModel'; 7 | import DamFromViewModel from './DamFormViewModel'; 8 | class DamViewModel { 9 | damListViewModel = null; 10 | damFormViewModel = null; 11 | constructor(damStore) { 12 | if (damStore) { 13 | this.damListViewModel = new DamListViewModel(damStore); 14 | this.damFormViewModel = new DamFromViewModel(damStore); 15 | this.damListViewModel.setDamFormViewModel(this.damFormViewModel); 16 | this.damFormViewModel.setDamListViewModel(this.damListViewModel); 17 | } 18 | } 19 | 20 | getDamListViewModel = () => this.damListViewModel; 21 | getDamFormViewModel = () => this.damFormViewModel; 22 | } 23 | 24 | export default DamViewModel; 25 | -------------------------------------------------------------------------------- /tests/Profile/profile_test.js: -------------------------------------------------------------------------------- 1 | import AuthenticationMockData from '../Authentication/Mock/Authentication.data' 2 | import ProfileStep from './Step/ProfileStep' 3 | import LoginSteps from '../Authentication/Step/LoginSteps' 4 | import ProfileMockData from './Mock/ProfileMockData' 5 | 6 | const profile = new ProfileStep() 7 | const login = new LoginSteps() 8 | Feature('Profile') 9 | 10 | Scenario('Update Profile', async ({ Data, ProfileInfo }) => { 11 | login.loginOnApp(Data.email, Data.password) 12 | await profile.updateGeneralInfo(ProfileInfo) 13 | profile.updatePassword(ProfileInfo) 14 | login.loginOnApp(Data.email, ProfileInfo.newPassword) 15 | ProfileInfo.currentPassword = ProfileInfo.newPassword 16 | ProfileInfo.newPassword = Data.password 17 | profile.updatePassword(ProfileInfo) 18 | }).injectDependencies({ 19 | Data: AuthenticationMockData.getInformationForLogin(), 20 | ProfileInfo: ProfileMockData.getUserInformationForUpdate(), 21 | }) 22 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tests", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "test-dam-app-login": "npx codeceptjs run --debug --verbose Authentication/login_test.js", 9 | "test-dam-app-collection": "npx codeceptjs run --debug --verbose Collection/collection_test.js", 10 | "test-dam-app-asset": "npx codeceptjs run --debug --verbose Asset/asset_test.js", 11 | "test-dam-app-profile": "npx codeceptjs run --debug --verbose Profile/profile_test.js", 12 | "test-dam-app-setting": "npx codeceptjs run --debug --verbose Setting/setting_test.js" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "dependencies": { 18 | "codeceptjs": "^3.4.1", 19 | "import-export": "^1.0.1", 20 | "puppeteer": "^19.7.2" 21 | }, 22 | "devDependencies": { 23 | "prettier": "^2.8.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Authentication/Step/LoginSteps.js: -------------------------------------------------------------------------------- 1 | import LoginPage from '../Page/LoginPage' 2 | 3 | const { I } = inject() 4 | 5 | class LoginSteps { 6 | constructor() { 7 | this.page = new LoginPage() 8 | } 9 | 10 | loginOnApp(email, password) { 11 | I.amOnPage(this.page.locators.url) 12 | I.waitForText(this.page.locators.signInText, 30) 13 | I.waitForText(this.page.locators.emailLabel, 30) 14 | I.waitForElement(this.page.locators.emailInput, 30) 15 | I.fillField(this.page.locators.emailInput, email) 16 | I.waitForElement(this.page.locators.passwordInput, 30) 17 | I.clearField(this.page.locators.passwordInput) 18 | I.fillField(this.page.locators.passwordInput, password) 19 | I.waitForElement(this.page.locators.forGotPasswordText, 30) 20 | I.waitForElement(this.page.locators.signInButton, 30) 21 | I.click(this.page.locators.signInButton) 22 | I.waitForText(this.page.locators.adminText, 30) 23 | I.waitForInvisible(this.page.locators.spinner, 30) 24 | } 25 | } 26 | export default LoginSteps 27 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/ion_trash-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "packages/*" 5 | ], 6 | "devDependencies": { 7 | "nx": "16.3.2" 8 | }, 9 | "resolutions": { 10 | "@yarnpkg/parsers": "3.0.0-rc.48.1", 11 | "tough-cookie": "^4", 12 | "semver": "^7", 13 | "jsdom": "^16", 14 | "json5": "^2", 15 | "postcss": "^8", 16 | "nth-check": "^2.0.1", 17 | "clipboardy": "3.0.0", 18 | "tsup": "6", 19 | "@types/react": "^18" 20 | }, 21 | "scripts": { 22 | "prepare": "nx run aesirx-lib:build && nx run aesirx-sso:build && nx run aesirx-uikit:build && nx run-many -t build:lib --exclude aesirx-uikit aesirx-lib", 23 | "dev": "nx run-many -t dev", 24 | "dev:lib": "nx run aesirx-dam-app:dev:lib", 25 | "build": "nx run aesirx-dam-app:build", 26 | "build:lib": "nx run aesirx-dam-app:build:lib", 27 | "lint:check": "nx run aesirx-dam-app:lint:check", 28 | "format:check": "nx run aesirx-dam-app:format:check", 29 | "prepublishOnly": "nx run aesirx-dam-app:prepublishOnly" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/EyeIcon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Eye = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 25 | 26 | ); 27 | }; 28 | 29 | export default Eye; 30 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { Options } from 'tsup'; 2 | import { sassPlugin } from 'esbuild-sass-plugin'; 3 | import { ScssModulesPlugin } from 'esbuild-scss-modules-plugin'; 4 | import inlineImage from 'esbuild-plugin-inline-image'; 5 | 6 | const env = process.env.NODE_ENV; 7 | 8 | export const tsup: Options = { 9 | clean: env !== 'development', 10 | format: ['esm'], 11 | watch: env === 'development', 12 | outDir: 'dist', 13 | entry: ['src/integration/index.js', 'src/integration/**/*.{js,jsx}'], //entry: ['src/index.{ts,tsx}', 'src/**/*.{ts,tsx}', '!src/**/*.test.{ts,tsx}', '!src/**/*.d.ts'], 14 | target: 'es2020', 15 | platform: 'browser', 16 | esbuildPlugins: [ 17 | inlineImage({ limit: -1 }), 18 | ScssModulesPlugin({ localsConvention: 'dashes' }), 19 | sassPlugin({ type: 'style' }), 20 | ], 21 | esbuildOptions(options, context) { 22 | options.drop = ['console']; 23 | }, 24 | outExtension() { 25 | return { 26 | js: `.js`, 27 | }; 28 | }, 29 | loader: { 30 | '.js': 'jsx', 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/member.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/ImageEditor/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'tui-image-editor/dist/tui-image-editor.css'; 3 | import ImageEditor from '@toast-ui/react-image-editor'; 4 | import { DAM_ASSETS_FIELD_KEY } from 'aesirx-lib'; 5 | import moment from 'moment'; 6 | 7 | export default function ImageEditorComponent({ editorRef, damEditdata }) { 8 | const myTheme = { 9 | 'common.bi.image': '/assets/images/file.svg', 10 | 'common.bisize.width': '21px', 11 | 'loadButton.display': 'none', 12 | }; 13 | 14 | const imageEditorOptions = { 15 | includeUI: { 16 | loadImage: { 17 | path: `${damEditdata?.[DAM_ASSETS_FIELD_KEY.DOWNLOAD_URL]}?${moment( 18 | damEditdata[DAM_ASSETS_FIELD_KEY.LAST_MODIFIED] 19 | ).unix()}`, 20 | name: damEditdata?.[DAM_ASSETS_FIELD_KEY.NAME], 21 | }, 22 | theme: myTheme, 23 | menuBarPosition: 'bottom', 24 | }, 25 | cssMaxHeight: 500, 26 | cssMaxWidthL: 700, 27 | usageStatistics: false, 28 | }; 29 | 30 | return ; 31 | } 32 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Breadcrumbs/index.module.scss: -------------------------------------------------------------------------------- 1 | .dot { 2 | position: relative; 3 | width: 24px; 4 | height: 24px; 5 | transition: all 0.2s ease-in-out; 6 | &::after { 7 | content: ''; 8 | width: 100%; 9 | height: 100%; 10 | position: absolute; 11 | top: 50%; 12 | left: 50%; 13 | transform: translate(-50%, -50%); 14 | box-shadow: 0 3px 6px var(--bs-gray-400); 15 | border-radius: 50%; 16 | opacity: 0; 17 | transition: 0.5s all ease-in-out; 18 | pointer-events: none; 19 | } 20 | 21 | .list { 22 | top: 2rem; 23 | max-height: 200px; 24 | overflow-y: auto; 25 | // opacity: 0; 26 | // pointer-events: none; 27 | // user-select: none; 28 | // transition: 0.5s all ease-in-out; 29 | } 30 | &.active, 31 | &:hover { 32 | &::after { 33 | opacity: 1; 34 | transition: 0.5s all ease-in-out; 35 | } 36 | .list { 37 | transition: 0.5s all ease-in-out; 38 | opacity: 1; 39 | pointer-events: all; 40 | user-select: auto; 41 | } 42 | } 43 | } 44 | 45 | .h_40 { 46 | height: 40px; 47 | min-width: 200px; 48 | } 49 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/SbarLeft/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | import { withTranslation } from 'react-i18next'; 8 | 9 | import './index.scss'; 10 | import Menu from '../Menu'; 11 | import Menu2 from 'components/Menu2'; 12 | import { withRouter } from 'react-router-dom'; 13 | import { settingRoutes } from 'routes/routes'; 14 | import { SbarLeft as AesirXSbarLeft } from 'aesirx-uikit'; 15 | 16 | class SbarLeft extends React.Component { 17 | constructor(props) { 18 | super(props); 19 | this.state = {}; 20 | } 21 | 22 | componentDidMount() {} 23 | render() { 24 | const { match } = this.props; 25 | 26 | const has = settingRoutes.find((router) => router.path === match.path); 27 | 28 | return ( 29 | 30 | {!has ? ( 31 | <> 32 | 33 | 34 | ) : ( 35 | 36 | )} 37 | 38 | ); 39 | } 40 | } 41 | 42 | export default withTranslation()(withRouter(SbarLeft)); 43 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Dropzone/index.module.scss: -------------------------------------------------------------------------------- 1 | .onDragEnter { 2 | max-height: 100%; 3 | position: absolute; 4 | top: 100px; 5 | left: 0; 6 | z-index: 999; 7 | border: 1px var(--bs-success) dashed; 8 | background: rgba(0, 0, 0, 0.5); 9 | width: 100%; 10 | height: 100%; 11 | } 12 | 13 | .dropToUpload { 14 | position: fixed; 15 | left: calc(50% + 248px / 2); 16 | bottom: 0; 17 | transform: translate(-50%, -50%); 18 | z-index: 1000; 19 | p { 20 | background: var(--bs-white); 21 | color: var(--bs-black); 22 | min-width: 200px; 23 | text-align: center; 24 | min-height: 50px; 25 | padding: 10px; 26 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3); 27 | margin-bottom: 0; 28 | border-radius: 5px; 29 | } 30 | } 31 | 32 | .bounce { 33 | animation: bounce 2s infinite; 34 | -webkit-animation: bounce 2s infinite; 35 | -moz-animation: bounce 2s infinite; 36 | -o-animation: bounce 2s infinite; 37 | } 38 | @keyframes bounce { 39 | 0%, 40 | 20%, 41 | 50%, 42 | 80%, 43 | 100% { 44 | transform: translateY(0); 45 | } 46 | 40% { 47 | transform: translateY(-15px); 48 | } 49 | 60% { 50 | transform: translateY(-5px); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/routes/routes.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React, { lazy } from 'react'; 7 | import { LoginPage, ProfilePage } from 'aesirx-uikit'; 8 | import { Redirect } from 'react-router-dom'; 9 | const SSOConfig = lazy(() => 10 | import('aesirx-sso').then((module) => ({ default: module.SSOConfig })) 11 | ); 12 | const DashboardPage = lazy(() => import('../containers/Homepage')); 13 | 14 | const authRoutes = [ 15 | { 16 | path: '/login', 17 | exact: true, 18 | main: () => , 19 | }, 20 | ]; 21 | 22 | const mainRoutes = [ 23 | { 24 | path: ['/'], 25 | exact: true, 26 | main: () => , 27 | }, 28 | { 29 | path: ['/root', '/root/*'], 30 | exact: true, 31 | main: () => , 32 | }, 33 | ]; 34 | 35 | const settingRoutes = [ 36 | { 37 | path: '/profile', 38 | exact: false, 39 | main: () => , 40 | }, 41 | { 42 | path: '/sso', 43 | exact: false, 44 | main: () => , 45 | }, 46 | ]; 47 | 48 | export { authRoutes, mainRoutes, settingRoutes }; 49 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Table/ThumbDragPreview.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Image } from 'aesirx-uikit'; 4 | import { DAM_ASSETS_FIELD_KEY } from 'aesirx-lib'; 5 | import styles from './table.module.scss'; 6 | const ThumbsDragPreview = ({ thumbs }) => { 7 | return ( 8 |
9 | {thumbs.length ? ( 10 | thumbs.slice(0, 3).map((thumb, i) => ( 11 |
19 | {thumb.name} 28 | {thumb.name} 29 |
30 | )) 31 | ) : ( 32 |
File
33 | )} 34 |
35 | ); 36 | }; 37 | 38 | export default ThumbsDragPreview; 39 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/MoveFolderIcon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const MoveFolder = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 25 | 26 | ); 27 | }; 28 | 29 | export default MoveFolder; 30 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:react/recommended" 10 | ], 11 | "globals": { 12 | "Atomics": "readonly", 13 | "SharedArrayBuffer": "readonly" 14 | }, 15 | "parserOptions": { 16 | "ecmaFeatures": { 17 | "jsx": true 18 | }, 19 | "ecmaVersion": 2022, 20 | "sourceType": "module" 21 | }, 22 | "plugins": [ 23 | "react" 24 | ], 25 | "rules": { 26 | "no-unused-vars": "warn", 27 | "react/display-name": "off", 28 | "react/prop-types": "off", 29 | "react/jsx-key": "warn", 30 | "no-unsafe-optional-chaining": "warn", 31 | "react/no-deprecated": "warn", 32 | "react/no-children-prop": "warn", 33 | "no-case-declarations": "warn" 34 | }, 35 | 36 | "parser": "@babel/eslint-parser", 37 | "ignorePatterns": [ 38 | "*.json", 39 | "*.scss", 40 | "*.svg", 41 | "*.woff", 42 | "*.woff2", 43 | "*.ttf", 44 | "*.otf", 45 | "*.eot", 46 | "*.png", 47 | "*.config.js", 48 | "dist/*" 49 | ] 50 | } -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/storage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Storage/storage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Table/table.module.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | .btn { 7 | width: 35px; 8 | height: 35px; 9 | margin-right: 5px; 10 | margin-bottom: 5px; 11 | 12 | &:last-child { 13 | margin-right: 0; 14 | } 15 | } 16 | 17 | .btn_toggle { 18 | &:after { 19 | display: none !important; 20 | } 21 | } 22 | .col_thumb_folder { 23 | height: 220px; 24 | } 25 | .col_thumb { 26 | height: 248px; 27 | } 28 | .w_112 { 29 | min-width: 112px; 30 | } 31 | .w_272 { 32 | min-width: 272px; 33 | } 34 | .w_136 { 35 | min-width: 136px; 36 | } 37 | 38 | .image_thumb { 39 | width: 40px; 40 | height: 40px; 41 | overflow: hidden; 42 | img { 43 | object-fit: cover; 44 | width: 100%; 45 | height: 100%; 46 | } 47 | } 48 | 49 | .active { 50 | fill: var(--bs-white); 51 | } 52 | 53 | .inactive { 54 | fill: var(--bs-blue-9); 55 | } 56 | 57 | .checkbox { 58 | width: 16px; 59 | height: 16px; 60 | margin: 0 auto; 61 | input { 62 | width: 100%; 63 | height: 100%; 64 | } 65 | } 66 | .count { 67 | position: absolute; 68 | width: 32px; 69 | height: 32px; 70 | top: 16px; 71 | right: 16px; 72 | } 73 | .item_hover { 74 | &:hover { 75 | border: 1px solid var(--bs-green); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/Asset/assets_test.js: -------------------------------------------------------------------------------- 1 | import LoginSteps from '../Authentication/Step/LoginSteps' 2 | import AuthenticationMockData from '../Authentication/Mock/Authentication.data' 3 | import AssetSteps from './Step/AssetSteps' 4 | import AssetMockData from './Mock/AssetMockData' 5 | 6 | const login = new LoginSteps() 7 | const asset = new AssetSteps() 8 | 9 | Feature('Asset') 10 | 11 | Scenario('Create Asset', ({ Data, Asset }) => { 12 | login.loginOnApp(Data.email, Data.password) 13 | asset.createAsset(Asset) 14 | }).injectDependencies({ 15 | Data: AuthenticationMockData.getInformationForLogin(), 16 | Asset: AssetMockData.getInformationForUploadAsset(), 17 | AssetUpdate: AssetMockData.getInformationForUpdateAsset(), 18 | }) 19 | Scenario('Update Asset', ({ Data, Asset, AssetUpdate }) => { 20 | login.loginOnApp(Data.email, Data.password) 21 | asset.updateName(Asset, AssetUpdate) 22 | }).injectDependencies({ 23 | Data: AuthenticationMockData.getInformationForLogin(), 24 | Asset: AssetMockData.getInformationForUploadAsset(), 25 | AssetUpdate: AssetMockData.getInformationForUpdateAsset(), 26 | }) 27 | Scenario('Delete Asset', ({ Data, AssetUpdate }) => { 28 | login.loginOnApp(Data.email, Data.password) 29 | asset.deleteAsset(AssetUpdate) 30 | }).injectDependencies({ 31 | Data: AuthenticationMockData.getInformationForLogin(), 32 | AssetUpdate: AssetMockData.getInformationForUpdateAsset(), 33 | }) 34 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/TrashIcon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Trash = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 20 | 21 | 27 | 28 | ); 29 | }; 30 | 31 | export default Trash; 32 | -------------------------------------------------------------------------------- /.github/workflows/demo.yml: -------------------------------------------------------------------------------- 1 | name: demo 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | build-and-deploy: 10 | runs-on: ubuntu-latest 11 | environment: demo 12 | env: 13 | CI: false 14 | REACT_APP_DEMO_USER: ${{ secrets.REACT_APP_DEMO_USER }} 15 | REACT_APP_DEMO_PASSWORD: ${{ secrets.REACT_APP_DEMO_PASSWORD }} 16 | REACT_APP_SSO_CLIENT_ID: ${{ secrets.REACT_APP_SSO_CLIENT_ID }} 17 | REACT_APP_SSO_CLIENT_SECRET: ${{ secrets.REACT_APP_SSO_CLIENT_SECRET }} 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | ref: master 23 | 24 | - uses: actions/setup-node@v3 25 | with: 26 | node-version: 16 27 | 28 | - run: git submodule update --init --recursive 29 | - run: yarn install --frozen-lockfile 30 | - run: yarn build 31 | 32 | - name: Install SSH Key 33 | uses: shimataro/ssh-key-action@v2 34 | with: 35 | key: ${{ secrets.SSH_PRIVATE_KEY }} 36 | known_hosts: unnecessary 37 | 38 | - name: Adding Known Hosts 39 | run: ssh-keyscan -p ${{ secrets.SSH_PORT}} -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 40 | 41 | - name: Deploy with rsync 42 | run: rsync -avz -e "ssh -p ${{ secrets.SSH_PORT }}" ./packages/aesirx-dam-app/build/ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.SSH_PATH }} 43 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/ArrowBack.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ArrowBack = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 17 | 18 | ); 19 | }; 20 | 21 | export default ArrowBack; 22 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: 'CodeQL' 2 | 3 | on: 4 | push: 5 | branches: [master, develop, develop-*] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master, develop, develop-*] 9 | schedule: 10 | - cron: '15 2 * * 5' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | language: ['javascript'] 25 | 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v3 29 | 30 | # Initializes the CodeQL tools for scanning. 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v2 33 | with: 34 | languages: ${{ matrix.language }} 35 | 36 | - run: git submodule update --init --recursive 37 | 38 | - name: Install modules 39 | run: yarn install 40 | 41 | - name: Lint 42 | run: yarn lint:check 43 | 44 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 45 | # If this step fails, then you should remove it and run the build manually (see below) 46 | - name: Autobuild 47 | uses: github/codeql-action/autobuild@v2 48 | 49 | - name: Perform CodeQL Analysis 50 | uses: github/codeql-action/analyze@v2 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AesirX DAM 2 | 3 | ## About 4 | 5 | AesirX DAM is our Open-Source PWA-powered enterprise-level Digital Asset Management as a Service (DAMaaS) Solution 6 | 7 | Find out more in [https://dam.aesirx.io](https://dam.aesirx.io) 8 | 9 | ## Development 10 | 11 | 1. This project is using Monorepos with git submodule. You need to run `git submodule update --init --recursive` after cloned the project. 12 | 2. Run `yarn install` to install the dependencies. 13 | 3. Run `yarn prepare` to build the dependencies. 14 | 2. Rename the `.env.dist` file to `.env` on `packages/aesirx-dam-app` folder. 15 | 3. Replace license keys in the `.env` file with the one provided in your profile account. 16 | 1. `REACT_APP_SSO_CLIENT_ID` replace this with the provided `SSO CLIENT ID` from https://dapp.shield.aesirx.io/licenses 17 | 2. `REACT_APP_SSO_CLIENT_SECRET` replace this with the provided `SSO CLIENT SECRET` from https://dapp.shield.aesirx.io/licenses 18 | 3. `PORT` change the port. Default is 3000 19 | 20 | 5. Run `yarn dev` 21 | 6. Open [http://localhost:3000](http://localhost:3000) - 3000 is `PORT` to view it in the browser. 22 | 23 | ## Production 24 | Run on a webserver: 25 | 1. Run `yarn build` after changed `.env` file. 26 | 2. Upload `packages/aesirx-dam-app/build` folder to webserver. 27 | 28 | ### Dockerize 29 | 1. Rename and copy the `.env.dist` file to `.env` on `packages/aesirx-dam-app` folder to `root` folder. 30 | 2. Run `docker compose -f "docker-compose.yml" up -d --build` 31 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Table/ThumbDragLayer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDragLayer } from 'react-dnd'; 3 | import { DND_ITEM_TYPE } from './Thumb'; 4 | import ThumbDragPreview from './ThumbDragPreview'; 5 | 6 | const layerStyles = { 7 | position: 'fixed', 8 | pointerEvents: 'none', 9 | zIndex: 100, 10 | left: 0, 11 | top: 0, 12 | right: 0, 13 | bottom: 0, 14 | }; 15 | 16 | const getItemStyles = (currentOffset) => { 17 | if (!currentOffset) { 18 | return { 19 | display: 'none', 20 | }; 21 | } 22 | const { x, y } = currentOffset; 23 | return { 24 | transform: `translate(${x}px, ${y}px)`, 25 | filter: 'drop-shadow(0 2px 5px rgba(0,0,0,0.45))', 26 | }; 27 | }; 28 | 29 | export default function ThumbDragLayer() { 30 | const { itemType, isDragging, item, currentOffset } = useDragLayer((monitor) => ({ 31 | item: monitor.getItem(), 32 | itemType: monitor.getItemType(), 33 | currentOffset: monitor.getSourceClientOffset(), 34 | isDragging: monitor.isDragging(), 35 | })); 36 | 37 | const renderItem = (type, item) => { 38 | switch (type) { 39 | case DND_ITEM_TYPE: 40 | return ; 41 | default: 42 | return null; 43 | } 44 | }; 45 | if (!isDragging) { 46 | return null; 47 | } 48 | 49 | return ( 50 |
51 |
{renderItem(itemType, item)}
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/containers/Homepage/index.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | @import 'aesirx-uikit/dist/utils/bootstrap.scss'; 6 | 7 | .dam-integrate-layout { 8 | @include media-breakpoint-down(xxl) { 9 | .sdbar_right { 10 | width: 340px; 11 | } 12 | 13 | .pe-400 { 14 | padding-right: 340px !important; 15 | } 16 | } 17 | 18 | .home-modal { 19 | .modal-content { 20 | height: 80vh; 21 | overflow: hidden; 22 | padding-bottom: 1rem; 23 | } 24 | .modal-body { 25 | height: calc(100% - 48px); 26 | overflow: auto; 27 | } 28 | } 29 | 30 | @include media-breakpoint-down(xl) { 31 | .pe-400 { 32 | padding-right: 15px !important; 33 | } 34 | 35 | .show_menu_right { 36 | .sdbar_right { 37 | right: 0 !important; 38 | } 39 | } 40 | 41 | .item_hambuger_icon { 42 | display: flex !important; 43 | width: 24px; 44 | height: 24px; 45 | right: 10px; 46 | } 47 | 48 | .item_collap_fixed { 49 | display: none !important; 50 | } 51 | } 52 | #contextMenuItem { 53 | > div:not(:last-child) { 54 | svg { 55 | path { 56 | fill: $gray-900; 57 | } 58 | } 59 | .stroke-dark { 60 | path { 61 | stroke: $gray-900; 62 | fill: transparent; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Folder.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Folder = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 17 | 21 | 22 | ); 23 | }; 24 | 25 | export default Folder; 26 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/App.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import 'aesirx-uikit/dist/index.css'; 9 | import 'scss/app.scss'; 10 | 11 | import { AppProvider, Menu as AesirXMenu, isLogin } from 'aesirx-uikit'; 12 | import appLanguages from 'translations'; 13 | import { authRoutes, mainRoutes, settingRoutes } from 'routes/routes'; 14 | 15 | import { DamStoreProvider } from 'store/DamStore/DamViewModelContextProvider'; 16 | import DamViewModel from 'store/DamStore/DamViewModel'; 17 | import DamStore from 'store/DamStore/DamStore'; 18 | import Search from 'components/Search'; 19 | import Storage from 'components/Storage'; 20 | import Menu from 'components/Menu'; 21 | import { settingMenu, profileMenu } from 'routes/menu'; 22 | 23 | const damStore = new DamStore(); 24 | const damsViewModel = new DamViewModel(damStore); 25 | 26 | const App = () => { 27 | return ( 28 | 29 | } 37 | componentBottomMenu={} 38 | leftMenu={} 39 | settingMenu={} 40 | /> 41 | 42 | ); 43 | }; 44 | 45 | export default App; 46 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Storage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Storage = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default Storage; 29 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/editing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/integration/lib/AesirXDamLayout.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import { DamStoreProvider } from 'store/DamStore/DamViewModelContextProvider'; 9 | import DamViewModel from 'store/DamStore/DamViewModel'; 10 | import DamStore from 'store/DamStore/DamStore'; 11 | 12 | import AesirXDamComponent from './AesirXDamComponent'; 13 | import AesirXDamActionBar from './AesirXDamForm/AesirXDamActionBar'; 14 | import { useThemeContext } from 'aesirx-uikit'; 15 | 16 | const damStore = new DamStore(); 17 | const damsViewModel = new DamViewModel(damStore); 18 | 19 | const AesirXDamLayout = (props) => { 20 | const { theme } = useThemeContext(); 21 | 22 | return ( 23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |
39 | ); 40 | }; 41 | 42 | export default AesirXDamLayout; 43 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/integration/lib/index.module.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | .dam-integrate-layout { 7 | .item_collap_fixed { 8 | left: 250px; 9 | } 10 | 11 | .wrapper_new_schedule { 12 | top: 10px; 13 | right: 1.5rem; 14 | } 15 | 16 | .full_calender { 17 | .pe-400 { 18 | padding-right: 1rem !important; 19 | } 20 | 21 | .sdbar_right { 22 | display: none; 23 | } 24 | } 25 | .folder { 26 | margin-bottom: 32px; 27 | } 28 | 29 | .image { 30 | height: 212px; 31 | overflow: hidden; 32 | width: 100%; 33 | } 34 | .image_isList { 35 | width: 56px; 36 | height: 56px; 37 | } 38 | .popupImageHeight { 39 | height: calc(100% - 50px); 40 | } 41 | 42 | .txt_hover { 43 | &:hover { 44 | span { 45 | color: var(--bs-success); 46 | } 47 | svg { 48 | fill: var(--bs-success); 49 | path { 50 | fill: var(--bs-success); 51 | } 52 | } 53 | } 54 | } 55 | 56 | .input { 57 | border: 1px solid transparent; 58 | &::-moz-selection { 59 | /* Code for Firefox */ 60 | color: var(--bs-white); 61 | background: var(--bs-green); 62 | transition: 0.3s all ease-in-out; 63 | } 64 | &::selection { 65 | color: var(--bs-white); 66 | background: var(--bs-green); 67 | transition: 0.3s all ease-in-out; 68 | } 69 | &:focus { 70 | transition: 0.3s all ease-in-out; 71 | border-radius: 3px; 72 | // border: 1px solid #2828314d; 73 | box-shadow: unset; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/ComponentNoData/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | import React, { Component } from 'react'; 6 | import Dropzone from 'components/Dropzone'; 7 | 8 | import { withTranslation } from 'react-i18next'; 9 | 10 | class ComponentNoData extends Component { 11 | constructor(props) { 12 | super(props); 13 | } 14 | render() { 15 | const { className, createAssets, t } = this.props; 16 | return ( 17 |
24 | 25 |
26 |
27 |

28 | {t('txt_drop_files_anywhere_to_upload')} 29 |

30 |

{t('txt_or')}

31 | 32 |

33 | {t('txt_select_file')} 34 |

35 |

{t('maximum_upload_size')}

36 |
37 |
38 |
39 |
40 |
41 | ); 42 | } 43 | } 44 | 45 | export default withTranslation()(ComponentNoData); 46 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/assets.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/Profile/Step/ProfileStep.js: -------------------------------------------------------------------------------- 1 | import ProfilePage from '../Page/ProfilePage' 2 | 3 | const { I } = inject() 4 | 5 | class ProfileStep { 6 | constructor() { 7 | this.page = new ProfilePage() 8 | } 9 | 10 | async updateGeneralInfo(profile) { 11 | I.amOnPage(this.page.locators.urlProfile) 12 | I.waitForText(this.page.locators.generalInformationText, 30) 13 | I.waitForElement(this.page.locators.fullNameInput, 30) 14 | I.fillField(this.page.locators.fullNameInput, profile.fullName) 15 | I.waitForElement(this.page.locators.phoneInput, 30) 16 | I.fillField(this.page.locators.phoneInput, profile.phone) 17 | I.waitForElement(this.page.locators.updateGeneralButton, 30) 18 | I.click(this.page.locators.updateGeneralButton) 19 | I.waitForText(this.page.locators.messageSuccess, 30) 20 | I.seeInField(this.page.locators.fullNameInput, profile.fullName) 21 | I.seeInField(this.page.locators.phoneInput, profile.phone) 22 | } 23 | 24 | updatePassword(profile) { 25 | I.amOnPage(this.page.locators.urlProfile) 26 | I.waitForElement(this.page.locators.passwordSection, 30) 27 | I.scrollTo(this.page.locators.passwordSection) 28 | I.waitForText(this.page.locators.passwordText, 30) 29 | I.waitForElement(this.page.locators.currentPasswordInput, 30) 30 | I.fillField(this.page.locators.currentPasswordInput, profile.currentPassword) 31 | I.waitForElement(this.page.locators.newPasswordInput, 30) 32 | I.fillField(this.page.locators.newPasswordInput, profile.newPassword) 33 | I.waitForElement(this.page.locators.confirmNewPasswordInput, 30) 34 | I.fillField(this.page.locators.confirmNewPasswordInput, profile.newPassword) 35 | I.waitForElement(this.page.locators.updatePasswordButton, 30) 36 | I.click(this.page.locators.updatePasswordButton) 37 | I.waitForText(this.page.locators.welcomeText, 30) 38 | } 39 | } 40 | export default ProfileStep 41 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/word.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/file_default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/containers/Homepage/HomeUtils/HomeUtils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import { DAM_ASSETS_FIELD_KEY } from 'aesirx-lib'; 7 | 8 | // import HomeModel from '../HomeModel/HomeModel'; 9 | 10 | class HomeUtils { 11 | transformPersonaResponseIntoModel = (response) => { 12 | return response; 13 | }; 14 | 15 | checkFileTypeFormData = (data) => { 16 | switch (data[DAM_ASSETS_FIELD_KEY.FILE_EXTENTION]) { 17 | case 'xlsx': 18 | return '/assets/images/xlsx.svg'; 19 | case 'docx': 20 | return '/assets/images/word.svg'; 21 | case 'pptx': 22 | return '/assets/images/pptx.svg'; 23 | case 'pdf': 24 | return '/assets/images/pdf.svg'; 25 | default: 26 | return '/assets/images/file_default.svg'; 27 | } 28 | }; 29 | 30 | convertImageEditortoFile = (damEditdata, formPropsData, editorRef) => { 31 | if (damEditdata?.[DAM_ASSETS_FIELD_KEY.TYPE] === 'image') { 32 | const editorInstance = editorRef.current.getInstance(); 33 | 34 | formPropsData[DAM_ASSETS_FIELD_KEY.FILE] = this.dataURLtoFile( 35 | editorInstance.toDataURL({ format: damEditdata?.[DAM_ASSETS_FIELD_KEY.FILE_EXTENTION] }), 36 | damEditdata?.[DAM_ASSETS_FIELD_KEY.NAME] 37 | ); 38 | } 39 | 40 | return formPropsData; 41 | }; 42 | 43 | dataURLtoFile(dataurl, filename) { 44 | var arr = dataurl.split(','), 45 | mime = arr[0].match(/:(.*?);/)[1], 46 | bstr = atob(arr[arr.length - 1]), 47 | n = bstr.length, 48 | u8arr = new Uint8Array(n); 49 | while (n--) { 50 | u8arr[n] = bstr.charCodeAt(n); 51 | } 52 | return new File([u8arr], filename, { type: mime }); 53 | } 54 | } 55 | 56 | const utils = new HomeUtils(); 57 | 58 | export default utils; 59 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 24 | AesirX - Digital Asset Management as a Service (DAMaaS) 25 | 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Word.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Word = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 17 | 21 | 25 | 26 | ); 27 | }; 28 | 29 | export default Word; 30 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/EddingIcon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Edding = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default Edding; 33 | -------------------------------------------------------------------------------- /tests/Collection/Page/CollectionPage.js: -------------------------------------------------------------------------------- 1 | class CollectionPage { 2 | locators = { 3 | urlRoot: 'root', 4 | h2Text: 'Your digital Assets', 5 | searchInput: '//input[@placeholder="Search all content"]', 6 | uploadFileButton: '.btn-success', 7 | createFolderButton: '.btn-outline-gray-300', 8 | uploadFileSpan: "//span[contains(text(),'Upload File')]", 9 | createFolderSpan: "//span[contains(text(),'Create Folder')]", 10 | myAssetSpan: "//span[contains(text(),'My Assets')]", 11 | settingSpan: "//span[contains(text(),'Setting')]", 12 | backSpan: "//span[contains(text(),'Back')]", 13 | previewSpan: "//span[contains(text(),'Preview')]", 14 | moveToFolderSpan: "//span[contains(text(),'Move to folder')]", 15 | downloadFolderSpan: "//span[contains(text(),'Download Folder')]", 16 | deleteSpan: "//span[contains(text(),'Delete')]", 17 | deleteModal: "//div[@class='modal-content bg-white shadow']", 18 | deleteMessage: 'Are you sure you want to delete this folder (including children and assets) ?', 19 | deleteAssetMessage: 'Are you sure you want to delete this asset ?', 20 | yesDeleteSpan: "//span[contains(text(),'Yes, Delete')]", 21 | nameInput: "//input[@id='name']", 22 | deleteButton: "//button//span[contains(text(),'Delete')]", 23 | createButton: "//span[contains(text(),'Create')]", 24 | saveButton: "//span[contains(text(),'Save')]", 25 | cancelButton: "//button//span[contains(text(),'Cancel')]", 26 | foldersText: "//p[contains(text(),'FOLDERS')]", 27 | listButton: "//span[contains(text(),'List')]", 28 | thumbButton: "//span[contains(text(),'Thumb')]", 29 | typeSelect: "//div[contains(text(),'Type')]", 30 | sortBySelect: "//div[contains(text(),'Sort By')]", 31 | messageSuccess: 'Success', 32 | closeMessageSuccess: ".Toastify__close-button", 33 | newFolderTitleXpath: '//div[@role="row"]//span[contains(text(),\'New Folder\')]', 34 | xpathCollectionFirst: "(//div[@type='folder'])[1]", 35 | xpathAssetFirst: "(//div[@type='assets'])[1]", 36 | inputFile: "(//input[@type = 'file'])[1]", 37 | } 38 | } 39 | export default CollectionPage 40 | -------------------------------------------------------------------------------- /tests/Setting/Step/SettingStep.js: -------------------------------------------------------------------------------- 1 | import SettingPage from '../Page/SettingPage' 2 | 3 | const { I } = inject() 4 | 5 | class SettingStep { 6 | constructor() { 7 | this.page = new SettingPage() 8 | } 9 | 10 | settingStorageDefault() { 11 | I.amOnPage(this.page.locators.urlSetting) 12 | I.waitForText(this.page.locators.configurationStorageText, 30) 13 | I.waitForText(this.page.locators.storageLabel, 30) 14 | I.waitForElement(this.page.locators.storageSelect, 30) 15 | I.click(this.page.locators.storageSelect) 16 | I.wait(1) 17 | I.waitForVisible(this.page.locators.storageInput) 18 | I.fillField(this.page.locators.storageInput, 'AesirX') 19 | I.pressKey('Enter') 20 | I.waitForVisible(this.page.locators.saveSettingButton) 21 | I.click(this.page.locators.saveSettingButton) 22 | I.waitForText(this.page.locators.saveSuccessMessage, 30) 23 | } 24 | 25 | settingStorageAWS(storeAWS) { 26 | I.amOnPage(this.page.locators.urlSetting) 27 | I.waitForText(this.page.locators.configurationStorageText, 30) 28 | I.waitForText(this.page.locators.storageLabel, 30) 29 | I.wait(1) 30 | I.waitForElement(this.page.locators.storageSelect, 30) 31 | I.click(this.page.locators.storageSelect) 32 | I.wait(1) 33 | I.waitForVisible(this.page.locators.storageInput) 34 | I.fillField(this.page.locators.storageInput, storeAWS.name) 35 | I.pressKey('Enter') 36 | I.waitForElement(this.page.locators.clientIdInput, 30) 37 | I.fillField(this.page.locators.clientIdInput, storeAWS.key) 38 | I.waitForElement(this.page.locators.clientIdInput, 30) 39 | I.fillField(this.page.locators.secretInput, storeAWS.secret) 40 | I.waitForElement(this.page.locators.regionInput, 30) 41 | I.fillField(this.page.locators.regionInput, storeAWS.region) 42 | I.waitForElement(this.page.locators.bucketInput, 30) 43 | I.fillField(this.page.locators.bucketInput, storeAWS.bucket) 44 | I.waitForVisible(this.page.locators.saveSettingButton) 45 | I.click(this.page.locators.saveSettingButton) 46 | I.waitForText(this.page.locators.saveSuccessMessage, 30) 47 | } 48 | } 49 | export default SettingStep 50 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/xlsx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/Asset/Step/AssetSteps.js: -------------------------------------------------------------------------------- 1 | import CollectionPage from '../../Collection/Page/CollectionPage' 2 | 3 | const { I } = inject() 4 | 5 | class AssetSteps { 6 | constructor() { 7 | this.page = new CollectionPage() 8 | } 9 | 10 | createAsset(asset) { 11 | I.amOnPage(this.page.locators.urlRoot) 12 | I.waitForText(this.page.locators.h2Text, 30) 13 | I.waitForElement(this.page.locators.inputFile, 30) 14 | I.attachFile(this.page.locators.inputFile, asset.file) 15 | I.waitForText(this.page.locators.messageSuccess, 30) 16 | I.waitForText(asset.name, 30) 17 | } 18 | 19 | searchAsset(assetName) { 20 | I.amOnPage(this.page.locators.urlRoot) 21 | I.waitForText(this.page.locators.h2Text, 30) 22 | I.waitForElement(this.page.locators.searchInput) 23 | I.fillField(this.page.locators.searchInput, assetName) 24 | I.wait(3) 25 | I.pressKey('Enter') 26 | I.waitForText(assetName, 30, this.page.locators.xpathAssetFirst) 27 | } 28 | 29 | updateName(asset, assetUpdate) { 30 | this.searchAsset(asset.name) 31 | I.waitForElement(this.page.locators.xpathAssetFirst, 30) 32 | I.rightClick(this.page.locators.xpathAssetFirst) 33 | I.waitForElement(this.page.locators.previewSpan) 34 | I.click(this.page.locators.previewSpan) 35 | I.waitForElement(this.page.locators.nameInput) 36 | I.fillField(this.page.locators.nameInput, assetUpdate.name) 37 | I.waitForElement(this.page.locators.saveButton) 38 | I.click(this.page.locators.saveButton) 39 | I.waitForText(this.page.locators.messageSuccess, 30) 40 | I.waitForText(assetUpdate.name, 30, this.page.locators.xpathAssetFirst) 41 | } 42 | 43 | deleteAsset(asset) { 44 | this.searchAsset(asset.name) 45 | I.waitForElement(this.page.locators.xpathAssetFirst, 30) 46 | I.rightClick(this.page.locators.xpathAssetFirst) 47 | I.waitForElement(this.page.locators.deleteSpan) 48 | I.click(this.page.locators.deleteSpan) 49 | I.waitForText(this.page.locators.deleteAssetMessage, 30) 50 | I.waitForElement(this.page.locators.yesDeleteSpan) 51 | I.click(this.page.locators.yesDeleteSpan) 52 | I.waitForText(this.page.locators.messageSuccess, 30) 53 | I.dontSee(asset.name) 54 | } 55 | } 56 | export default AssetSteps 57 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/containers/Homepage/index.module.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | .item_collap_fixed { 7 | left: 250px; 8 | } 9 | 10 | .wrapper_new_schedule { 11 | top: 10px; 12 | right: 1.5rem; 13 | } 14 | 15 | .full_calender { 16 | .pe-400 { 17 | padding-right: 1rem !important; 18 | } 19 | 20 | .sdbar_right { 21 | display: none; 22 | } 23 | } 24 | .folder { 25 | margin-bottom: 32px; 26 | } 27 | 28 | .image { 29 | height: 212px; 30 | overflow: hidden; 31 | width: 100%; 32 | } 33 | .image_isList { 34 | width: 56px; 35 | height: 56px; 36 | } 37 | .popupImageHeight { 38 | height: calc(100% - 50px); 39 | } 40 | 41 | .txt_hover { 42 | &:hover { 43 | span { 44 | color: var(--bs-success); 45 | } 46 | svg { 47 | fill: var(--bs-success); 48 | path { 49 | fill: var(--bs-success); 50 | } 51 | } 52 | } 53 | } 54 | 55 | .input { 56 | border: 2px solid transparent; 57 | &::-moz-selection { 58 | /* Code for Firefox */ 59 | color: var(--bs-white); 60 | background: var(--bs-green); 61 | transition: 0.3s all ease-in-out; 62 | } 63 | &::selection { 64 | color: var(--bs-white); 65 | background: var(--bs-green); 66 | transition: 0.3s all ease-in-out; 67 | } 68 | &:focus { 69 | transition: 0.3s all ease-in-out; 70 | border-radius: 3px; 71 | // border: 2px solid #2828314d; 72 | box-shadow: unset; 73 | } 74 | } 75 | .checkbox { 76 | width: 16px; 77 | height: 16px; 78 | margin: 0 auto; 79 | input { 80 | width: 100%; 81 | height: 100%; 82 | } 83 | } 84 | 85 | .contextMenuItem { 86 | min-width: 248px; 87 | div:not(:last-child) { 88 | &:hover { 89 | span { 90 | font-weight: 600; 91 | color: var(--aesirxui-green) !important; 92 | } 93 | } 94 | } 95 | div:last-child { 96 | &:hover { 97 | span { 98 | font-weight: 600; 99 | } 100 | } 101 | } 102 | } 103 | .items_file{ 104 | display: flex !important; 105 | } 106 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/setting.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/File.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const File = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 26 | 30 | 31 | ); 32 | }; 33 | 34 | export default File; 35 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'release' 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | ref: master 17 | 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: 16 21 | 22 | - run: git submodule update --init --recursive 23 | 24 | - name: Docker meta 25 | id: meta 26 | uses: docker/metadata-action@v5 27 | with: 28 | # list of Docker images to use as base name for tags 29 | images: | 30 | aesirxio/dam-app 31 | # generate Docker tags based on the following events/attributes 32 | tags: | 33 | type=schedule 34 | type=ref,event=branch 35 | type=ref,event=pr 36 | type=semver,pattern={{version}} 37 | type=semver,pattern={{major}}.{{minor}} 38 | type=semver,pattern={{major}} 39 | type=sha 40 | 41 | - name: Set up QEMU 42 | uses: docker/setup-qemu-action@v3 43 | 44 | - name: Set up Docker Buildx 45 | uses: docker/setup-buildx-action@v3 46 | 47 | - name: Login to Docker Hub 48 | if: github.event_name != 'pull_request' 49 | uses: docker/login-action@v3 50 | with: 51 | username: ${{ secrets.DOCKERHUB_USERNAME }} 52 | password: ${{ secrets.DOCKERHUB_TOKEN }} 53 | 54 | - name: Build and push 55 | uses: docker/build-push-action@v5 56 | with: 57 | context: . 58 | platforms: linux/amd64,linux/arm64 59 | push: ${{ github.event_name != 'pull_request' }} 60 | tags: ${{ steps.meta.outputs.tags }} 61 | labels: ${{ steps.meta.outputs.labels }} 62 | 63 | - run: yarn install 64 | - run: yarn lint:check 65 | - run: CI=false yarn build 66 | - uses: JS-DevTools/npm-publish@v2 67 | with: 68 | token: ${{ secrets.NPM_TOKEN }} 69 | strategy: upgrade 70 | ignore-scripts: false 71 | package: ./packages/aesirx-dam-app 72 | 73 | - name: Release note 74 | uses: ncipollo/release-action@v1 75 | with: 76 | generateReleaseNotes: true 77 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/collection_transfer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | ## Deps 3 | FROM node:16-alpine AS deps 4 | WORKDIR /app 5 | 6 | COPY nx.json . 7 | COPY package.json . 8 | COPY yarn.lock . 9 | 10 | COPY ./packages/aesirx-dam-app ./packages/aesirx-dam-app 11 | COPY ./packages/aesirx-lib ./packages/aesirx-lib 12 | COPY ./packages/aesirx-uikit ./packages/aesirx-uikit 13 | COPY ./packages/aesirx-sso ./packages/aesirx-sso 14 | 15 | RUN apk add --update --no-cache \ 16 | make \ 17 | g++ \ 18 | jpeg-dev \ 19 | cairo-dev \ 20 | giflib-dev \ 21 | pango-dev \ 22 | libtool \ 23 | autoconf \ 24 | automake \ 25 | py3-pip 26 | 27 | RUN yarn install --frozen-lockfile --network-timeout 600000 28 | 29 | ## Builder 30 | FROM node:16-alpine AS builder 31 | WORKDIR /app 32 | 33 | RUN apk add --no-cache git 34 | 35 | # Cache and Install dependencies 36 | COPY --from=deps ./app/node_modules ./node_modules 37 | COPY --from=deps ./app/packages/aesirx-dam-app/dist ./packages/aesirx-dam-app/dist 38 | COPY --from=deps ./app/packages/aesirx-lib/dist ./packages/aesirx-lib/dist 39 | COPY --from=deps ./app/packages/aesirx-uikit/dist ./packages/aesirx-uikit/dist 40 | COPY --from=deps ./app/packages/aesirx-sso/build ./packages/aesirx-sso/build 41 | 42 | # Copy app files 43 | COPY ./.git ./ 44 | COPY ./nx.json ./ 45 | COPY ./package.json ./ 46 | 47 | COPY ./packages/aesirx-lib/package.json ./packages/aesirx-lib/package.json 48 | COPY ./packages/aesirx-uikit/package.json ./packages/aesirx-uikit/package.json 49 | COPY ./packages/aesirx-sso/package.json ./packages/aesirx-sso/package.json 50 | 51 | COPY ./packages/aesirx-dam-app/package.json ./packages/aesirx-dam-app/ 52 | COPY ./packages/aesirx-dam-app/craco.config.js ./packages/aesirx-dam-app/ 53 | COPY ./packages/aesirx-dam-app/jsconfig.json ./packages/aesirx-dam-app/ 54 | COPY ./packages/aesirx-dam-app/.eslintrc ./packages/aesirx-dam-app/ 55 | COPY ./packages/aesirx-dam-app/public ./packages/aesirx-dam-app/public 56 | COPY ./packages/aesirx-dam-app/src ./packages/aesirx-dam-app/src 57 | 58 | # Build the app 59 | RUN yarn build 60 | 61 | # Bundle static assets 62 | FROM node:16-alpine AS production 63 | WORKDIR /app 64 | 65 | # Copy built assets from builder 66 | COPY --from=builder ./app/packages/aesirx-dam-app/build ./build 67 | 68 | RUN yarn add serve react-inject-env 69 | 70 | # Expose port 71 | EXPOSE 3000 72 | 73 | ENTRYPOINT npx react-inject-env set && npx serve -s build 74 | 75 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Dropzone/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | import { useState } from 'react'; 8 | import { useDropzone } from 'react-dropzone'; 9 | import styles from './index.module.scss'; 10 | import { useTranslation } from 'react-i18next'; 11 | import CloudUpload from 'svg/CloudUpload'; 12 | 13 | const Dropzone = ({ 14 | children, 15 | noClick, 16 | createAssets, 17 | className, 18 | isBtn = true, 19 | noDrag = true, 20 | accept = '*', 21 | }) => { 22 | const [onDrag, setOnDrag] = useState(false); 23 | const { t } = useTranslation(); 24 | const { getRootProps, getInputProps } = useDropzone({ 25 | accept: accept, 26 | noClick: noClick, 27 | noDrag: noDrag, 28 | // maxFiles: 1, 29 | multiple: true, 30 | onDragEnter: () => { 31 | setOnDrag(true); 32 | }, 33 | onDragLeave: () => { 34 | setOnDrag(false); 35 | }, 36 | onDrop: (acceptedFiles) => { 37 | setOnDrag(false); 38 | createAssets(acceptedFiles); 39 | }, 40 | }); 41 | 42 | return ( 43 |
52 |
53 | 54 |
55 | 59 | 60 | {children} 61 |
62 | {onDrag ? ( 63 |
66 | 67 | 70 |
71 | ) : null} 72 |
73 |
74 | ); 75 | }; 76 | 77 | export default Dropzone; 78 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Xlsx.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Xlsx = ({ fill = 'none', ...props }) => { 4 | return ( 5 | 13 | 19 | 26 | 30 | 31 | ); 32 | }; 33 | 34 | export default Xlsx; 35 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/containers/Homepage/HomeForm/CollectionName.jsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import { DAM_COLLECTION_FIELD_KEY } from 'aesirx-lib'; 4 | import { useDamViewModel } from 'store/DamStore/DamViewModelContextProvider'; 5 | import { DAM_COLUMN_INDICATOR } from 'constants/DamConstant'; 6 | import { Form } from 'react-bootstrap'; 7 | import styles from '../index.module.scss'; 8 | import { notify } from 'aesirx-uikit'; 9 | import { useTranslation } from 'react-i18next'; 10 | const CollectionName = observer(({ item }) => { 11 | const { damListViewModel, damFormViewModel } = useDamViewModel(); 12 | const [value, setValue] = useState(item[DAM_COLUMN_INDICATOR.NAME]); 13 | const [isFocus, setIsFocus] = useState(false); 14 | const { t } = useTranslation(); 15 | 16 | const handleUpdateFolder = useCallback(() => { 17 | if (value) { 18 | if (item?.create) { 19 | damListViewModel.createCollections( 20 | { 21 | ...item, 22 | [DAM_COLLECTION_FIELD_KEY.NAME]: value, 23 | }, 24 | 'server' 25 | ); 26 | } else { 27 | if (value !== item[DAM_COLUMN_INDICATOR.NAME]) { 28 | damListViewModel.updateCollections({ 29 | ...item, 30 | [DAM_COLLECTION_FIELD_KEY.NAME]: value, 31 | }); 32 | } else { 33 | setValue(item[DAM_COLUMN_INDICATOR.NAME]); 34 | } 35 | } 36 | } else { 37 | notify(t('txt_name_can_not_blank'), 'warn'); 38 | } 39 | damFormViewModel.setOffEditCollection(); 40 | }, [value]); 41 | 42 | return ( 43 | setValue(e.target.value)} 55 | onFocus={(e) => { 56 | e.target.select(); 57 | setIsFocus(true); 58 | }} 59 | onBlur={() => { 60 | if (isFocus) { 61 | handleUpdateFolder(); 62 | setIsFocus(false); 63 | } 64 | }} 65 | onKeyDown={(e) => { 66 | if (e.keyCode === 13) { 67 | e.target.blur(); 68 | } 69 | }} 70 | /> 71 | ); 72 | }); 73 | 74 | export default CollectionName; 75 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Menu/index.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | .dam-integrate-layout { 7 | .caret-toggle { 8 | left: 0; 9 | cursor: s-resize; 10 | &.index { 11 | right: 10px; 12 | left: unset; 13 | } 14 | &.down { 15 | transform: translate(-50%, -50%) rotate(90deg) !important; 16 | cursor: n-resize; 17 | } 18 | } 19 | .item_menu { 20 | .link_menu { 21 | transition: color 0.2s ease-in-out; 22 | white-space: nowrap; 23 | font-size: 1.1rem; 24 | 25 | &.active { 26 | color: var(--bs-green) !important; 27 | font-weight: 600; 28 | } 29 | &:hover { 30 | color: var(--bs-green) !important; 31 | } 32 | 33 | i, 34 | span { 35 | transition: color 0.2s ease-in-out; 36 | } 37 | 38 | .icon { 39 | width: 24px; 40 | height: 24px; 41 | background-color: var(--bs-white); 42 | } 43 | } 44 | } 45 | .wr_list_menu { 46 | .item_menu { 47 | &:first-child { 48 | .link_menu { 49 | background-color: transparent !important; 50 | box-shadow: none; 51 | 52 | i, 53 | span { 54 | color: var(--bs-blue) !important; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | .section_menu_title, 62 | .header_logo { 63 | transition: all 0.3s ease; 64 | } 65 | .show { 66 | .btn-success.dropdown-toggle { 67 | &:focus { 68 | box-shadow: none; 69 | } 70 | } 71 | } 72 | 73 | .main-menu { 74 | max-height: 300px; 75 | overflow-y: auto; 76 | &::-webkit-scrollbar { 77 | width: 5px; 78 | height: 5px; 79 | background-color: rgba($color: #fff, $alpha: 0.2); 80 | } 81 | &::-webkit-scrollbar-thumb { 82 | -webkit-box-shadow: inset 0 0 6px transparent; 83 | border-radius: 5px; 84 | background-color: rgba($color: #fff, $alpha: 0.5); 85 | box-shadow: inset 0 0 6px transparent; 86 | } 87 | &::-webkit-scrollbar-track { 88 | -webkit-box-shadow: inset 0 0 6px transparent; 89 | background-color: transparent; 90 | box-shadow: inset 0 0 6px transparent; 91 | } 92 | } 93 | body.mini_left { 94 | .sidebar { 95 | .button-language { 96 | bottom: 2.25rem !important; 97 | padding-bottom: 1rem !important; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/assets/images/help-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/CloudUpload.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const CloudUpload = (props) => { 4 | return ( 5 | 14 | 15 | 21 | 22 | ); 23 | }; 24 | 25 | export default CloudUpload; 26 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/ThemeMode.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ThemeMode = ({ fill = 'none', onClick, ...props }) => { 4 | return ( 5 | 14 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 46 | 50 | 51 | ); 52 | }; 53 | 54 | export default ThemeMode; 55 | -------------------------------------------------------------------------------- /tests/Collection/Step/CollectionStep.js: -------------------------------------------------------------------------------- 1 | import CollectionPage from '../Page/CollectionPage' 2 | 3 | const { I } = inject() 4 | 5 | class CollectionStep { 6 | constructor() { 7 | this.page = new CollectionPage() 8 | } 9 | 10 | createCollection(collectionName) { 11 | I.amOnPage(this.page.locators.urlRoot) 12 | I.waitForText(this.page.locators.h2Text, 30) 13 | I.waitForElement(this.page.locators.createFolderButton, 30) 14 | I.click(this.page.locators.createFolderButton) 15 | I.waitForElement(this.page.locators.nameInput, 30) 16 | I.fillField(this.page.locators.nameInput, collectionName) 17 | I.waitForElement(this.page.locators.createButton) 18 | I.click(this.page.locators.createButton) 19 | I.waitForText(this.page.locators.messageSuccess, 30) 20 | I.waitForElement(this.page.locators.closeMessageSuccess, 30) 21 | I.click(this.page.locators.closeMessageSuccess) 22 | I.waitForText(collectionName, 30) 23 | } 24 | 25 | searchCollection(collectionName) { 26 | I.amOnPage(this.page.locators.urlRoot) 27 | I.waitForText(this.page.locators.h2Text, 30) 28 | I.waitForElement(this.page.locators.searchInput) 29 | I.fillField(this.page.locators.searchInput, collectionName) 30 | I.pressKey('Enter') 31 | I.waitForText(collectionName, 30, this.page.locators.xpathCollectionFirst) 32 | } 33 | 34 | updateCollectionName(collectionName, collectionNameUpdate) { 35 | I.waitForText(collectionName, 30, this.page.locators.xpathCollectionFirst) 36 | I.waitForElement(this.page.locators.xpathCollectionFirst, 30) 37 | I.rightClick(this.page.locators.xpathCollectionFirst) 38 | I.waitForElement(this.page.locators.previewSpan) 39 | I.click(this.page.locators.previewSpan) 40 | I.waitForElement(this.page.locators.nameInput) 41 | I.fillField(this.page.locators.nameInput, collectionNameUpdate) 42 | I.waitForElement(this.page.locators.saveButton) 43 | I.click(this.page.locators.saveButton) 44 | I.waitForText(this.page.locators.messageSuccess, 30) 45 | I.waitForElement(this.page.locators.closeMessageSuccess, 30) 46 | I.click(this.page.locators.closeMessageSuccess) 47 | I.waitForText(collectionNameUpdate, 30, this.page.locators.xpathCollectionFirst) 48 | } 49 | 50 | deleteCollection(collectionName) { 51 | I.waitForText(collectionName, 30, this.page.locators.xpathCollectionFirst) 52 | I.waitForElement(this.page.locators.xpathCollectionFirst, 30) 53 | I.rightClick(this.page.locators.xpathCollectionFirst) 54 | I.waitForElement(this.page.locators.deleteSpan) 55 | I.click(this.page.locators.deleteSpan) 56 | I.waitForVisible(this.page.locators.deleteModal, 30) 57 | I.waitForText(this.page.locators.deleteMessage, 30) 58 | I.waitForElement(this.page.locators.yesDeleteSpan, 30) 59 | I.click(this.page.locators.yesDeleteSpan) 60 | I.waitForText(this.page.locators.messageSuccess, 30) 61 | I.waitForElement(this.page.locators.closeMessageSuccess, 30) 62 | I.click(this.page.locators.closeMessageSuccess) 63 | I.dontSee(collectionName) 64 | } 65 | } 66 | export default CollectionStep 67 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Search/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | import { AsyncTypeahead } from 'react-bootstrap-typeahead'; 5 | import { useState } from 'react'; 6 | import { useDamViewModel } from 'store/DamStore/DamViewModelContextProvider'; 7 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 8 | import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch'; 9 | import { observer } from 'mobx-react'; 10 | import styles from './index.module.scss'; 11 | const Search = observer(() => { 12 | const damListViewModel = useDamViewModel(); 13 | const { t } = useTranslation(); 14 | 15 | const [isLoading, setIsLoading] = useState(false); 16 | const [options, setOptions] = useState([]); 17 | 18 | const handleSearch = async (query) => { 19 | setIsLoading(true); 20 | 21 | try { 22 | const items = await damListViewModel.damListViewModel.damStore.search(query); 23 | setOptions(items); 24 | setIsLoading(false); 25 | } catch (error) { 26 | setIsLoading(false); 27 | } 28 | }; 29 | 30 | const handleChange = (data) => { 31 | damListViewModel.damFormViewModel.damEditdata = data[0]; 32 | damListViewModel.damFormViewModel.openModal(); 33 | }; 34 | 35 | const handleKeyDown = (e) => { 36 | if (e.keyCode === 13) { 37 | damListViewModel.damListViewModel.isSearch = true; 38 | const assets = options.filter((asset) => asset.type); 39 | const collections = options.filter((collection) => !collection.type); 40 | if (assets) { 41 | damListViewModel.damListViewModel.assets = assets; 42 | } 43 | 44 | if (collections) { 45 | damListViewModel.damListViewModel.collections = collections; 46 | } 47 | } 48 | }; 49 | // Bypass client-side filtering by returning `true`. Results are already 50 | // filtered by the search endpoint, so no need to do it again. 51 | const filterBy = () => true; 52 | 53 | return ( 54 |
57 | 64 | 65 | ( 81 | <> 82 | {option.name} 83 | 84 | )} 85 | /> 86 |
87 | ); 88 | }); 89 | 90 | export default Search; 91 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/svg/Warn.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Warn = (props) => { 4 | return ( 5 | 13 | 17 | 21 | 25 | 29 | 33 | 37 | 38 | ); 39 | }; 40 | 41 | export default Warn; 42 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/Menu2/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import React from 'react'; 7 | import { NavLink } from 'react-router-dom'; 8 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 9 | import { withTranslation } from 'react-i18next'; 10 | import { faArrowLeft } from '@fortawesome/free-solid-svg-icons/faArrowLeft'; 11 | import { faUser } from '@fortawesome/free-solid-svg-icons/faUser'; 12 | 13 | class Menu2 extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | language: 'English', 18 | activeMenu: '', 19 | dataMenu: [ 20 | { 21 | title: 'ACCOUNT SETTINGS', 22 | listMenu: [ 23 | { 24 | name: 'profile', 25 | text: 'txt_menu_profile', 26 | link: '/profile', 27 | icons: faUser, 28 | }, 29 | ], 30 | }, 31 | ], 32 | }; 33 | } 34 | 35 | checkActiveMenu = () => {}; 36 | 37 | componentDidMount = () => { 38 | this.checkActiveMenu(); 39 | }; 40 | 41 | handleCheckActive = (name) => { 42 | this.checkActiveMenu(name); 43 | }; 44 | 45 | render() { 46 | let { dataMenu } = this.state; 47 | const { t } = this.props; 48 | 49 | return ( 50 | 91 | ); 92 | } 93 | } 94 | 95 | export default withTranslation()(Menu2); 96 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aesirx-dam-app", 3 | "version": "1.6.1", 4 | "license": "GPL-3.0-only", 5 | "author": "AesirX", 6 | "main": "dist/index.js", 7 | "module": "dist/index.js", 8 | "repository": "https://github.com/aesirxio/dam-app", 9 | "dependencies": { 10 | "@fortawesome/fontawesome-svg-core": "^6.2.0", 11 | "@fortawesome/free-regular-svg-icons": "^6.2.0", 12 | "@fortawesome/free-solid-svg-icons": "^6.4.0", 13 | "@fortawesome/react-fontawesome": "^0.2.0", 14 | "@toast-ui/react-image-editor": "^3.15.2", 15 | "aesirx-lib": "*", 16 | "aesirx-uikit": "*", 17 | "aesirx-sso": "*", 18 | "file-saver": "^2.0.5", 19 | "mobx": "^6.9.0", 20 | "mobx-react": "^7.6.0", 21 | "moment": "^2.29.4", 22 | "react": "^18.2.0", 23 | "react-bootstrap": "^2.7.4", 24 | "react-bootstrap-typeahead": "^6.0.0", 25 | "react-dnd": "^16.0.1", 26 | "react-dnd-html5-backend": "^16.0.1", 27 | "react-dom": "^18.2.0", 28 | "react-dropzone": "^14.2.3", 29 | "react-i18next": "^12.2.0", 30 | "react-router-dom": "^5.2.0", 31 | "react-table": "^7.8.0", 32 | "simple-react-validator": "^1.6.2", 33 | "web-vitals": "^3.3.1" 34 | }, 35 | "scripts": { 36 | "start": "yarn run build && serve -s build", 37 | "build": "craco build && react-inject-env set", 38 | "test": "craco test", 39 | "dev": "craco start", 40 | "lint": "eslint --fix \"src/**/\"", 41 | "lint:check": "eslint \"src/**/\"", 42 | "lint:nowarns": "eslint --quiet \"src/**/\"", 43 | "build:lib": "NODE_ENV=production tsup", 44 | "dev:lib": "NODE_ENV=development tsup --watch", 45 | "prepublishOnly": "yarn build:lib", 46 | "format:check": "prettier --check \"./src/**/*.{js,jsx,ts,tsx}\"", 47 | "format:write": "prettier --write \"./src/**/*.{js,jsx,ts,tsx}\"" 48 | }, 49 | "browserslist": { 50 | "production": [ 51 | ">0.2%", 52 | "not dead", 53 | "not op_mini all" 54 | ], 55 | "development": [ 56 | "last 1 chrome version", 57 | "last 1 firefox version", 58 | "last 1 safari version" 59 | ] 60 | }, 61 | "devDependencies": { 62 | "@babel/core": "^7.19.6", 63 | "@babel/eslint-parser": "^7.18", 64 | "@babel/plugin-proposal-class-properties": "^7.18.6", 65 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11", 66 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 67 | "@babel/plugin-transform-runtime": "^7.21.0", 68 | "@babel/preset-env": "^7.22.4", 69 | "@babel/preset-react": "^7.18.6", 70 | "@craco/craco": "^7.1.0", 71 | "babel-plugin-file-loader": "^2.0.0", 72 | "babel-plugin-inline-react-svg": "^2.0.1", 73 | "babel-plugin-module-resolver": "^5.0.0", 74 | "babel-plugin-react-css-modules": "^5.2.6", 75 | "esbuild-plugin-inline-image": "^0.0.9", 76 | "esbuild-sass-plugin": "^2.8.0", 77 | "esbuild-scss-modules-plugin": "^1.1.1", 78 | "eslint": "^8.17", 79 | "git-revision-webpack-plugin": "^5.0.0", 80 | "prettier": "^2.8.4", 81 | "react-inject-env": "^2.1.0", 82 | "react-scripts": "^5.0.1", 83 | "sass": "^1.52", 84 | "serve": "^14.2.0", 85 | "tsup": "^7.1.0", 86 | "url": "^0.11.0" 87 | }, 88 | "files": [ 89 | "dist" 90 | ], 91 | "resolutions": { 92 | "react": "^18", 93 | "react-dom": "^18", 94 | "react-dnd": "^16" 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/components/ChooseAnAction/index.jsx: -------------------------------------------------------------------------------- 1 | import { faChevronDown } from '@fortawesome/free-solid-svg-icons'; 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 3 | import { observer } from 'mobx-react'; 4 | import React, { useMemo } from 'react'; 5 | import { Dropdown } from 'react-bootstrap'; 6 | import { useTranslation } from 'react-i18next'; 7 | import { useDamViewModel } from 'store/DamStore/DamViewModelContextProvider'; 8 | import styles from './index.module.scss'; 9 | // eslint-disable-next-line react/display-name 10 | const CustomToggle = React.forwardRef(({ onClick }, ref) => { 11 | const { t } = useTranslation(); 12 | 13 | return ( 14 |
{ 17 | e.preventDefault(); 18 | onClick(e); 19 | }} 20 | className="d-flex align-items-center text-decoration-none cursor-pointer choose-an-action justify-content-between w-100 h-100 px-3 mt-n1" 21 | > 22 |
23 |

{t('txt_choose_an_action')}

24 |
25 | 26 | 27 | 28 |
29 | ); 30 | }); 31 | 32 | const ChooseAction = observer(() => { 33 | const { t } = useTranslation(); 34 | const { openDeleteModal, openMoveToFolder, downloadFile } = 35 | useDamViewModel().getDamFormViewModel(); 36 | 37 | const Action = useMemo(() => ({ 38 | id: 'action', 39 | // className: styles.w_272, 40 | className: 41 | 'border-end border-gray-select bg-select-control-background choose-an-action col-auto fs-14 minw-272px', 42 | placeholder: t('txt_choose_an_action'), 43 | options: [ 44 | { 45 | label: t('txt_preview'), 46 | value: t('txt_preview'), 47 | }, 48 | { 49 | label: t('txt_move_to_folder'), 50 | value: t('txt_move_to_folder'), 51 | onSelect: openMoveToFolder, 52 | }, 53 | { 54 | label: t('txt_download'), 55 | value: t('txt_download'), 56 | onSelect: downloadFile, 57 | }, 58 | { 59 | label: t('txt_delete'), 60 | value: t('txt_delete'), 61 | onSelect: openDeleteModal, 62 | }, 63 | ], 64 | })); 65 | return ( 66 |
67 | 68 | 72 | 75 |
    76 | {Action.options.map((value, index) => { 77 | return ( 78 |
  • 79 | 84 | {t(value.label)} 85 | 86 |
  • 87 | ); 88 | })} 89 |
90 |
91 |
92 |
93 | ); 94 | }); 95 | 96 | export default ChooseAction; 97 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/store/DamStore/DamFormViewModel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | * @license GNU General Public License version 3, see LICENSE. 4 | */ 5 | 6 | import { 7 | DAM_ASSETS_API_FIELD_KEY, 8 | DAM_ASSETS_FIELD_KEY, 9 | DAM_COLLECTION_API_RESPONSE_FIELD_KEY, 10 | } from 'aesirx-lib'; 11 | import { notify } from 'aesirx-uikit'; 12 | import PAGE_STATUS from 'constants/PageStatus'; 13 | 14 | import { makeAutoObservable } from 'mobx'; 15 | 16 | class DamFormViewModel { 17 | show = false; 18 | showContextMenuItem = false; 19 | showContextMenu = false; 20 | showDeleteModal = false; 21 | isEditCollection = false; 22 | damEditdata = null; 23 | editMode = null; 24 | damListViewModel = null; 25 | showMoveToFolder = false; 26 | formStatus = PAGE_STATUS.READY; 27 | damStore = null; 28 | 29 | constructor(damStore) { 30 | makeAutoObservable(this); 31 | this.damStore = damStore; 32 | } 33 | 34 | openMoveToFolder = () => { 35 | if (this.damListViewModel.actionState.selectedCards.length) { 36 | this.showMoveToFolder = true; 37 | } else { 38 | notify('please choose item to move', 'warn'); 39 | } 40 | }; 41 | 42 | setDamListViewModel = (damListViewModel) => { 43 | this.damListViewModel = damListViewModel; 44 | }; 45 | 46 | closeMoveToFolder = () => { 47 | this.showMoveToFolder = false; 48 | }; 49 | 50 | openContextMenu = () => { 51 | this.showContextMenu = true; 52 | }; 53 | 54 | closeContextMenu = () => { 55 | this.showContextMenu = false; 56 | }; 57 | 58 | openContextMenuItem = () => { 59 | this.showContextMenuItem = true; 60 | }; 61 | 62 | closeContextMenuItem = () => { 63 | this.showContextMenuItem = false; 64 | }; 65 | 66 | openModal = () => { 67 | this.show = true; 68 | }; 69 | 70 | closeModal = () => { 71 | this.editMode = false; 72 | this.show = false; 73 | }; 74 | 75 | openDeleteModal = () => { 76 | this.showDeleteModal = true; 77 | }; 78 | 79 | closeDeleteModal = () => { 80 | this.showDeleteModal = false; 81 | }; 82 | 83 | setOnEditCollection = () => { 84 | this.isEditCollection = true; 85 | }; 86 | 87 | setOffEditCollection = () => { 88 | this.isEditCollection = false; 89 | }; 90 | 91 | downloadFile = async () => { 92 | if (!this.damListViewModel.actionState.selectedCards.length) { 93 | notify('Please choose one item to download', 'warn'); 94 | return; 95 | } else { 96 | const collectionIds = this.damListViewModel.actionState.selectedCards 97 | .filter((item) => !item?.[DAM_ASSETS_FIELD_KEY.TYPE]) 98 | .map((id) => id[DAM_COLLECTION_API_RESPONSE_FIELD_KEY.ID]); 99 | 100 | const assetIds = this.damListViewModel.actionState.selectedCards 101 | .filter((item) => item?.[DAM_ASSETS_FIELD_KEY.TYPE]) 102 | .map((id) => id[DAM_ASSETS_API_FIELD_KEY.ID]); 103 | if (collectionIds || assetIds) { 104 | notify( 105 | this.damStore.downloadCollections({ 106 | [DAM_COLLECTION_API_RESPONSE_FIELD_KEY.ASSETSIDS]: assetIds, 107 | [DAM_COLLECTION_API_RESPONSE_FIELD_KEY.COLLECTIONIDS]: collectionIds, 108 | }), 109 | 'promise' 110 | ); 111 | } 112 | } 113 | 114 | this.closeContextMenuItem(); 115 | }; 116 | 117 | callbackOnErrorHander = (data) => { 118 | notify(data.message, 'error'); 119 | }; 120 | 121 | callbackOnSuccessHandler = (data) => { 122 | if (data) { 123 | this.damListViewModel.assets = this.damListViewModel.assets.filter((asset) => { 124 | return asset.id !== data.id; 125 | }); 126 | } 127 | }; 128 | } 129 | 130 | export default DamFormViewModel; 131 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/translations/tr/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "txt_digital_asset_management": "Dijital Varlık Yönetimi", 3 | "txt_digital_assets": "Dijital Varlık", 4 | "txt_publish": "Yayınla", 5 | "txt_when_to_publish_this?": "Bu ne zaman yayınlanacak ?", 6 | "txt_save_as_draft": "Taslak olarak kaydet", 7 | "txt_choose_file": "Dosya Seçin", 8 | 9 | "txt_project": "Proje", 10 | "txt_post_now": "Şimdi Gönder", 11 | "txt_schedule": "Takvim", 12 | "txt_publish_date/time": "Yayınlama Zamanı", 13 | "txt_search_all_content": "Tüm içeriklerde ara", 14 | "txt_your_digital_assets": "Dijital Varıklarınız", 15 | "txt_name": "Ad", 16 | "txt_size": "Beden", 17 | "txt_owner": "Sahibi", 18 | "txt_last_modified": "Son Düzenleme", 19 | "txt_image": "Foto", 20 | "txt_document": "Doküman", 21 | "txt_audio": "Ses", 22 | "txt_preview": "Önizleme", 23 | "txt_move_to_folder": "Klasöre taşı", 24 | "txt_download": "İndir", 25 | "txt_delete": "Sil", 26 | "txt_sort_by": "Göre Sırala", 27 | "txt_date_create": "Oluşturma Tarihi", 28 | "txt_a_z": "A - Z", 29 | "txt_z_a": "Z - A", 30 | "txt_menu_member": "Üyeler", 31 | "txt_menu_import_export": "İçeri Al/Dışa Aktar", 32 | "txt_menu_colection_transfer": "Kolleksiyon Transferi", 33 | "txt_menu_setting": "Ayarlar", 34 | "txt_menu_trash": "Çöp utusu", 35 | "txt_title_profile_setting": "Profil Ayarları", 36 | "txt_title_set_information_name": "Adınızı ve halka açık diğer bilgileri ayarlayın", 37 | "txt_cancel": "İptal", 38 | "txt_your_avatar": "Avatarınız", 39 | "txt_upload_file": "Dosya yükle", 40 | "txt_create_folder": "Klasör oluştur", 41 | "txt_set_up": "Ayar", 42 | "txt_my_assets": "Varlıklarım", 43 | "txt_download_folder": "İndir", 44 | "txt_delete_folder": "Klasör sil", 45 | "txt_are_you_sure": "Emin misiniz?", 46 | "txt_delete_popup_desc": "Lorem ipsum dolor sit amet, consectetur adipiscing", 47 | "txt_Cancel": "İptal", 48 | "txt_yes_delete": "Evet, Sil", 49 | "txt_file": "DOSYALAR", 50 | "txt_storage": "Depolama", 51 | "txt_upgrade": "Güncelle", 52 | "txt_configuration_storage": "Depolama Ayarları", 53 | "txt_configuration_desc": "Aşağıda listelenen boyut, Ortam Kitaplığına bir görüntü eklerken kullanılacak piksel cinsinden maksimum boyutu belirler.", 54 | "txt_save_setting": "Ayarları kaydet", 55 | "txt_client_id": "Üye ID", 56 | "txt_client_secret": "Üye Gizli Kelime", 57 | "txt_region": "Bölge", 58 | "txt_bucket": "Bütçe", 59 | "txt_drop_files_anywhere_to_upload": "Yüklemek için dosyayı herhangi bir yere sürükleyin", 60 | "txt_or": "veya", 61 | "txt_select_file": "Dosya seç", 62 | "txt_save_update": "Kaydet", 63 | "txt_delete_assets_popup_desc": "Bu varlığı silmek istediğinizden emin misiniz ?", 64 | "txt_delete_collections_popup_desc": "Klasörü ve içerdiği herşeyi silmek istediğinizden emin misiniz ?", 65 | "tx_forgot_password": "Şifrenizi mi unuttunuz?", 66 | "txt_file_size": "Beden", 67 | "txt_url": "URL", 68 | "txt_file_type": "Dosya Türü", 69 | "txt_sign_in_to_getting_started": "Başlamak için Oturum Açın.", 70 | "txt_folders": "KLASÖRLER", 71 | "txt_of": "dan", 72 | "txt_used": "kullanıldı", 73 | "txt_new_folder": "Yeni Klasör", 74 | "txt_create": "Oluştur", 75 | "txt_rename": "Yeniden adlandır", 76 | "txt_can_not_move": "Taşınamaz", 77 | "txt_move_with_file_or_folder": "{{type}} {{name}}, {{name_folder}} klasörüne taşınmıştı", 78 | "txt_drop_to_upload": "Yüklemek için sürükleyin", 79 | "txt_digital_assets_media": "Dijital Varlık Medyaları", 80 | "txt_remember_me": "Beni Hatırla", 81 | "txt_by": "tarafından", 82 | "txt_max_file_size": "Max dosya boyutu: 2 MB (İzin verilen uzantılar: jpg, jpeg, gif, png)", 83 | "txt_item_already_in_this_folder": "Nesne zaten klasörde", 84 | "txt_can_not_move_to_itself": "Kendi üstüne taşınamaz", 85 | "txt_name_can_not_blank": "Kalsör adı boş olamaz!", 86 | "txt_click_to_change_image": "Foto değiştirmek için tıklayın" 87 | } 88 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/src/translations/th/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "txt_digital_asset_management": "การจัดการสินทรัพย์ดิจิทัล", 3 | "txt_digital_assets": "สินทรัพย์ดิจิทัล", 4 | "txt_publish": "เผยแพร่", 5 | "txt_when_to_publish_this?": "เมื่อไรจะเผยแพร่สิ่งนี้ ?", 6 | "txt_save_as_draft": "บันทึกเป็นร่าง", 7 | "txt_choose_file": "เลือกไฟล์", 8 | 9 | "txt_project": "โครงการ", 10 | "txt_post_now": "โพสทันที", 11 | "txt_schedule": "ตั้งเวลาล่วงหน้า", 12 | "txt_publish_date/time": "เผยแพร่ วัน/เวลา", 13 | "txt_search_all_content": "ค้นหาในเนื้อหาทั้งหมด", 14 | "txt_your_digital_assets": "สินทรัพย์ดิจิทัลของคุณ", 15 | "txt_name": "ชื่อ", 16 | "txt_size": "ขนาด", 17 | "txt_owner": "เจ้าของ", 18 | "txt_last_modified": "แก้ไขล่าสุด", 19 | "txt_image": "ภาพ", 20 | "txt_document": "เอกสาร", 21 | "txt_audio": "ไฟล์เสียง", 22 | "txt_preview": "ดูตัวอย่าง", 23 | "txt_move_to_folder": "ย้ายไปยังโฟลเดอร์", 24 | "txt_download": "ดาวน์โหลด", 25 | "txt_delete": "ลบ", 26 | "txt_sort_by": "เรียงตาม", 27 | "txt_date_create": "วันที่สร้าง", 28 | "txt_a_z": "A - Z", 29 | "txt_z_a": "Z - A", 30 | "txt_menu_member": "สมาชิก", 31 | "txt_menu_import_export": "นำเข้า/ส่งออก", 32 | "txt_menu_colection_transfer": "การโอนคอลเลกชัน", 33 | "txt_menu_setting": "การตั้งค่า", 34 | "txt_menu_trash": "ถังขยะ", 35 | "txt_title_profile_setting": "การตั้งค่าโปรไฟล์", 36 | "txt_title_set_information_name": "ตั้งชื่อของคุณและเปิดเผยข้อมูลอื่นๆ ต่อสาธารณะ", 37 | "txt_cancel": "ยกเลิก", 38 | "txt_your_avatar": "อวตารของคุณ", 39 | "txt_upload_file": "อัพโหลดไฟล์", 40 | "txt_create_folder": "สร้างโฟลเดอร์", 41 | "txt_set_up": "ติดตั้ง", 42 | "txt_my_assets": "ทรัพย์สินของฉัน", 43 | "txt_download_folder": "ดาวน์โหลดโฟลเดอร์", 44 | "txt_delete_folder": "ลบโฟลเดอร์", 45 | "txt_are_you_sure": "คุณแน่ใจนะ?", 46 | "txt_delete_popup_desc": "Lorem ipsum dolor sit amet, consectetur adipiscing", 47 | "txt_Cancel": "ยกเลิก", 48 | "txt_yes_delete": "ใช่, ลบ", 49 | "txt_file": "ไฟล์", 50 | "txt_storage": "พื้นที่จัดเก็บ", 51 | "txt_upgrade": "อัปเกรด", 52 | "txt_configuration_storage": "กำหนดค่า พื้นที่จัดเก็บ", 53 | "txt_configuration_desc": "ขนาดที่แสดงด้านล่างนี้กำหนดขนาดสูงสุดเป็นพิกเซลเพื่อใช้เมื่อเพิ่มรูปภาพลงในไลบรารีสื่อ", 54 | "txt_save_setting": "บันทึกการตั้งค่า", 55 | "txt_client_id": "Client ID", 56 | "txt_client_secret": "Client Secret", 57 | "txt_region": "ภูมิภาค", 58 | "txt_bucket": "ถัง", 59 | "txt_drop_files_anywhere_to_upload": "วางไฟล์ที่ใดก็ได้เพื่ออัปโหลด", 60 | "txt_or": "หรือ", 61 | "txt_select_file": "เลือกไฟล์", 62 | "txt_save_update": "บันทึกการปรับปรุง", 63 | "txt_delete_assets_popup_desc": "คุณแน่ใจหรือไม่ว่าต้องการลบเนื้อหานี้ ?", 64 | "txt_delete_collections_popup_desc": "คุณแน่ใจหรือไม่ว่าต้องการลบโฟลเดอร์นี้ (รวมถึงรายการย่อยและเนื้อหา) ?", 65 | "tx_forgot_password": "ลืมรหัสผ่าน?", 66 | "txt_file_size": "ขนาด", 67 | "txt_url": "URL", 68 | "txt_file_type": "ประเภทไฟล์", 69 | "txt_sign_in_to_getting_started": "ลงชื่อเข้าใช้เพื่อเริ่มต้นใช้งาน", 70 | "txt_folders": "โฟลเดอร์", 71 | "txt_of": "จาก", 72 | "txt_used": "ใช้งาน", 73 | "txt_new_folder": "เพิ่มโฟลเดอร์", 74 | "txt_create": "สร้าง", 75 | "txt_rename": "เปลี่ยนชื่อ", 76 | "txt_can_not_move": "ไม่สามารถย้าย", 77 | "txt_move_with_file_or_folder": "ได้ทำการย้าย {{type}} {{name}} ไปยังโฟรเดอร์ {{name_folder}}", 78 | "txt_drop_to_upload": "วางเพื่ออัปโหลด", 79 | "txt_digital_assets_media": "สื่อสินทรัพย์ดิจิทัล", 80 | "txt_by": "โดย", 81 | "txt_can_not_move_to_itself": "Can not move to itself", 82 | "txt_name_can_not_blank": "Folder name can not be blank!", 83 | "txt_size": "มิติข้อมูล", 84 | "txt_description" : "คำอธิบาย", 85 | "maximum_upload_size": "ขนาดอัพโหลดสูงสุด: 10.00 MB", 86 | "txt_keywords": "คำหลัก", 87 | "txt_tags" : "แท็ก", 88 | "double_click_to_edit": "ดับเบิลคลิกเพื่อแก้ไข", 89 | "right-click_to_get_a_list_of_actions": "คลิกขวาเพื่อดูรายการการกระทำ", 90 | "txt_sso" : "การลงชื่อเพียงครั้งเดียว" 91 | } 92 | -------------------------------------------------------------------------------- /packages/aesirx-dam-app/public/.htaccess: -------------------------------------------------------------------------------- 1 | ## /* 2 | ## * @copyright Copyright (C) 2022 AesirX. All rights reserved. 3 | ## * @license GNU General Public License version 3, see LICENSE. 4 | ## */ 5 | 6 | ## 7 | # READ THIS COMPLETELY IF YOU CHOOSE TO USE THIS FILE! 8 | # 9 | # The line 'Options +FollowSymLinks' may cause problems with some server configurations. 10 | # It is required for the use of Apache mod_rewrite, but it may have already been set by 11 | # your server administrator in a way that disallows changing it in this .htaccess file. 12 | # If using it causes your site to produce an error, comment it out (add # to the 13 | # beginning of the line), reload your site in your browser and test your sef urls. If 14 | # they work, then it has been set by your server administrator and you do not need to 15 | # set it here. 16 | ## 17 | 18 | ## No directory listings 19 | 20 | IndexIgnore * 21 | 22 | 23 | ## Suppress mime type detection in browsers for unknown types 24 | # 25 | #Header always set X-Content-Type-Options "nosniff" 26 | # 27 | 28 | ## Can be commented out if causes errors, see notes above. 29 | #Options +FollowSymlinks 30 | Options -Indexes 31 | 32 | ## Disable inline JavaScript when directly opening SVG files or embedding them with the object-tag 33 | # 34 | # 35 | # Header always set Content-Security-Policy "script-src 'none'" 36 | # 37 | # 38 | 39 | ## Mod_rewrite in use. 40 | Header add Access-Control-Allow-Origin "*" 41 | Header add Access-Control-Allow-Headers "x-requested-with, content-type" 42 | Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS" 43 | ################ 44 | RewriteEngine On 45 | RewriteCond %{HTTPS} off 46 | RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] 47 | 48 | ## Begin - Rewrite rules to block out some common exploits. 49 | # If you experience problems on your site then comment out the operations listed 50 | # below by adding a # to the beginning of the line. 51 | # This attempts to block the most common type of exploit `attempts` on Joomla! 52 | # 53 | # Block any script trying to base64_encode data within the URL. 54 | RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR] 55 | # Block any script that includes a