Add graphql support for api platform + add vue apollo to query the api

Load "my courses" page with graphql instead of rest api
pull/3890/head
Julio Montoya 5 years ago
parent 1ecc9e5331
commit f922607460
  1. 2
      assets/js/app.js
  2. 23
      assets/vue/App.vue
  3. 2
      assets/vue/components/course/CourseCard.vue
  4. 6
      assets/vue/components/course/CourseCardList.vue
  5. 18
      assets/vue/main.js
  6. 43
      assets/vue/views/user/courses/List.vue
  7. 5
      composer.json
  8. 9
      package.json
  9. 18
      src/CoreBundle/Entity/Course.php
  10. 3729
      yarn.lock

@ -75,8 +75,6 @@ const homePublicUrl = '/';
const mainUrl = homePublicUrl + 'main/';
const webAjax = homePublicUrl + 'main/inc/ajax/';
var ajax_url = webAjax + 'chat.ajax.php';
$(function () {
let courseId = $('body').attr('data-course-id');
let webCidReq = '&cid=' + courseId + '&sid=' + $('body').attr('data-session-id');

@ -12,7 +12,7 @@
import {mapGetters} from 'vuex';
import NotificationMixin from './mixins/NotificationMixin';
import axios from "axios";
import { onMounted, onUnmounted, ref, computed, watch } from 'vue';
import { onMounted, onUnmounted, ref, computed, watch, provide } from 'vue';
import isEmpty from 'lodash/isEmpty';
import { fasGlobeAmericas, fasFlask } from '@quasar/extras/fontawesome-v5'
import { useRouter, useRoute } from 'vue-router'
@ -27,6 +27,25 @@ import Button from './components/global/Button.vue'*/
const defaultLayout = "Dashboard";
import { DefaultApolloClient } from '@vue/apollo-composable'
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core'
// HTTP connection to the API
const httpLink = createHttpLink({
// You should use an absolute URL here
uri: '/api/graphql',
})
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
export default {
name: "App",
components: {
@ -38,6 +57,8 @@ export default {
);
const route = useRoute();
provide(DefaultApolloClient, apolloClient)
watch(
() => route.meta,
async meta => {

@ -15,7 +15,7 @@
<img src="/img/session_default.png" />
<q-card-section>
<div class="text-h7">
<router-link :to="{ name: 'CourseHome', params: {id: course.id, course: course}}">
<router-link :to="{ name: 'CourseHome', params: {id: course._id, course: course}}">
{{ course.title }}
</router-link>
</div>

@ -1,10 +1,10 @@
<template>
<div
v-for="card in courses"
:key="card.course.id"
v-for="course in courses"
:key="course.id"
>
<CourseCard
:course="card.course"
:course="course"
/>
</div>
</template>

@ -15,21 +15,12 @@ import makeCrudModule from './store/modules/crud';
//require('@fancyapps/fancybox');
//require('@fancyapps/fancybox/dist/jquery.fancybox.css');
/*
import VueApollo from 'vue-apollo';
import ApolloClient from 'apollo-boost';
const apolloClient = new ApolloClient({
// You should use an absolute URL here
uri: '/api/graphql/'
});*/
// Font awesome
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
library.add(fas);
//Vue.use(Vuelidate);
//Vue.use(VueApollo);
import Toast from 'vue-toastification';
//import 'vue-toastification/dist/index.css';
@ -38,11 +29,6 @@ const toastOptions = {
maxToasts: 20,
newestOnTop: true
};
/*const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});*/
import VueFlatPickr from 'vue-flatpickr-component';
import 'flatpickr/dist/flatpickr.css';
@ -161,12 +147,10 @@ app.component('EmptyLayout', EmptyLayout);
app.component('TinyEditor', Editor);
app.config.globalProperties.axios = axios;
const prettyBytes = require('pretty-bytes');
const { DateTime } = require("luxon");
app.config.globalProperties.$luxonDateTime = DateTime;
app.config.globalProperties.$luxonDateTime = DateTime;
app.config.globalProperties.$filters = {
prettyBytes(num) {
return prettyBytes(num);

@ -1,6 +1,6 @@
<template>
<!-- {{ loading }}-->
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 mt-2">
{{ status }}
<CourseCardList
:courses="courses"
/>
@ -13,6 +13,8 @@ import {ENTRYPOINT} from '../../../config/entrypoint';
import axios from "axios";
import {ref, computed} from "vue";
import { useStore } from 'vuex';
import gql from "graphql-tag";
import { useQuery, useResult } from '@vue/apollo-composable'
export default {
name: 'CourseList',
@ -20,7 +22,7 @@ export default {
CourseCardList,
},
setup() {
const courses = ref([]);
//const courses = ref([]);
const status = ref('Loading');
const store = useStore();
@ -28,7 +30,7 @@ export default {
if (user.value) {
let userId = user.value.id;
axios.get(ENTRYPOINT + 'users/' + userId + '/courses.json').then(response => {
/*axios.get(ENTRYPOINT + 'users/' + userId + '/courses.json').then(response => {
if (Array.isArray(response.data)) {
courses.value = response.data;
}
@ -36,12 +38,37 @@ export default {
console.log(error);
}).finally(() =>
status.value = ''
);
}
);*/
const GET_COURSE_REL_USER = gql`
query getCourses($user: String!){
courseRelUsers(user: $user) {
edges {
node {
course {
_id
title
}
}
}
}
}
`;
const {result, loading, error} = useQuery(GET_COURSE_REL_USER, {
user: "/api/users/" + userId
}, );
const courses = useResult(result, null, (data) => {
return data.courseRelUsers.edges.map(function(edge) {
return edge.node.course;
});
});
return {
courses,
status
return {
courses,
loading
}
}
}
};

@ -55,7 +55,7 @@
"a2lix/translation-form-bundle": "^3.0",
"api-platform/api-pack": "^1.3",
"api-platform/core": "^2.6",
"beberlei/doctrineextensions": "^1.2",
"beberlei/doctrineextensions": "^1.3",
"chamilo/settings-bundle": "dev-master",
"clue/graph": "^0.9.2",
"cocur/slugify": "^4.0",
@ -142,7 +142,8 @@
"tgalopin/html-sanitizer-bundle": "^1.1",
"twig/intl-extra": "^3.0",
"vich/uploader-bundle": "^1.17",
"webit/eval-math": "^1.0"
"webit/eval-math": "^1.0",
"webonyx/graphql-php": "^14.7"
},
"config": {
"optimize-autoloader": true,

@ -6,6 +6,7 @@
"start": "vue-cli-service serve --open"
},
"dependencies": {
"@apollo/client": "^3.3.19",
"@babel/plugin-transform-runtime": "^7.9.6",
"@fancyapps/fancybox": "^3.5.7",
"@fortawesome/fontawesome-svg-core": "^1.2.35",
@ -20,6 +21,8 @@
"@tailwindcss/ui": "^0.7.2",
"@tinymce/tinymce-vue": "^4.0",
"@types/lodash": "^4.14.168",
"@vue/apollo-composable": "^4.0.0-alpha.12",
"@vue/apollo-option": "^4.0.0-alpha.11",
"@vue/cli": "^4.5",
"@vuelidate/core": "^2.0.0-alpha.16",
"@vuelidate/validators": "^2.0.0-alpha.13",
@ -47,6 +50,7 @@
"full-icu": "^1.3.4",
"fullcalendar": "^5.7",
"glob-all": "^3.2.1",
"graphql": "^15.5.0",
"highlight.js": "^10.0",
"hljs": "^6.2",
"html2canvas": "^1.0.0-rc.7",
@ -93,7 +97,8 @@
"tinymce": "^5.7",
"ts-loader": "^8.1.0",
"video.js": "^7.11.8",
"vue": "^3.0",
"vue": "^3.1.0-beta.3",
"vue-apollo": "^3.0.7",
"vue-eslint-parser": "^7.6.0",
"vue-flatpickr-component": "^9.0",
"vue-i18n": "^9.0.0",
@ -123,12 +128,14 @@
"deepmerge": "^4.2.2",
"filemanager-webpack-plugin": "^4.0",
"free-jqgrid": "https://github.com/chamilo/jqGrid.git#bs4",
"graphql-tag": "^2.12.4",
"node-sass": "^6.0",
"popper.js": "^1.14.7",
"postcss-rtl": "^1.2.3",
"sass": "^1.29.0",
"sass-loader": "^10.1",
"typescript": "^3.8.3",
"vue-cli-plugin-apollo": "~0.22.2",
"vue-cli-plugin-quasar": "next",
"vue-cli-plugin-vuetify": "~2.3.1",
"webpack-notifier": "^1.13"

@ -26,8 +26,6 @@ use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Course.
*
* @ApiResource(
* attributes={"security"="is_granted('ROLE_ADMIN')"},
* iri="https://schema.org/Course",
@ -98,7 +96,7 @@ class Course extends AbstractResource implements ResourceInterface, ResourceWith
* @var Collection|CourseRelUser[]
*
* @ApiSubresource()
* Groups({"course:read"})
* @Groups({"course:read", "user:read"})
* "orphanRemoval" is needed to delete the CourseRelUser relation
* in the CourseAdmin class. The setUsers, getUsers, removeUsers and
* addUsers methods need to be added.
@ -591,23 +589,11 @@ class Course extends AbstractResource implements ResourceInterface, ResourceWith
return $this;
}
/**
* Get code.
*
* @return string
*/
public function getCode()
public function getCode(): string
{
return $this->code;
}
public function setDirectory(string $directory): self
{
$this->directory = $directory;
return $this;
}
/**
* Get directory.
*

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save