Giter Club home page Giter Club logo

magpie-base's Introduction

magpie-base

Base components in Vue for magpie-powered experiments.

Installation

First, ensure you have Node.js v16 or v18 installed.

To install this package, run npm install -g magpie-base.

To initialize a new experiment based on magpie (after installing the package), run magpie new experiment-name.

For more information, please visit the project homepage

Documentation

The API reference for the latest version is available at reference.magpie-experiments.org.

A guided introduction to building experiments with magpie is available at magpie-experiments.org.

How to update existing projects

$ cd your-project
$ npm update magpie-base

Read more on maintaining npm dependencies.

Core Development

Git branching model

The master branch represents the latest release. Development of new features and pull requests happen on the develop branch.

Release procedure

If a release should be done

  1. Review changes and determine new version number according to Semantic versioning
  2. Document new release in CHANGELOG.md file
  3. Bump package.json:version
  4. Commit and tag vX.X.X
  5. Merge into master
  6. Wait for CI to complete and pass
  7. npm publish
  8. Upgrade magpie in project repositories of this Github Organization

Development principles

  • Components should not expose CSS classes for manipulation but instead offer customization either via unstyled slots or via props.
  • Pre-packaged screens are more of a convenience should be rather easy to replicate with normal userland code
  • Always use camelCase for measurements

Linting

Before committing changes it is recommended to run the linter to make sure the changes adhere to the general coding style.

Run the js/vue linter using

npm run lint:fix

and the css linter using

npm run stylelint:fix

Tests

Ideally every feature should be covered by at least one unit test. Unit tests are run on every commit and pull requests, so we can quickly detect whenever a change breaks something.

Run the unit tests using

npm run test:unit

For implementing tests we're using the jest framework in combination with vue test utils.

Docs

In order to spin up a local web server with the docs run npm run docs.

In order to build the docs run npm run docs:build.

The contents and organization of the docs are declared in styleguide.config.js. Each source folder should have a docs.md file with a general introduction to the feature in said folder.

The online docs are automatically built from the latest commit of the master branch.

Vue components

All Vue components must be exported in src/components/index.js in order to be available in downstream projects without importing them.

magpie-base's People

Contributors

dependabot[bot] avatar marcelklehr avatar x-ji avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

magpie-base's Issues

API review

hey!

I just wanted to get some feedback on the API so far. (cc @x-ji @DiGyt)

  1. The magic magpie property is currently named $exp, but I'm pondering renaming it, e.g. $experiment or even $magpie to make it obvious what this is.
  2. The trials mechanism allows specifying trial data once via the trials prop of the Experiment component and then accessing single data points via e.g.$exp.trial.color. To make it more clear that this is not an array, I'm considering renaming this to $exp.currentTrial.color. That would make it more verbose, however.

What do you think?

Additions to the Chat component

Hey everyone, this is probably for you @marcelklehr

