Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T#2490/primevue projects management #2572

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
matrix:
#IMPORTANT: must, must, must match the total number of containers below: runSubsetOfCypressTests.sh.sh -t <num_of_containers>
# container: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]
container: [ 1, 2, 3, 4, 5, 6]
container: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

services:
postgres:
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:
- name: Run Cypress tests
run: |
cd e2e-tests
../.github/scripts/runSubsetOfCypressTests.sh -t 6 -c ${{ matrix.container }} -f 'projects_crud|/skills_table_spec|/skill_reuse_spec|quiz_creation|question_def|metrics-reUsedData_spec|quiz_and_survey|quiz_runs|quiz_skill_assignment|quiz_read|quiz_role|quiz_settings|quiz_skills-in_project_reuse|client-display_quiz_spec|client-display_quiz_theme_spec|client-display_quiz_visual_spec|client-display_run_quiz_spec|run_survey_spec|quiz_skills-catalog_spec|/inception|user_actions|configure-skill-expiration_spec|skill-expiration-table_spec|configure_video_spec|configure_video_features_spec|configure_skill_video_self_report_spec|configure_video_validation_spec|handle_video_without_duration_spec|client_display_video_on_subject_page_spec|client_display_video_on_skill_page_spec|/skills_spec|/users_spec|/subjects_spec|/levels_management_spec|/skills_group_spec|/skills_group_modal_spec|/move-skills/|/badges_spec|/skill-reuse/skill_reuse/|/catalog/|/project_settings_spec|/icon_manager_spec|/not_found_spec|my-usage_spec|/error_pages_spec|/add_skills_to_badge_spec|/tag-skills|/settings_spec|/client-display/|/learning-path/|/copy_project_spec|/project_errors_spec|/selfReport-approvalHistory_spec|/approver|/manage-my-projects_spec|/accessibility|/community/|/metrics/projectMetrics|/metrics/skillMetrics_spec|/metrics/subjectMetrics_spec|/projects_invite_only_spec|/app_features_spec|/breadcrumb_spec|/contact|/cross-project_spec|/discoverable_proj_invite_spec|/login_spec|/markdown_spec/metrics/multipleProjectMetrics_empty_spec|/metrics/multipleProjectMetrics_spec|/my-progress_breadcrumb_spec|/my-progress_spec|/my-progress-badges_spec|/navigation_spec|/progress_and_ranking_disabled_spec|/project_expiration_spec|performedSkills_table_spec'
../.github/scripts/runSubsetOfCypressTests.sh -t 10 -c ${{ matrix.container }} -f 'projects_crud|/skills_table_spec|/skill_reuse_spec|quiz_creation|question_def|metrics-reUsedData_spec|quiz_and_survey|quiz_runs|quiz_skill_assignment|quiz_read|quiz_role|quiz_settings|quiz_skills-in_project_reuse|client-display_quiz_spec|client-display_quiz_theme_spec|client-display_quiz_visual_spec|client-display_run_quiz_spec|run_survey_spec|quiz_skills-catalog_spec|/inception|user_actions|configure-skill-expiration_spec|skill-expiration-table_spec|configure_video_spec|configure_video_features_spec|configure_skill_video_self_report_spec|configure_video_validation_spec|handle_video_without_duration_spec|client_display_video_on_subject_page_spec|client_display_video_on_skill_page_spec|/skills_spec|/users_spec|/subjects_spec|/levels_management_spec|/skills_group_spec|/skills_group_modal_spec|/move-skills/|/badges_spec|/skill-reuse/skill_reuse/|/catalog/|/project_settings_spec|/icon_manager_spec|/not_found_spec|my-usage_spec|/error_pages_spec|/add_skills_to_badge_spec|/tag-skills|/settings_spec|/client-display/|/learning-path/|/copy_project_spec|/project_errors_spec|/selfReport-approvalHistory_spec|/approver|/manage-my-projects_spec|/accessibility|/community/|/metrics/projectMetrics|/metrics/skillMetrics_spec|/metrics/subjectMetrics_spec|/projects_invite_only_spec|/app_features_spec|/breadcrumb_spec|/contact|/cross-project_spec|/discoverable_proj_invite_spec|/login_spec|/markdown_spec/metrics/multipleProjectMetrics_empty_spec|/metrics/multipleProjectMetrics_spec|/my-progress_breadcrumb_spec|/my-progress_spec|/my-progress-badges_spec|/navigation_spec|/progress_and_ranking_disabled_spec|/project_expiration_spec|performedSkills_table_spec|/projects_admin_management_spec|/projects_modal_management_spec|/projects_modal_validation_spec|/projects_spec'
cd ..
env:
ELECTRON_EXTRA_LAUNCH_ARGS: '--disable-gpu'
Expand Down
9 changes: 8 additions & 1 deletion dashboard-prime/src/components/access/AccessSettings.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<script setup>
import { ref, onMounted } from 'vue';
import { ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router'
import SubPageHeader from "@/components/utils/pages/SubPageHeader.vue";
import RoleManager from "@/components/access/RoleManager.vue";
import PrivateInviteOnlyProjManagement from '@/components/access/invite-only/PrivateInviteOnlyProjManagement.vue'
import SettingsService from '@/components/settings/SettingsService.js'
import { useAppConfig } from '@/common-components/stores/UseAppConfig.js'
import TrustedClientProps from '@/components/access/TrustedClientProps.vue'

const route = useRoute();
const appConfig = useAppConfig()

const showTrustedClientProps = computed(() => (!appConfig.isPkiAuthenticated));

const isLoading = ref(true);
const privateProject = ref(false);
Expand Down Expand Up @@ -44,6 +49,8 @@ onMounted(() => {
:add-role-confirmation="privateProject" />

<private-invite-only-proj-management v-if="privateProject"/>

<trusted-client-props v-if="showTrustedClientProps" class="my-4"/>
</div>
</div>
</template>
Expand Down
43 changes: 25 additions & 18 deletions dashboard-prime/src/components/access/RoleManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,25 @@ onMounted(() => {
loadData();
});


const sortInfo = ref({ sortOrder: 1, sortBy: 'userId' })
const possiblePageSizes = [ 5, 10, 15, 20]
const pageSize = ref(5)
let table = ref({
options: {
busy: true,
sortBy: 'userId',
sortDesc: 1,
pagination: {
hideUnnecessary: true,
server: false,
currentPage: 1,
totalRows: 1,
pageSize: 5,
possiblePageSizes: [5, 10, 15, 20],
},
tableDescription: `${props.roleDescription} table`,
},
});

let data = ref([]);
let userIds = ref([]);
const data = ref([]);
const userIds = computed(() => data.value.map((d) => d.userId));
const selectedUser = ref(null);
const isSaving = ref(false);
const errNotification = ref({
Expand Down Expand Up @@ -130,19 +130,18 @@ function getRoleDisplay(roleName) {
return 'Unknown';
}

function loadData() {
const loadData = () => {
table.value.options.busy = true;
const pageParams = {
limit: 200,
ascending: table.value.options.sortDesc === 1,
page: 1,
orderBy: table.value.options.sortBy,
ascending: sortInfo.value.sortOrder === 1,
orderBy: sortInfo.value.sortBy
};
AccessService.getUserRoles(props.projectId, props.roles, pageParams).then((result) => {
table.value.options.busy = false;
data.value = result.data;
table.value.options.pagination.totalRows = result.totalCount;
// userIds.value = result.data.map((u) => [u.userId, u.userIdForDisplay]).flatten();
});
}

Expand Down Expand Up @@ -225,7 +224,7 @@ function deleteUserRole(row) {
table.value.options.busy = true;
AccessService.deleteUserRole(row.projectId, row.userId, row.roleName).then(() => {
data.value = data.value.filter((item) => item.userId !== row.userId);
userIds.value = userIds.value.filter((userId) => userId !== row.userId && userId !== row.userIdForDisplay);
userIds.value = userIds.value.filter((userId) => userId !== row.userId);
emit('role-deleted', { userId: row.userId, role: row.roleName });
table.value.options.busy = false;
table.value.options.pagination.totalRows = data.value.length;
Expand Down Expand Up @@ -317,13 +316,20 @@ defineExpose({
<strong>Error!</strong> Request could not be completed! {{ errNotification.msg }}
</Message>
</div>
<DataTable :value="data" :rowsPerPageOptions="[5, 10, 15, 20]" data-cy="roleManagerTable" striped-rows
v-model:sort-field="table.options.sortBy"
v-model:sort-order="table.options.sortDesc"
paginator :rows="5">
<SkillsDataTable
:value="data"
:rowsPerPageOptions="possiblePageSizes"
data-cy="roleManagerTable"
tableStoredStateId="roleManagerTableSort"
striped-rows
paginator
v-model:sort-field="sortInfo.sortBy"
v-model:sort-order="sortInfo.sortOrder"
:rows="pageSize">
<Column :header="roleDescription" field="userId" sortable :class="{'flex': responsive.md.value }">
<template #header>
<span class="mr-2"><i class="fas fa-user skills-color-users" :class="colors.getTextClass(0)" aria-hidden="true"></i> </span>
<span class="mr-2"><i class="fas fa-user skills-color-users" :class="colors.getTextClass(0)"
aria-hidden="true"></i> </span>
</template>
<template #body="slotProps">
<div :data-cy="`userCell_${slotProps.data.userId}`">
Expand All @@ -333,7 +339,8 @@ defineExpose({
</Column>
<Column header="Role" field="roleName" sortable :class="{'flex': responsive.md.value }">
<template #header>
<span class="mr-2"><i class="fas fa-id-card text-danger" :class="colors.getTextClass(1)" aria-hidden="true"></i> </span>
<span class="mr-2"><i class="fas fa-id-card text-danger" :class="colors.getTextClass(1)"
aria-hidden="true"></i> </span>
</template>
<template #body="slotProps">
<div v-if="!slotProps.data.isEdited">{{ getRoleDisplay(slotProps.data.roleName) }}</div>
Expand Down Expand Up @@ -383,7 +390,7 @@ defineExpose({
<template #empty>
<span class="flex align-items-center justify-content-center">There are no records to show</span>
</template>
</DataTable>
</SkillsDataTable>
</div>
</template>
</Card>
Expand Down
70 changes: 70 additions & 0 deletions dashboard-prime/src/components/access/TrustedClientProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script setup>
import SkillsCardHeader from '@/components/utils/cards/SkillsCardHeader.vue'
import { useRoute } from 'vue-router'
import { computed, onMounted, ref } from 'vue'
import AccessService from '@/components/access/AccessService.js'
import { useDialogMessages } from '@/components/utils/modal/UseDialogMessages.js'

const route = useRoute()
const dialogMessages = useDialogMessages()

const projectId = computed(() => route.params.projectId)

const loadingSecret = ref(true)
const clientSecret = ref('')

onMounted(() => {
loadClientSecret()
})

const loadClientSecret = () => {
loadingSecret.value = true
AccessService.getClientSecret(projectId.value)
.then((clientSecretRes) => {
clientSecret.value = clientSecretRes
}).finally(() => {
loadingSecret.value = false
})
}

const resetClientSecret = () => {
const message = 'Are you sure you want reset the client secret? Your current client secret will no longer work after reset and you will need to update any application configuration using the old secret.'
dialogMessages.msgConfirm(message, 'Reset Secret?', () => {
AccessService.resetClientSecret(projectId.value)
.then((clientSecretRes) => {
clientSecret.value = clientSecretRes
})
})
}
</script>

<template>
<Card data-cy="trusted-client-props-panel">
<template #header>
<SkillsCardHeader title="Trusted Client Properties"></SkillsCardHeader>
</template>
<template #content>
<skills-spinner v-if="loadingSecret" :is-loading="loadingSecret" class="my-5" />
<div v-if="!loadingSecret">
<div>
<span class="text-color-secondary">Client ID:</span>
<span class="ml-2">{{ projectId }}</span>
</div>
<div class="mt-2">
<span class="text-color-secondary">Client Secret:</span>
<span class="ml-2">{{ clientSecret }}</span>
</div>
<SkillsButton
label="Reset Client Secret"
icon="fas fa-sync-alt"
size="small"
@click="resetClientSecret"
class="mt-3" />
</div>
</template>
</Card>
</template>

<style scoped>

</style>
4 changes: 4 additions & 0 deletions dashboard-prime/src/components/levels/NewLevel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ const initialLevelData = {
points: props.level.points,
};

if (!props.isEdit) {
initialLevelData.percent = props.allLevels.reduce((max, level) => Math.max(max, level.percent), 0) +1;
}

const boundsValidator = (value) => {
const gte = (value, compareTo) => value >= compareTo;
const lte = (value, compareTo) => value <= compareTo;
Expand Down
2 changes: 1 addition & 1 deletion dashboard-prime/src/components/projects/EditProject.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const schema = object({
.max(appConfig.maxProjectNameLength)
.nullValueNotAllowed()
.test('uniqueName', 'Project Name already exists', (value) => checkProjNameUnique(value))
.customNameValidator()
.customNameValidator('Project Name')
.label('Project Name'),
'projectId': string()
.required()
Expand Down
3 changes: 2 additions & 1 deletion dashboard-prime/src/components/projects/MyProject.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const announcer = useSkillsAnnouncer()

// data items
const pinned = ref(false);
const projectInternal = ref({ ...props.project });
const projectInternal = computed(() => props.project );
const stats = ref([]);
const showEditProjectModal = ref(false);
const showCopyProjectModal = ref(false);
Expand Down Expand Up @@ -247,6 +247,7 @@ defineExpose({
<ReminderMessage
v-if="warningMsgAboutPoints"
:id="`projectCardWarning_${projectInternal.projectId}`"
data-cy="projectCardWarning"
severity="info">{{ warningMsgAboutPoints}}</ReminderMessage>

<div v-if="!disableSortControl"
Expand Down
53 changes: 29 additions & 24 deletions dashboard-prime/src/components/projects/MyProjects.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,17 @@ const openProjectModal = (project = {}, isEdit = false) => {
provide('createOrUpdateProject', openProjectModal)

const projectAdded = (project) => {

const existingIndex = projects.value.findIndex((item) => item.projectId === project.originalProjectId)
if (existingIndex >= 0) {
console.log(`edit: ${existingIndex} project at this indeex`)
projects.value.splice(existingIndex, 1, project)
announcer.polite(`Project ${project.name} has been updated`);
} else {
projects.value.push(project)
SkillsReporter.reportSkill('CreateProject');
announcer.polite(`Project ${project.name} has been created`);
}
announcer.polite(`Project ${project.name} has been created`);
};
const projectEdited = (editedProject) => {
// ProjectService.saveProject(editedProject).then(() => {
loadProjects().then(() => {
// this.$refs.projectsTable.focusOnEditButton(editedProject.projectId);
nextTick(() => {
announcer.polite(`Project ${editedProject.name} has been edited`);
});
});
// });
};
const enableDropAndDrop = () => {
if (projects.value && projects.value.length > 0 && projects.value.length < appConfig.numProjectsForTableView) {
Expand Down Expand Up @@ -211,12 +204,9 @@ const saveProject = (values, isEdit, projectId) => {
}
return ProjectService.getProject(projRes.projectId)
.then((retrievedProj) => {
if (!isEdit) {
projectAdded(retrievedProj);
} else {
projectEdited(retrievedProj);
}
return {...retrievedProj, originalProjectId: projectId}
const projWithOriginalId = { ...retrievedProj, originalProjectId: projectId }
projectAdded(projWithOriginalId)
return projWithOriginalId
})
})
}
Expand Down Expand Up @@ -276,12 +266,14 @@ const hasData = computed(() => {
<div v-for="project of projects" :key="project.projectId" class="mb-3"
:id="project.projectId">
<BlockUI :blocked="sortOrder.loading">
<div class="text-center" :data-cy="`${project.projectId}_overlayShown`">
<div v-if="project.projectId===sortOrder.loadingProjectId && sortOrder.loading"
data-cy="updatingSortMsg">
<div class="text-info text-uppercase mb-1">Updating sort order!</div>
<SkillsSpinner :is-loading="sortOrder.loading" label="Loading..." style="width: 3rem; height: 3rem;" variant="info" />
</div>
<div v-if="sortOrder.loading"
class="text-center loading-indicator"
:data-cy="`${project.projectId}_overlayShown`">
<SkillsSpinner
v-if="project.projectId === sortOrder.loadingProjectId"
:is-loading="true"
data-cy="overlaySpinner"
aria-label="Updating sort order" />
</div>
<MyProject :id="`proj${project.projectId}`" tabindex="-1"
:project="project" :disable-sort-control="projects.length === 1"
Expand Down Expand Up @@ -319,4 +311,17 @@ const hasData = computed(() => {
</div>
</template>

<style scoped></style>
<style scoped>
.loading-indicator {
position: absolute;
z-index: 999;
height: 2em;
width: 2em;
overflow: show;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
</style>
12 changes: 12 additions & 0 deletions e2e-tests/cypress/e2e/client-display/client-display_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,27 +217,39 @@ describe('Client Display Tests', () => {

it('clearly represent navigable components', () => {
cy.cdVisit('?internalBackButton=true', true);
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSubj(0, 'Subject 1',true);
cy.get('[data-cy="pointHistoryChartWithData"]')

// make sure it can navigate into each skill via title
cy.cdClickSkill(0, false);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(1, false);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(2, false);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(3, false);
cy.get('[data-cy="prerequisitesCard"] [data-cy="skillLink-proj1-skill2"]')
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')

// make sure it can navigate into each skill via progress bar
cy.cdClickSkill(0);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(1);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(2);
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
cy.cdClickSkill(3);
cy.get('[data-cy="prerequisitesCard"] [data-cy="skillLink-proj1-skill2"]')
cy.cdBack('Subject 1');
cy.get('[data-cy="pointHistoryChartWithData"]')
});

it('components should not be clickable in the summary only option', () => {
Expand Down
Loading
Loading