During the work on our interactive chat experiment and from the discussion I had with @michael-franke , I though that several things should be added to the chat component:

  • As of now, when logging chat messages, we can log author and the content of the chat message. However, Michael emphasized that it would be probably worth to also broadcast the current time each time a message is sent. This will later allow the experimenter to better untangle confusing threads as they occur when the chat partners send messages at almost the same time.
  • Speaking of that, logging the chat messages as given in 0.3.0 via simply adding :messages.sync="responses.messages" and $magpie.addTrialData(responses); will result in the .csv log of the chat messages only reads [object object] (as objects aren't serialized in the results). Of course we can extract the content of these objects before addTrialData however, it would be better if :messages.sync="responses.messages" and $magpie.addTrialData(responses); would give you some clear data already, (My guess is that it would be easiest to add some form of serialization of objects, such that addTrialData returns a field that could look similar to this): question: chat messages, answer: [{author:Me, content:"Hi", time:2021-03-03-15-23-23}, {author:Partner, content:"What's up", time:2021-03-03-15-23-24}, ...].
    Michael also suggested having this data in a format that can be easily converted to a structured table with columns [author, message, time] and a row for each message.
  • The biggest practical challenge to using the chat component for me was not knowing whether your partner is there or not. You could e.g. throw some messages into the ether but your partner would never receive them because she/he was still lingering in the previous screen while you were in the chat screen already (the same problem occurs when one person leaves the chat unexpectedly). This becomes especially problematic, when you want to have multiple subsequent Chat screens in one experiment.
    _
    I think a good way to solve this is to have a status indicator somewhere that tells you stuff like Your partner has not yet entered the chat, Your partner is active or Your partner has left the chat. Having this status indicator in the chat component makes it instantly more comfortable to handle, so I would really advocate for including it as a standard.
    _
    I made a very crude implementation of this in my experimental code (Experiment link: https://sad-bhabha-077723.netlify.app). I know my code is really ugly, but maybe it helps you with implementing a more elegant version. It works by invoking a routine on creation of the chat component, with both partners sending a status with the current time each two seconds. When there is no partner status found yet, the function infers that the partner has not entered yet. When the partner's last status timestamp is older than some timeout range of seconds, then it concludes that the partner has left the chat (irrespective of her/him clicking the [next] button or closing the browser window).

Sorry for annoying again πŸ˜…
But I think this would make the Chat component even better.

Edit:
I will also work on adding the time variable to messages in my experiment if you want to look into it. But you probably won't need to as I think adding this addition would be rather trivial...

Fix typo in experiments created with 'magpie new'

Currently, it says:

<!-- While developing your experiment, using the DebugResults screen is fine,
  once you're going live, you can use the <SubmitResults> screen to automatically send your experimental data to the server. -->

It should be:

... ...

Add tests

When the package has stabilized we should add tests (e.g. with Jest). Not a priority for now of course.

Implement trial views

Trial views

        Forced choice (2 alternatives)
        Sentence choice
        Image selection
        Textbox Input task
        Slider rating
        Dropdown choice
        Rating scale
        Key press

Submit all chat messages to results

While we're at it already, you could help me with another thing ;)

When working with the Chat component, I want submit all the chat messages of one trial/chat to the results as a list (As shown below).

chat_messages

However, my current method is super clumsy and I'm sure that there are way more elegant methods to solve this.
For my first tries, I tweaked the Chat component, such that I can reference the chatbox, and then extract all the messages from it:

methods: {
    submit_chat() {
      var container = [];
      for(var i=0; i<document.getElementById('chatbox_1').children.length; i++){
        var msg = document.getElementById('chatbox_1').children[i];
        var msg_text = msg.textContent;
        container.push(msg_text);
      }
      this.$magpie.addResult({ question: this.$magpie.currentTrial.QUD, answer: container});
      }
  }

Can you maybe give me a hint on how to access the messages variable from the Chat component directly/ how to improve this?
I think it would be nice to have an inbuilt function which does this automatically.

It would be also great to add the participant ID to this to distinguish between chat message authors, e.g. like:

container = [ "1 --- hey", "2 --- hello", "1 --- what's up", "2 --- nothing" ]

But I think this will be somewhat annoying with the method I'm currently using.,.

Bugs in v0.3.0

Sorry for being annoying, but I've found a few bugs with the new version:

Problem 1 - magpie.addTrialData seems to not be defined:

After reinstalling the new magpie, generating a new experiment via magpie new experiment installing and serving it, I get errors when clicking on a button that's linked to the addTrialData function:

[Vue warn]: Error in v-on handler: "TypeError: _vm.$magpie.addTrialData is not a function"

found in

---> <ForcedChoiceInput> at node_modules/magpie-base/src/components/inputs/ForcedChoiceInput.vue
...

and

TypeError: _vm.$magpie.addTrialData is not a function

addResults on the other hand still works.

Problem 2 - When trying to log the chat message data, as @marcelklehr proposed in Issue #21 , the fact that the Chat screen is now also a template seems to create a bug: After being done chatting and clicking the button for the next screen, the heading of the next screen is rendered, but instead of the correct next screen content (e.g. a slider window), the chat component shows again, with full functionality. If you click the button again, you skip directly further, ignoring the component that would have come after the chat screen.

You should be able to reproduce this bug with the following MWE:

      <ConnectInteractive />

      <Screen :title="'Chat'">
        <template #0="{responses}">
          <Chat :messages.sync="responses.messages"></Chat>
          <button @click=
                      "
                      $magpie.addResult({question:'messages', answer: responses.messages});
                      $magpie.nextScreen();">
            Leave Chat</button>
        </template>
      </Screen>

      <Screen :title="'Posttest'">
        <template #0="{responses}">
          <SliderInput
              left="Very Unfair"
              right="Very Fair"
              initial="50"
              :response.sync="responses.slider"
          />
          <button @click=
                      "
                      $magpie.addResult({question: 'posttest', answer:  responses.slider});
                      $magpie.nextScreen();">
            Continue</button>
        </template>
      </Screen>

Can you tell me what's the problem here and whether I'm doing something wrong?

Variables for syncing up over socket [Question]

Got another question (probably for @x-ji ):

I'm currently fixing the last stuff for my interactive experiment. One part is to make sure the two socket partners sync up correctly. For that I need 2 networked variables on which I can base my random trial and condition assignment.

One variable needs to differ between interactive partners, such that I can put partner A in condition 1 and partner B in condition 2.

The other variable needs to remain constant for both partners, but needs to differ for each new instantiation of the experiment, such that I can feed each new pair with new trial data (while the trial data is consistent for the pair).

After testing it out I think that the first variable I'm looking for is socket.variant (differing within a pair) and the second variable I'm looking for is socket.chain (differing between experiment instances). However I believe that socket.chain actually only increases for simultaneous instances of the experiment, and not for subsequent instances of the experiment (in the case Γ³f pair 2 starting after pair 1 has finished).

Can you maybe quickly confirm/falsify my assumptions?

And if the last one is true can you maybe tell me what else I could use, or how I can introduce additional variables to socket which track the number of instantiations of an experiment?

Sorry again for my illiteracy when it comes to socket :D

PS.: I think it would be nice to have this in somewhere in the documentation!

Edit: Just noted that you can't seed Math.random() in JavaScript, so I'm not sure anymore whether it will be faster to seed based upon some socket variables, or whether I just should assign/generate the trials with Partner A, and them send them to Partner B via socket. What do you think?

Write tests

  • ResponseTimeStart
  • TimerStart/stop
  • PostTestScreen
  • Canvas
  • SelfPacedReading
  • Synth

Hello World Todo

  • Finalize website setup
    • DNS CNAME for api.magpie-experiments.org (reference)
    • DNS A for magpie-experiments.org (docs; I'm happy to do these, but would need to have access to namecheap)
    • Update website-references to new domain
  • Bump major version to >= 1 Any low hanging breaking changes already visible?
  • #123
  • Get rid of cute Trump references in manual
  • Find out dynamically if deploy is on github pages or netlify
  • Sort our docker container business (magpie-ea/magpie-backend#131)
  • Release magpie-base v0.7.0 v3.0.0 with latest changes
  • Add applicable version number to docs
  • Update example projects on github to latest version of magpie-base
  • Link to repos of magpie-base and magpie-backend from docs
  • change allocation order
  • pilot iterated guessing
  • pilot color guessing

Test interactive components

  • Create working production docker container of magpie-backend
  • Write basic integration tests
  • Setup CI with the docker container
  • Test interactive components in CI

Socket connection sometimes breaks and can't be set up again

Working with the chat component works usually completely smooth, however after some time working with it, it will often occur that the connection somehow just "breaks", meaning that two chat components aren't able to match up anymore and you're endlessly stuck in the <ConnectInteractive /> lobby.

Clearing cookies, changing the browser from Firefox to Opera, restarting WebStorm/Ubuntu doesn't help, as the problem remains the same over days. After the connection was broken, the browser console constantly puts out:

Firefox can’t establish a connection to the server at wss://magpie-demo.herokuapp.com/socket/websocket?participant_id=88efcc028c68802683062e874ca2c25dd70500ac&experiment_id=171&vsn=2.0.0.

and

[HTTP/1.1 403 Forbidden 583ms]

In fact, the same error even occurs on the magpie documentation for the chat component at the current moment. I've got no idea how this socket stuff works under the hood, but my guess is that this "server" is broken and needs to be restarted.

@marcelklehr @x-ji What do you think of this problem? Do you have an idea how to fix it from happening again? Any suggestions on how to prevent it or how to handle it when it occurs?

Thanks for all the great work so far :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.